summaryrefslogtreecommitdiff
path: root/runtime/commonMain/src/kotlinx/serialization/Mapper.kt
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/commonMain/src/kotlinx/serialization/Mapper.kt')
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/Mapper.kt154
1 files changed, 154 insertions, 0 deletions
diff --git a/runtime/commonMain/src/kotlinx/serialization/Mapper.kt b/runtime/commonMain/src/kotlinx/serialization/Mapper.kt
new file mode 100644
index 00000000..3a0fb9ff
--- /dev/null
+++ b/runtime/commonMain/src/kotlinx/serialization/Mapper.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.serialization
+
+import kotlinx.serialization.modules.*
+
+class Mapper(context: SerialModule = EmptyModule) : AbstractSerialFormat(context) {
+
+ internal inner class OutMapper : NamedValueEncoder() {
+ override val context: SerialModule = this@Mapper.context
+
+ override fun beginCollection(
+ desc: SerialDescriptor,
+ collectionSize: Int,
+ vararg typeParams: KSerializer<*>
+ ): CompositeEncoder {
+ encodeTaggedInt(nested("size"), collectionSize)
+ return this
+ }
+
+ private var _map: MutableMap<String, Any> = mutableMapOf()
+
+ val map: Map<String, Any>
+ get() = _map
+
+ override fun encodeTaggedValue(tag: String, value: Any) {
+ _map[tag] = value
+ }
+
+ override fun encodeTaggedNull(tag: String) {
+ throw SerializationException("null is not supported. use Mapper.mapNullable()/OutNullableMapper instead")
+ }
+ }
+
+ internal inner class OutNullableMapper : NamedValueEncoder() {
+ override val context: SerialModule = this@Mapper.context
+
+ internal val map: MutableMap<String, Any?> = mutableMapOf()
+
+ override fun beginCollection(
+ desc: SerialDescriptor,
+ collectionSize: Int,
+ vararg typeParams: KSerializer<*>
+ ): CompositeEncoder {
+ encodeTaggedInt(nested("size"), collectionSize)
+ return this
+ }
+
+ override fun encodeTaggedValue(tag: String, value: Any) {
+ map[tag] = value
+ }
+
+ override fun encodeTaggedNull(tag: String) {
+ map[tag] = null
+ }
+ }
+
+ internal inner class InMapper(val map: Map<String, Any>) : NamedValueDecoder() {
+ override val context: SerialModule = this@Mapper.context
+
+ override fun decodeCollectionSize(desc: SerialDescriptor): Int {
+ return decodeTaggedInt(nested("size"))
+ }
+
+ override fun decodeTaggedValue(tag: String): Any = map.getValue(tag)
+ }
+
+ internal inner class InNullableMapper(val map: Map<String, Any?>) : NamedValueDecoder() {
+ override val context: SerialModule = this@Mapper.context
+
+ override fun decodeCollectionSize(desc: SerialDescriptor): Int {
+ return decodeTaggedInt(nested("size"))
+ }
+
+ override fun decodeTaggedValue(tag: String): Any = map.getValue(tag)!!
+
+ override fun decodeTaggedNotNullMark(tag: String): Boolean {
+ return tag !in map || // in case of complex object, its fields are
+ // prefixed with dot and there are no 'clean' tag with object name.
+ // Invalid tags can be handled later, in .decodeValue
+ map.getValue(tag) != null
+ }
+ }
+
+ fun <T> map(strategy: SerializationStrategy<T>, obj: T): Map<String, Any> {
+ val m = OutMapper()
+ m.encode(strategy, obj)
+ return m.map
+ }
+
+ fun <T> mapNullable(strategy: SerializationStrategy<T>, obj: T): Map<String, Any?> {
+ val m = OutNullableMapper()
+ m.encode(strategy, obj)
+ return m.map
+ }
+
+ fun <T> unmap(strategy: DeserializationStrategy<T>, map: Map<String, Any>): T {
+ val m = InMapper(map)
+ return m.decode(strategy)
+ }
+
+ fun <T> unmapNullable(strategy: DeserializationStrategy<T>, map: Map<String, Any?>): T {
+ val m = InNullableMapper(map)
+ return m.decode(strategy)
+ }
+
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> map(obj: T): Map<String, Any> = map(context.getContextualOrDefault(T::class), obj)
+
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> mapNullable(obj: T): Map<String, Any?> =
+ mapNullable(context.getContextualOrDefault(T::class), obj)
+
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> unmap(map: Map<String, Any>): T = unmap(context.getContextualOrDefault(T::class), map)
+
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> unmapNullable(map: Map<String, Any?>): T =
+ unmapNullable(context.getContextualOrDefault(T::class), map)
+
+ companion object {
+ val default = Mapper()
+
+ fun <T> map(strategy: SerializationStrategy<T>, obj: T): Map<String, Any> = default.map(strategy, obj)
+ fun <T> mapNullable(strategy: SerializationStrategy<T>, obj: T): Map<String, Any?> =
+ default.mapNullable(strategy, obj)
+ fun <T> unmap(strategy: DeserializationStrategy<T>, map: Map<String, Any>): T = default.unmap(strategy, map)
+ fun <T> unmapNullable(strategy: DeserializationStrategy<T>, map: Map<String, Any?>): T =
+ default.unmapNullable(strategy, map)
+
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> map(obj: T): Map<String, Any> = default.map(obj)
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> mapNullable(obj: T): Map<String, Any?> = default.mapNullable(obj)
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> unmap(map: Map<String, Any>): T = default.unmap(map)
+ @ImplicitReflectionSerializer
+ inline fun <reified T : Any> unmapNullable(map: Map<String, Any?>): T = default.unmapNullable(map)
+ }
+}