forked from GitLiveApp/firebase-kotlin-sdk
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPolymorphic.kt
62 lines (57 loc) · 2.73 KB
/
Polymorphic.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package dev.gitlive.firebase
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.findPolymorphicSerializer
import kotlinx.serialization.internal.AbstractPolymorphicSerializer
/*
* This code was inspired on polymorphic json serialization of kotlinx.serialization.
* See https://github.com/Kotlin/kotlinx.serialization/blob/master/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt
*/
@Suppress("UNCHECKED_CAST")
internal fun <T> FirebaseEncoder.encodePolymorphically(
serializer: SerializationStrategy<T>,
value: T,
ifPolymorphic: (String) -> Unit
) {
// If serializer is not an AbstractPolymorphicSerializer we can just use the regular serializer
// This will result in calling structureEncoder for complicated structures
// For PolymorphicKind this will first encode the polymorphic discriminator as a String and the remaining StructureKind.Class as a map of key-value pairs
// This will result in a list structured like: (type, { classKey = classValue })
if (serializer !is AbstractPolymorphicSerializer<*>) {
serializer.serialize(this, value)
return
}
val casted = serializer as AbstractPolymorphicSerializer<Any>
val baseClassDiscriminator = serializer.descriptor.classDiscriminator()
val actualSerializer = casted.findPolymorphicSerializer(this, value as Any)
ifPolymorphic(baseClassDiscriminator)
actualSerializer.serialize(this, value)
}
@Suppress("UNCHECKED_CAST")
internal fun <T> FirebaseDecoder.decodeSerializableValuePolymorphic(
value: Any?,
deserializer: DeserializationStrategy<T>,
): T {
// If deserializer is not an AbstractPolymorphicSerializer we can just use the regular serializer
if (deserializer !is AbstractPolymorphicSerializer<*>) {
return deserializer.deserialize(this)
}
val casted = deserializer as AbstractPolymorphicSerializer<Any>
val discriminator = deserializer.descriptor.classDiscriminator()
val type = getPolymorphicType(value, discriminator)
val actualDeserializer = casted.findPolymorphicSerializerOrNull(
structureDecoder(deserializer.descriptor, false),
type
) as DeserializationStrategy<T>
return actualDeserializer.deserialize(this)
}
internal fun SerialDescriptor.classDiscriminator(): String {
// Plain loop is faster than allocation of Sequence or ArrayList
// We can rely on the fact that only one FirebaseClassDiscriminator is present —
// compiler plugin checked that.
for (annotation in annotations) {
if (annotation is FirebaseClassDiscriminator) return annotation.discriminator
}
return "type"
}