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