All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.dev.gitlive.firebase.internal.serializers.kt Maven / Gradle / Ivy

Go to download

The Firebase Kotlin SDK is a Kotlin-first SDK for Firebase. It's API is similar to the Firebase Android SDK Kotlin Extensions but also supports multiplatform projects, enabling you to use Firebase directly from your common source targeting iOS, Android or JS.

There is a newer version: 2.1.0
Show newest version
/*
 * Copyright (c) 2020 GitLive Ltd.  Use of this source code is governed by the Apache 2.0 license.
 */

package dev.gitlive.firebase.internal

import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.StructureKind
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.serializer

@Suppress("UNCHECKED_CAST")
public inline fun  T.firebaseSerializer(): SerializationStrategy = runCatching { serializer() }
    .getOrElse {
        when (this) {
            is Map<*, *> -> FirebaseMapSerializer()
            is List<*> -> FirebaseListSerializer()
            is Set<*> -> FirebaseListSerializer()
            else -> this::class.serializer()
        } as SerializationStrategy
    }

public class FirebaseMapSerializer : KSerializer> {

    public lateinit var keys: List
    public lateinit var map: Map

    override val descriptor: SerialDescriptor = object : SerialDescriptor {
        override val kind = StructureKind.MAP
        override val serialName = "kotlin.Map"
        override val elementsCount get() = map.size
        override fun getElementIndex(name: String) = keys.indexOf(name)
        override fun getElementName(index: Int) = keys[index]
        override fun getElementAnnotations(index: Int) = emptyList()
        override fun getElementDescriptor(index: Int) = throw NotImplementedError()
        override fun isElementOptional(index: Int) = false
    }

    @Suppress("UNCHECKED_CAST")
    override fun serialize(encoder: Encoder, value: Map) {
        map = value
        keys = value.keys.toList()
        val collectionEncoder = encoder.beginCollection(descriptor, value.size)
        keys.forEachIndexed { index, key ->
            val listValue = map.getValue(key)
            val serializer = (listValue?.firebaseSerializer() ?: Unit.serializer()) as KSerializer
            String.serializer().let {
                collectionEncoder.encodeSerializableElement(it.descriptor, index * 2, it, key)
            }
            collectionEncoder.encodeNullableSerializableElement(
                serializer.descriptor,
                index * 2 + 1,
                serializer,
                listValue,
            )
        }
        collectionEncoder.endStructure(descriptor)
    }

    override fun deserialize(decoder: Decoder): Map {
        val collectionDecoder = decoder.beginStructure(descriptor) as FirebaseCompositeDecoder
        val map = mutableMapOf()
        for (index in 0 until collectionDecoder.decodeCollectionSize(descriptor) * 2 step 2) {
//            map[collectionDecoder.decodeNullableSerializableElement(index) as String] =
//                collectionDecoder.decodeNullableSerializableElement(index + 1)
        }
        return map
    }
}

public class FirebaseListSerializer : KSerializer> {

    public lateinit var list: List

    override val descriptor: SerialDescriptor = object : SerialDescriptor {
        override val kind = StructureKind.LIST
        override val serialName = "kotlin.List"
        override val elementsCount get() = list.size
        override fun getElementIndex(name: String) = throw NotImplementedError()
        override fun getElementName(index: Int) = throw NotImplementedError()
        override fun getElementAnnotations(index: Int) = emptyList()
        override fun getElementDescriptor(index: Int) = throw NotImplementedError()
        override fun isElementOptional(index: Int) = false
    }

    @Suppress("UNCHECKED_CAST")
    override fun serialize(encoder: Encoder, value: Iterable) {
        list = value.toList()
        val collectionEncoder = encoder.beginCollection(descriptor, list.size)
        list.forEachIndexed { index, listValue ->
            val serializer = (listValue?.firebaseSerializer() ?: Unit.serializer()) as KSerializer
            collectionEncoder.encodeNullableSerializableElement(
                serializer.descriptor,
                index,
                serializer,
                listValue,
            )
        }
        collectionEncoder.endStructure(descriptor)
    }

    override fun deserialize(decoder: Decoder): List {
        throw NotImplementedError()
//        val collectionDecoder = decoder.beginStructure(descriptor) as FirebaseCompositeDecoder
//        val list = mutableListOf()
//        list.forEachIndexed { index, _ ->
//            list.add(index, collectionDecoder.decodeNullableSerializableElement(index))
//        }
//        return list
    }
}

/**
 * A special case of serializer for values natively supported by Firebase and
 * don't require an additional encoding/decoding.
 */
public class SpecialValueSerializer(
    serialName: String,
    private val toNativeValue: (T) -> Any?,
    private val fromNativeValue: (Any?) -> T,
) : KSerializer {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor(serialName) { }

    override fun serialize(encoder: Encoder, value: T) {
        if (encoder is FirebaseEncoder) {
            encoder.value = toNativeValue(value)
        } else {
            throw SerializationException("This serializer must be used with FirebaseEncoder")
        }
    }

    override fun deserialize(decoder: Decoder): T = if (decoder is FirebaseDecoder) {
        fromNativeValue(decoder.value)
    } else {
        throw SerializationException("This serializer must be used with FirebaseDecoder")
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy