xref: /aosp_15_r20/external/kotlinx.serialization/core/commonMain/src/kotlinx/serialization/internal/Tagged.kt (revision 57b5a4a64c534cf7f27ac9427ceab07f3d8ed3d8)
1 /*
2  * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 @file:OptIn(ExperimentalSerializationApi::class)
5 
6 package kotlinx.serialization.internal
7 
8 import kotlinx.serialization.*
9 import kotlinx.serialization.descriptors.*
10 import kotlinx.serialization.encoding.*
11 import kotlinx.serialization.modules.*
12 
13 /*
14  * These classes are intended to be used only within the kotlinx.serialization.
15  * They neither do have stable API, nor internal invariants and are changed without any warnings.
16  */
17 @InternalSerializationApi
18 public abstract class TaggedEncoder<Tag : Any?> : Encoder, CompositeEncoder {
19 
20     /**
21      * Provides a tag object for given serial descriptor and index.
22      * Tag object allows associating given user information with a particular element of composite serializable entity.
23      */
SerialDescriptornull24     protected abstract fun SerialDescriptor.getTag(index: Int): Tag
25 
26     override val serializersModule: SerializersModule
27         get() = EmptySerializersModule()
28 
29     // ---- API ----
30     protected open fun encodeTaggedValue(tag: Tag, value: Any): Unit =
31         throw SerializationException("Non-serializable ${value::class} is not supported by ${this::class} encoder")
32 
33     protected open fun encodeTaggedNonNullMark(tag: Tag) {}
encodeTaggedNullnull34     protected open fun encodeTaggedNull(tag: Tag): Unit = throw SerializationException("null is not supported")
35     protected open fun encodeTaggedInt(tag: Tag, value: Int): Unit = encodeTaggedValue(tag, value)
36     protected open fun encodeTaggedByte(tag: Tag, value: Byte): Unit = encodeTaggedValue(tag, value)
37     protected open fun encodeTaggedShort(tag: Tag, value: Short): Unit = encodeTaggedValue(tag, value)
38     protected open fun encodeTaggedLong(tag: Tag, value: Long): Unit = encodeTaggedValue(tag, value)
39     protected open fun encodeTaggedFloat(tag: Tag, value: Float): Unit = encodeTaggedValue(tag, value)
40     protected open fun encodeTaggedDouble(tag: Tag, value: Double): Unit = encodeTaggedValue(tag, value)
41     protected open fun encodeTaggedBoolean(tag: Tag, value: Boolean): Unit = encodeTaggedValue(tag, value)
42     protected open fun encodeTaggedChar(tag: Tag, value: Char): Unit = encodeTaggedValue(tag, value)
43     protected open fun encodeTaggedString(tag: Tag, value: String): Unit = encodeTaggedValue(tag, value)
44 
45     protected open fun encodeTaggedEnum(
46         tag: Tag,
47         enumDescriptor: SerialDescriptor,
48         ordinal: Int
49     ): Unit = encodeTaggedValue(tag, ordinal)
50 
51     protected open fun encodeTaggedInline(tag: Tag, inlineDescriptor: SerialDescriptor): Encoder =
52         this.apply { pushTag(tag) }
53 
encodeInlinenull54     override fun encodeInline(descriptor: SerialDescriptor): Encoder =
55         encodeTaggedInline(popTag(), descriptor)
56 
57     // ---- Implementation of low-level API ----
58 
59     private fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
60         val tag = desc.getTag(index)
61         pushTag(tag)
62         return true
63     }
64 
encodeNotNullMarknull65     open override fun encodeNotNullMark(): Unit = encodeTaggedNonNullMark(currentTag)
66     open override fun encodeNull(): Unit = encodeTaggedNull(popTag())
67     final override fun encodeBoolean(value: Boolean): Unit = encodeTaggedBoolean(popTag(), value)
68     final override fun encodeByte(value: Byte): Unit = encodeTaggedByte(popTag(), value)
69     final override fun encodeShort(value: Short): Unit = encodeTaggedShort(popTag(), value)
70     final override fun encodeInt(value: Int): Unit = encodeTaggedInt(popTag(), value)
71     final override fun encodeLong(value: Long): Unit = encodeTaggedLong(popTag(), value)
72     final override fun encodeFloat(value: Float): Unit = encodeTaggedFloat(popTag(), value)
73     final override fun encodeDouble(value: Double): Unit = encodeTaggedDouble(popTag(), value)
74     final override fun encodeChar(value: Char): Unit = encodeTaggedChar(popTag(), value)
75     final override fun encodeString(value: String): Unit = encodeTaggedString(popTag(), value)
76 
77     final override fun encodeEnum(
78         enumDescriptor: SerialDescriptor,
79         index: Int
80     ): Unit = encodeTaggedEnum(popTag(), enumDescriptor, index)
81 
82     override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder = this
83 
84     final override fun endStructure(descriptor: SerialDescriptor) {
85         if (tagStack.isNotEmpty()) {
86             popTag()
87         }
88         endEncode(descriptor)
89     }
90 
91     /**
92      * Format-specific replacement for [endStructure], because latter is overridden to manipulate tag stack.
93      */
endEncodenull94     protected open fun endEncode(descriptor: SerialDescriptor) {}
95 
encodeBooleanElementnull96     final override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean): Unit =
97         encodeTaggedBoolean(descriptor.getTag(index), value)
98 
99     final override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte): Unit =
100         encodeTaggedByte(descriptor.getTag(index), value)
101 
102     final override fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short): Unit =
103         encodeTaggedShort(descriptor.getTag(index), value)
104 
105     final override fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int): Unit =
106         encodeTaggedInt(descriptor.getTag(index), value)
107 
108     final override fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long): Unit =
109         encodeTaggedLong(descriptor.getTag(index), value)
110 
111     final override fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float): Unit =
112         encodeTaggedFloat(descriptor.getTag(index), value)
113 
114     final override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double): Unit =
115         encodeTaggedDouble(descriptor.getTag(index), value)
116 
117     final override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char): Unit =
118         encodeTaggedChar(descriptor.getTag(index), value)
119 
120     final override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String): Unit =
121         encodeTaggedString(descriptor.getTag(index), value)
122 
123     final override fun encodeInlineElement(
124         descriptor: SerialDescriptor,
125         index: Int
126     ): Encoder {
127         return encodeTaggedInline(descriptor.getTag(index), descriptor.getElementDescriptor(index))
128     }
129 
encodeSerializableElementnull130     override fun <T : Any?> encodeSerializableElement(
131         descriptor: SerialDescriptor,
132         index: Int,
133         serializer: SerializationStrategy<T>,
134         value: T
135     ) {
136         if (encodeElement(descriptor, index))
137             encodeSerializableValue(serializer, value)
138     }
139 
140     @OptIn(ExperimentalSerializationApi::class)
encodeNullableSerializableElementnull141     override fun <T : Any> encodeNullableSerializableElement(
142         descriptor: SerialDescriptor,
143         index: Int,
144         serializer: SerializationStrategy<T>,
145         value: T?
146     ) {
147         if (encodeElement(descriptor, index))
148             encodeNullableSerializableValue(serializer, value)
149     }
150 
151     private val tagStack = arrayListOf<Tag>()
152     protected val currentTag: Tag
153         get() = tagStack.last()
154     protected val currentTagOrNull: Tag?
155         get() = tagStack.lastOrNull()
156 
pushTagnull157     protected fun pushTag(name: Tag) {
158         tagStack.add(name)
159     }
160 
popTagnull161     protected fun popTag(): Tag =
162         if (tagStack.isNotEmpty())
163             tagStack.removeAt(tagStack.lastIndex)
164         else
165             throw SerializationException("No tag in stack for requested element")
166 }
167 
168 @InternalSerializationApi
169 @OptIn(ExperimentalSerializationApi::class)
170 public abstract class NamedValueEncoder : TaggedEncoder<String>() {
171     final override fun SerialDescriptor.getTag(index: Int): String = nested(elementName(this, index))
172     protected fun nested(nestedName: String): String = composeName(currentTagOrNull ?: "", nestedName)
173     protected open fun elementName(descriptor: SerialDescriptor, index: Int): String = descriptor.getElementName(index)
174     protected open fun composeName(parentName: String, childName: String): String =
175         if (parentName.isEmpty()) childName else "$parentName.$childName"
176 }
177 
178 @InternalSerializationApi
179 public abstract class TaggedDecoder<Tag : Any?> : Decoder, CompositeDecoder {
180     override val serializersModule: SerializersModule
181         get() = EmptySerializersModule()
182 
SerialDescriptornull183     protected abstract fun SerialDescriptor.getTag(index: Int): Tag
184 
185     // ---- API ----
186     protected open fun decodeTaggedValue(tag: Tag): Any =
187         throw SerializationException("${this::class} can't retrieve untyped values")
188 
189     protected open fun decodeTaggedNotNullMark(tag: Tag): Boolean = true
190     protected open fun decodeTaggedNull(tag: Tag): Nothing? = null
191 
192     protected open fun decodeTaggedBoolean(tag: Tag): Boolean = decodeTaggedValue(tag) as Boolean
193     protected open fun decodeTaggedByte(tag: Tag): Byte = decodeTaggedValue(tag) as Byte
194     protected open fun decodeTaggedShort(tag: Tag): Short = decodeTaggedValue(tag) as Short
195     protected open fun decodeTaggedInt(tag: Tag): Int = decodeTaggedValue(tag) as Int
196     protected open fun decodeTaggedLong(tag: Tag): Long = decodeTaggedValue(tag) as Long
197     protected open fun decodeTaggedFloat(tag: Tag): Float = decodeTaggedValue(tag) as Float
198     protected open fun decodeTaggedDouble(tag: Tag): Double = decodeTaggedValue(tag) as Double
199     protected open fun decodeTaggedChar(tag: Tag): Char = decodeTaggedValue(tag) as Char
200     protected open fun decodeTaggedString(tag: Tag): String = decodeTaggedValue(tag) as String
201     protected open fun decodeTaggedEnum(tag: Tag, enumDescriptor: SerialDescriptor): Int =
202         decodeTaggedValue(tag) as Int
203 
204     protected open fun decodeTaggedInline(tag: Tag, inlineDescriptor: SerialDescriptor): Decoder = this.apply { pushTag(tag) }
205 
decodeSerializableValuenull206     protected open fun <T : Any?> decodeSerializableValue(deserializer: DeserializationStrategy<T>, previousValue: T?): T =
207         decodeSerializableValue(deserializer)
208 
209     // ---- Implementation of low-level API ----
210 
211     override fun decodeInline(descriptor: SerialDescriptor): Decoder =
212         decodeTaggedInline(popTag(), descriptor)
213 
214     // TODO this method should be overridden by any sane format that supports top-level nulls
215     override fun decodeNotNullMark(): Boolean {
216         // Tag might be null for top-level deserialization
217         val currentTag = currentTagOrNull ?: return false
218         return decodeTaggedNotNullMark(currentTag)
219     }
220 
decodeNullnull221     final override fun decodeNull(): Nothing? = null
222 
223     final override fun decodeBoolean(): Boolean = decodeTaggedBoolean(popTag())
224     final override fun decodeByte(): Byte = decodeTaggedByte(popTag())
225     final override fun decodeShort(): Short = decodeTaggedShort(popTag())
226     final override fun decodeInt(): Int = decodeTaggedInt(popTag())
227     final override fun decodeLong(): Long = decodeTaggedLong(popTag())
228     final override fun decodeFloat(): Float = decodeTaggedFloat(popTag())
229     final override fun decodeDouble(): Double = decodeTaggedDouble(popTag())
230     final override fun decodeChar(): Char = decodeTaggedChar(popTag())
231     final override fun decodeString(): String = decodeTaggedString(popTag())
232 
233     final override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = decodeTaggedEnum(popTag(), enumDescriptor)
234 
235     override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder = this
236 
237     override fun endStructure(descriptor: SerialDescriptor) {
238         // Nothing
239     }
240 
decodeBooleanElementnull241     final override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean =
242         decodeTaggedBoolean(descriptor.getTag(index))
243 
244     final override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte =
245         decodeTaggedByte(descriptor.getTag(index))
246 
247     final override fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short =
248         decodeTaggedShort(descriptor.getTag(index))
249 
250     final override fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int =
251         decodeTaggedInt(descriptor.getTag(index))
252 
253     final override fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long =
254         decodeTaggedLong(descriptor.getTag(index))
255 
256     final override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float =
257         decodeTaggedFloat(descriptor.getTag(index))
258 
259     final override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double =
260         decodeTaggedDouble(descriptor.getTag(index))
261 
262     final override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char =
263         decodeTaggedChar(descriptor.getTag(index))
264 
265     final override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String =
266         decodeTaggedString(descriptor.getTag(index))
267 
268     final override fun decodeInlineElement(
269         descriptor: SerialDescriptor,
270         index: Int
271     ): Decoder = decodeTaggedInline(descriptor.getTag(index), descriptor.getElementDescriptor(index))
272 
273     final override fun <T : Any?> decodeSerializableElement(
274         descriptor: SerialDescriptor,
275         index: Int,
276         deserializer: DeserializationStrategy<T>,
277         previousValue: T?
278     ): T =
279         tagBlock(descriptor.getTag(index)) { decodeSerializableValue(deserializer, previousValue) }
280 
decodeNullableSerializableElementnull281     final override fun <T : Any> decodeNullableSerializableElement(
282         descriptor: SerialDescriptor,
283         index: Int,
284         deserializer: DeserializationStrategy<T?>,
285         previousValue: T?
286     ): T? = tagBlock(descriptor.getTag(index)) {
287         decodeIfNullable(deserializer) {
288             decodeSerializableValue(deserializer, previousValue)
289         }
290     }
291 
tagBlocknull292     private fun <E> tagBlock(tag: Tag, block: () -> E): E {
293         pushTag(tag)
294         val r = block()
295         if (!flag) {
296             popTag()
297         }
298         flag = false
299         return r
300     }
301 
302     private val tagStack = arrayListOf<Tag>()
303     protected val currentTag: Tag
304         get() = tagStack.last()
305     protected val currentTagOrNull: Tag?
306         get() = tagStack.lastOrNull()
307 
pushTagnull308     protected fun pushTag(name: Tag) {
309         tagStack.add(name)
310     }
311 
copyTagsTonull312     protected fun copyTagsTo(other: TaggedDecoder<Tag>) {
313         other.tagStack.addAll(tagStack)
314     }
315 
316     private var flag = false
317 
popTagnull318     protected fun popTag(): Tag {
319         val r = tagStack.removeAt(tagStack.lastIndex)
320         flag = true
321         return r
322     }
323 }
324 
325 @InternalSerializationApi
326 @OptIn(ExperimentalSerializationApi::class)
327 public abstract class NamedValueDecoder : TaggedDecoder<String>() {
getTagnull328     final override fun SerialDescriptor.getTag(index: Int): String = nested(elementName(this, index))
329 
330     protected fun nested(nestedName: String): String = composeName(currentTagOrNull ?: "", nestedName)
331     protected open fun elementName(descriptor: SerialDescriptor, index: Int): String = descriptor.getElementName(index)
332     protected open fun composeName(parentName: String, childName: String): String =
333         if (parentName.isEmpty()) childName else "$parentName.$childName"
334 }
335