Skip to content

Commit

Permalink
Support Serializer for Nothing on the JS target (#2330)
Browse files Browse the repository at this point in the history
Workaround for KT-51333: serialization of `Nothing` on the JS target and related tests

See also #932 

Co-authored-by: Leonid Startsev <[email protected]>
  • Loading branch information
ShreckYe and sandwwraith authored Jul 12, 2023
1 parent 782b9f3 commit b8de86f
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
24 changes: 24 additions & 0 deletions core/commonTest/src/kotlinx/serialization/SerializersModuleTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class SerializersModuleTest {
@Serializable
class Parametrized<T : Any>(val a: T)

@Serializable
class ParametrizedOfNullable<T>(val a: T)

class ContextualType(val i: Int)

@Serializer(forClass = ContextualType::class)
Expand Down Expand Up @@ -81,6 +84,27 @@ class SerializersModuleTest {
assertEquals(PrimitiveKind.INT, mapSerializer.descriptor.getElementDescriptor(1).kind)
}

@Suppress("UNCHECKED_CAST")
@Test
fun testNothingAndParameterizedOfNothing() {
assertEquals(NothingSerializer, Nothing::class.serializer())
//assertEquals(NothingSerializer, serializer<Nothing>()) // prohibited by compiler
assertEquals(NothingSerializer, serializer(Nothing::class, emptyList(), false) as KSerializer<Nothing>)
//assertEquals(NullableSerializer(NothingSerializer), serializer<Nothing?>()) // prohibited by compiler
assertEquals(
NullableSerializer(NothingSerializer),
serializer(Nothing::class, emptyList(), true) as KSerializer<Nothing?>
)

val parameterizedNothingSerializer = serializer<Parametrized<Nothing>>()
val nothingDescriptor = parameterizedNothingSerializer.descriptor.getElementDescriptor(0)
assertEquals(NothingSerialDescriptor, nothingDescriptor)

val parameterizedNullableNothingSerializer = serializer<ParametrizedOfNullable<Nothing?>>()
val nullableNothingDescriptor = parameterizedNullableNothingSerializer.descriptor.getElementDescriptor(0)
assertEquals(SerialDescriptorForNullable(NothingSerialDescriptor), nullableNothingDescriptor)
}

@Test
fun testUnsupportedArray() {
assertFails {
Expand Down
7 changes: 5 additions & 2 deletions core/jsMain/src/kotlinx/serialization/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ internal actual fun BooleanArray.getChecked(index: Int): Boolean {
if (index !in indices) throw IndexOutOfBoundsException("Index $index out of bounds $indices")
return get(index)
}
@Suppress("UNCHECKED_CAST")

internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? =
this.constructSerializerForGivenTypeArgs() ?: this.js.asDynamic().Companion?.serializer() as? KSerializer<T>
this.constructSerializerForGivenTypeArgs() ?: (
if (this === Nothing::class) NothingSerializer // Workaround for KT-51333
else this.js.asDynamic().Companion?.serializer()
) as? KSerializer<T>

internal actual fun <T> createCache(factory: (KClass<*>) -> KSerializer<T>?): SerializerCache<T> {
return object: SerializerCache<T> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.serialization.protobuf

import kotlinx.serialization.*
import kotlinx.serialization.test.*
import kotlin.test.*

class ProtobufNothingTest {
@Serializable
/*private*/ data class NullableNothingBox(val value: Nothing?) // `private` doesn't work on the JS legacy target

@Serializable
private data class ParameterizedBox<T : Any>(val value: T?)

private inline fun <reified T> testConversion(data: T, expectedHexString: String) {
val string = ProtoBuf.encodeToHexString(data).uppercase()
assertEquals(expectedHexString, string)
assertEquals(data, ProtoBuf.decodeFromHexString(string))
}

@Test
fun testNothing() {
testConversion(NullableNothingBox(null), "")
if (isJsLegacy()) return
testConversion(ParameterizedBox(null), "")
}
}

0 comments on commit b8de86f

Please sign in to comment.