diff options
Diffstat (limited to 'formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt')
-rw-r--r-- | formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt index cdaeeb03..cf562de5 100644 --- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt +++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.serialization.json.internal @@ -10,11 +10,7 @@ import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* import kotlinx.serialization.json.* import kotlinx.serialization.modules.* -import kotlin.native.concurrent.* -@ExperimentalSerializationApi -@OptIn(ExperimentalUnsignedTypes::class) -@SharedImmutable private val unsignedNumberDescriptors = setOf( UInt.serializer().descriptor, ULong.serializer().descriptor, @@ -22,11 +18,13 @@ private val unsignedNumberDescriptors = setOf( UShort.serializer().descriptor ) -@ExperimentalSerializationApi internal val SerialDescriptor.isUnsignedNumber: Boolean get() = this.isInline && this in unsignedNumberDescriptors -@OptIn(ExperimentalSerializationApi::class, ExperimentalUnsignedTypes::class) +internal val SerialDescriptor.isUnquotedLiteral: Boolean + get() = this.isInline && this == jsonUnquotedLiteralDescriptor + +@OptIn(ExperimentalSerializationApi::class) internal class StreamingJsonEncoder( private val composer: Composer, override val json: Json, @@ -35,7 +33,7 @@ internal class StreamingJsonEncoder( ) : JsonEncoder, AbstractEncoder() { internal constructor( - output: JsonStringBuilder, json: Json, mode: WriteMode, + output: InternalJsonWriter, json: Json, mode: WriteMode, modeReuseCache: Array<JsonEncoder?> ) : this(Composer(output, json), json, mode, modeReuseCache) @@ -98,7 +96,7 @@ internal class StreamingJsonEncoder( override fun endStructure(descriptor: SerialDescriptor) { if (mode.end != INVALID) { composer.unIndent() - composer.nextItem() + composer.nextItemIfNotFirst() composer.print(mode.end) } } @@ -139,7 +137,7 @@ internal class StreamingJsonEncoder( if (!composer.writingFirst) composer.print(COMMA) composer.nextItem() - encodeString(descriptor.getElementName(index)) + encodeString(descriptor.getJsonElementName(json, index)) composer.print(COLON) composer.space() } @@ -158,11 +156,20 @@ internal class StreamingJsonEncoder( } } - override fun encodeInline(inlineDescriptor: SerialDescriptor): Encoder = - if (inlineDescriptor.isUnsignedNumber) StreamingJsonEncoder( - ComposerForUnsignedNumbers(composer.sb), json, mode, null - ) - else super.encodeInline(inlineDescriptor) + override fun encodeInline(descriptor: SerialDescriptor): Encoder = + when { + descriptor.isUnsignedNumber -> StreamingJsonEncoder(composerAs(::ComposerForUnsignedNumbers), json, mode, null) + descriptor.isUnquotedLiteral -> StreamingJsonEncoder(composerAs(::ComposerForUnquotedLiterals), json, mode, null) + else -> super.encodeInline(descriptor) + } + + private inline fun <reified T: Composer> composerAs(composerCreator: (writer: InternalJsonWriter, forceQuoting: Boolean) -> T): T { + // If we're inside encodeInline().encodeSerializableValue, we should preserve the forceQuoting state + // inside the composer, but not in the encoder (otherwise we'll get into `if (forceQuoting) encodeString(value.toString())` part + // and unsigned numbers would be encoded incorrectly) + return if (composer is T) composer + else composerCreator(composer.writer, forceQuoting) + } override fun encodeNull() { composer.print(NULL) @@ -192,7 +199,7 @@ internal class StreamingJsonEncoder( // First encode value, then check, to have a prettier error message if (forceQuoting) encodeString(value.toString()) else composer.print(value) if (!configuration.allowSpecialFloatingPointValues && !value.isFinite()) { - throw InvalidFloatingPointEncoded(value, composer.sb.toString()) + throw InvalidFloatingPointEncoded(value, composer.writer.toString()) } } @@ -200,7 +207,7 @@ internal class StreamingJsonEncoder( // First encode value, then check, to have a prettier error message if (forceQuoting) encodeString(value.toString()) else composer.print(value) if (!configuration.allowSpecialFloatingPointValues && !value.isFinite()) { - throw InvalidFloatingPointEncoded(value, composer.sb.toString()) + throw InvalidFloatingPointEncoded(value, composer.writer.toString()) } } |