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

commonMain.dev.gitlive.firebase.internal.encoders.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 dev.gitlive.firebase.EncodeSettings
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule

@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("encode(strategy, value) { encodeDefaults = shouldEncodeElementDefault }"))
public fun  encode(strategy: SerializationStrategy, value: T, shouldEncodeElementDefault: Boolean): Any? = encode(strategy, value) {
    this.encodeDefaults = shouldEncodeElementDefault
}

public inline fun  encode(strategy: SerializationStrategy, value: T, buildSettings: EncodeSettings.Builder.() -> Unit): Any? =
    encode(strategy, value, EncodeSettingsImpl.Builder().apply(buildSettings).buildEncodeSettings())

@PublishedApi
internal fun  encode(strategy: SerializationStrategy, value: T, encodeSettings: EncodeSettings): Any? =
    FirebaseEncoder(encodeSettings).apply { encodeSerializableValue(strategy, value) }.value

@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("encode(value) { this.encodeDefaults = shouldEncodeElementDefault }"))
public inline fun  encode(value: T, shouldEncodeElementDefault: Boolean): Any? = encode(value) {
    this.encodeDefaults = shouldEncodeElementDefault
}

public inline fun  encode(value: T, buildSettings: EncodeSettings.Builder.() -> Unit = {}): Any? =
    encode(value, EncodeSettingsImpl.Builder().apply(buildSettings).buildEncodeSettings())

/**
 * Encodes data as an [EncodedObject].
 * This is not recommended for manual use, but may be done by the library internally.
 * @throws IllegalArgumentException if [value] is not valid as an [EncodedObject] (e.g. not encodable in the form Map
 */
public inline fun  encodeAsObject(strategy: SerializationStrategy, value: T, buildSettings: EncodeSettings.Builder.() -> Unit = {}): EncodedObject {
    if (value is Map<*, *> && value.keys.any { it !is String }) {
        throw IllegalArgumentException("$value is a Map containing non-String keys. Must be of the form Map")
    }
    val encoded = encode(strategy, value, buildSettings) ?: throw IllegalArgumentException("$value was encoded as null. Must be of the form Map")
    return encoded.asNativeMap()?.asEncodedObject() ?: throw IllegalArgumentException("$value was encoded as ${encoded::class}. Must be of the form Map")
}

/**
 * Encodes data as an [EncodedObject].
 * This is not recommended for manual use, but may be done by the library internally.
 * @throws IllegalArgumentException if [value] is not valid as an [EncodedObject] (e.g. not encodable in the form Map
 */
public inline fun  encodeAsObject(value: T, buildSettings: EncodeSettings.Builder.() -> Unit = {}): EncodedObject {
    if (value is Map<*, *> && value.keys.any { it !is String }) {
        throw IllegalArgumentException("$value is a Map containing non-String keys. Must be of the form Map")
    }
    val encoded = encode(value, buildSettings) ?: throw IllegalArgumentException("$value was encoded as null. Must be of the form Map")
    return encoded.asNativeMap()?.asEncodedObject() ?: throw IllegalArgumentException("$value was encoded as ${encoded::class}. Must be of the form Map")
}

@PublishedApi
internal inline fun  encode(value: T, encodeSettings: EncodeSettings): Any? = value?.let {
    FirebaseEncoder(encodeSettings).apply {
        if (it is ValueWithSerializer<*> && it.value is T) {
            @Suppress("UNCHECKED_CAST")
            (it as ValueWithSerializer).let {
                encodeSerializableValue(it.serializer, it.value)
            }
        } else {
            encodeSerializableValue(it.firebaseSerializer(), it)
        }
    }.value
}

/**
 * An extension which which serializer to use for value. Handy in updating fields by name or path
 * where using annotation is not possible
 * @return a value with a custom serializer.
 */
public fun  T.withSerializer(serializer: SerializationStrategy): Any = ValueWithSerializer(this, serializer)
public data class ValueWithSerializer(val value: T, val serializer: SerializationStrategy)

public expect fun FirebaseEncoder.structureEncoder(descriptor: SerialDescriptor): FirebaseCompositeEncoder

public class FirebaseEncoder(
    internal val settings: EncodeSettings,
) : Encoder {

    public constructor(shouldEncodeElementDefault: Boolean) : this(
        EncodeSettingsImpl.Builder().apply { this.encodeDefaults = shouldEncodeElementDefault }.buildEncodeSettings(),
    )

    public var value: Any? = null

    override val serializersModule: SerializersModule = settings.serializersModule

    private var polymorphicDiscriminator: String? = null

    override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
        val encoder = structureEncoder(descriptor)
        if (polymorphicDiscriminator != null) {
            encoder.encodePolymorphicClassDiscriminator(polymorphicDiscriminator!!, descriptor.serialName)
            polymorphicDiscriminator = null
        }
        return encoder
    }

    override fun encodeBoolean(value: Boolean) {
        this.value = value
    }

    override fun encodeByte(value: Byte) {
        this.value = value
    }

    override fun encodeChar(value: Char) {
        this.value = value
    }

    override fun encodeDouble(value: Double) {
        this.value = value
    }

    override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) {
        this.value = enumDescriptor.getElementName(index)
    }

    override fun encodeFloat(value: Float) {
        this.value = value
    }

    override fun encodeInt(value: Int) {
        this.value = value
    }

    override fun encodeLong(value: Long) {
        this.value = value
    }

    override fun encodeNotNullMark() {
        // no-op
    }

    override fun encodeNull() {
        this.value = null
    }

    override fun encodeShort(value: Short) {
        this.value = value
    }

    override fun encodeString(value: String) {
        this.value = value
    }

    override fun encodeInline(descriptor: SerialDescriptor): Encoder = this

    override fun  encodeSerializableValue(serializer: SerializationStrategy, value: T) {
        encodePolymorphically(serializer, value) {
            polymorphicDiscriminator = it
        }
    }
}

public open class FirebaseCompositeEncoder(
    private val settings: EncodeSettings,
    private val end: () -> Unit = {},
    private val setPolymorphicType: (String, String) -> Unit = { _, _ -> },
    private val set: (descriptor: SerialDescriptor, index: Int, value: Any?) -> Unit,
) : CompositeEncoder {

//    private fun  SerializationStrategy.toFirebase(): SerializationStrategy = when(descriptor.kind) {
//        StructureKind.MAP -> FirebaseMapSerializer(descriptor.getElementDescriptor(1)) as SerializationStrategy
//        StructureKind.LIST -> FirebaseListSerializer(descriptor.getElementDescriptor(0)) as SerializationStrategy
//        else -> this
//    }

    override val serializersModule: SerializersModule = settings.serializersModule

    override fun endStructure(descriptor: SerialDescriptor): Unit = end()

    override fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean = settings.encodeDefaults

    override fun  encodeNullableSerializableElement(
        descriptor: SerialDescriptor,
        index: Int,
        serializer: SerializationStrategy,
        value: T?,
    ): Unit = set(
        descriptor,
        index,
        value?.let {
            FirebaseEncoder(settings).apply {
                encodeSerializableValue(serializer, value)
            }.value
        },
    )

    override fun  encodeSerializableElement(
        descriptor: SerialDescriptor,
        index: Int,
        serializer: SerializationStrategy,
        value: T,
    ): Unit = set(
        descriptor,
        index,
        FirebaseEncoder(settings).apply {
            encodeSerializableValue(serializer, value)
        }.value,
    )

    public fun  encodeObject(descriptor: SerialDescriptor, index: Int, value: T): Unit = set(descriptor, index, value)

    override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean): Unit = set(descriptor, index, value)

    override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte): Unit = set(descriptor, index, value)

    override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char): Unit = set(descriptor, index, value)

    override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double): Unit = set(descriptor, index, value)

    override fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float): Unit = set(descriptor, index, value)

    override fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int): Unit = set(descriptor, index, value)

    override fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long): Unit = set(descriptor, index, value)

    override fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short): Unit = set(descriptor, index, value)

    override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String): Unit = set(descriptor, index, value)

    @ExperimentalSerializationApi
    override fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder =
        FirebaseEncoder(settings)

    public fun encodePolymorphicClassDiscriminator(discriminator: String, type: String) {
        setPolymorphicType(discriminator, type)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy