Skip to content

Commit

Permalink
Experimental support for inline classes (#1244)
Browse files Browse the repository at this point in the history
* Support for `@Serializable inline class` with generated (requires 1.4.30 IR compiler) and custom serializers

* Standard serializers for UInt, ULong, UByte and UShort

* Unsigned types support for both streaming and tree Json

* Exclude folder with inline classes tests when legacy JVM compiler is used

* Add appendix with info about inline classes to documentation

Co-authored-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
  • Loading branch information
sandwwraith and qwwdfsad authored Jan 28, 2021
1 parent 07f730a commit ac54504
Show file tree
Hide file tree
Showing 31 changed files with 1,140 additions and 55 deletions.
64 changes: 64 additions & 0 deletions core/api/kotlinx-serialization-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ public final class kotlinx/serialization/builtins/BuiltinSerializersKt {
public static final fun ShortArraySerializer ()Lkotlinx/serialization/KSerializer;
public static final fun TripleSerializer (Lkotlinx/serialization/KSerializer;Lkotlinx/serialization/KSerializer;Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
public static final fun getNullable (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/UByte$Companion;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/UInt$Companion;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/ULong$Companion;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/UShort$Companion;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/Unit;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/jvm/internal/BooleanCompanionObject;)Lkotlinx/serialization/KSerializer;
public static final fun serializer (Lkotlin/jvm/internal/ByteCompanionObject;)Lkotlinx/serialization/KSerializer;
Expand Down Expand Up @@ -242,11 +246,13 @@ public abstract interface class kotlinx/serialization/descriptors/SerialDescript
public abstract fun getKind ()Lkotlinx/serialization/descriptors/SerialKind;
public abstract fun getSerialName ()Ljava/lang/String;
public abstract fun isElementOptional (I)Z
public abstract fun isInline ()Z
public abstract fun isNullable ()Z
}

public final class kotlinx/serialization/descriptors/SerialDescriptor$DefaultImpls {
public static fun getAnnotations (Lkotlinx/serialization/descriptors/SerialDescriptor;)Ljava/util/List;
public static fun isInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Z
public static fun isNullable (Lkotlinx/serialization/descriptors/SerialDescriptor;)Z
}

Expand Down Expand Up @@ -315,6 +321,8 @@ public abstract class kotlinx/serialization/encoding/AbstractDecoder : kotlinx/s
public fun decodeEnum (Lkotlinx/serialization/descriptors/SerialDescriptor;)I
public fun decodeFloat ()F
public final fun decodeFloatElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)F
public fun decodeInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Decoder;
public final fun decodeInlineElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/Decoder;
public fun decodeInt ()I
public final fun decodeIntElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)I
public fun decodeLong ()J
Expand Down Expand Up @@ -352,6 +360,8 @@ public abstract class kotlinx/serialization/encoding/AbstractEncoder : kotlinx/s
public fun encodeEnum (Lkotlinx/serialization/descriptors/SerialDescriptor;I)V
public fun encodeFloat (F)V
public final fun encodeFloatElement (Lkotlinx/serialization/descriptors/SerialDescriptor;IF)V
public fun encodeInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Encoder;
public final fun encodeInlineElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/Encoder;
public fun encodeInt (I)V
public final fun encodeIntElement (Lkotlinx/serialization/descriptors/SerialDescriptor;II)V
public fun encodeLong (J)V
Expand Down Expand Up @@ -382,6 +392,7 @@ public abstract interface class kotlinx/serialization/encoding/CompositeDecoder
public abstract fun decodeDoubleElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)D
public abstract fun decodeElementIndex (Lkotlinx/serialization/descriptors/SerialDescriptor;)I
public abstract fun decodeFloatElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)F
public abstract fun decodeInlineElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/Decoder;
public abstract fun decodeIntElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)I
public abstract fun decodeLongElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)J
public abstract fun decodeNullableSerializableElement (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/DeserializationStrategy;Ljava/lang/Object;)Ljava/lang/Object;
Expand Down Expand Up @@ -411,6 +422,7 @@ public abstract interface class kotlinx/serialization/encoding/CompositeEncoder
public abstract fun encodeCharElement (Lkotlinx/serialization/descriptors/SerialDescriptor;IC)V
public abstract fun encodeDoubleElement (Lkotlinx/serialization/descriptors/SerialDescriptor;ID)V
public abstract fun encodeFloatElement (Lkotlinx/serialization/descriptors/SerialDescriptor;IF)V
public abstract fun encodeInlineElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/Encoder;
public abstract fun encodeIntElement (Lkotlinx/serialization/descriptors/SerialDescriptor;II)V
public abstract fun encodeLongElement (Lkotlinx/serialization/descriptors/SerialDescriptor;IJ)V
public abstract fun encodeNullableSerializableElement (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
Expand All @@ -434,6 +446,7 @@ public abstract interface class kotlinx/serialization/encoding/Decoder {
public abstract fun decodeDouble ()D
public abstract fun decodeEnum (Lkotlinx/serialization/descriptors/SerialDescriptor;)I
public abstract fun decodeFloat ()F
public abstract fun decodeInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Decoder;
public abstract fun decodeInt ()I
public abstract fun decodeLong ()J
public abstract fun decodeNotNullMark ()Z
Expand Down Expand Up @@ -463,6 +476,7 @@ public abstract interface class kotlinx/serialization/encoding/Encoder {
public abstract fun encodeDouble (D)V
public abstract fun encodeEnum (Lkotlinx/serialization/descriptors/SerialDescriptor;I)V
public abstract fun encodeFloat (F)V
public abstract fun encodeInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Encoder;
public abstract fun encodeInt (I)V
public abstract fun encodeLong (J)V
public abstract fun encodeNotNullMark ()V
Expand Down Expand Up @@ -691,6 +705,13 @@ public final class kotlinx/serialization/internal/HashSetSerializer : kotlinx/se
public synthetic fun toResult (Ljava/lang/Object;)Ljava/lang/Object;
}

public final class kotlinx/serialization/internal/InlineClassDescriptor : kotlinx/serialization/internal/PluginGeneratedSerialDescriptor {
public fun <init> (Ljava/lang/String;Lkotlinx/serialization/internal/GeneratedSerializer;)V
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun isInline ()Z
}

public final class kotlinx/serialization/internal/IntArrayBuilder : kotlinx/serialization/internal/PrimitiveArrayBuilder {
public synthetic fun build$kotlinx_serialization_core ()Ljava/lang/Object;
}
Expand Down Expand Up @@ -878,6 +899,7 @@ public class kotlinx/serialization/internal/PluginGeneratedSerialDescriptor : ko
public fun getSerialNames ()Ljava/util/Set;
public fun hashCode ()I
public fun isElementOptional (I)Z
public fun isInline ()Z
public fun isNullable ()Z
public final fun pushAnnotation (Ljava/lang/annotation/Annotation;)V
public final fun pushClassAnnotation (Ljava/lang/annotation/Annotation;)V
Expand Down Expand Up @@ -975,6 +997,8 @@ public abstract class kotlinx/serialization/internal/TaggedDecoder : kotlinx/ser
public final fun decodeEnum (Lkotlinx/serialization/descriptors/SerialDescriptor;)I
public final fun decodeFloat ()F
public final fun decodeFloatElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)F
public final fun decodeInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Decoder;
public final fun decodeInlineElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/Decoder;
public final fun decodeInt ()I
public final fun decodeIntElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)I
public final fun decodeLong ()J
Expand All @@ -997,6 +1021,7 @@ public abstract class kotlinx/serialization/internal/TaggedDecoder : kotlinx/ser
protected fun decodeTaggedDouble (Ljava/lang/Object;)D
protected fun decodeTaggedEnum (Ljava/lang/Object;Lkotlinx/serialization/descriptors/SerialDescriptor;)I
protected fun decodeTaggedFloat (Ljava/lang/Object;)F
protected fun decodeTaggedInline (Ljava/lang/Object;Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Decoder;
protected fun decodeTaggedInt (Ljava/lang/Object;)I
protected fun decodeTaggedLong (Ljava/lang/Object;)J
protected fun decodeTaggedNotNullMark (Ljava/lang/Object;)Z
Expand Down Expand Up @@ -1028,6 +1053,8 @@ public abstract class kotlinx/serialization/internal/TaggedEncoder : kotlinx/ser
public final fun encodeEnum (Lkotlinx/serialization/descriptors/SerialDescriptor;I)V
public final fun encodeFloat (F)V
public final fun encodeFloatElement (Lkotlinx/serialization/descriptors/SerialDescriptor;IF)V
public final fun encodeInline (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Encoder;
public final fun encodeInlineElement (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Lkotlinx/serialization/encoding/Encoder;
public final fun encodeInt (I)V
public final fun encodeIntElement (Lkotlinx/serialization/descriptors/SerialDescriptor;II)V
public final fun encodeLong (J)V
Expand All @@ -1048,6 +1075,7 @@ public abstract class kotlinx/serialization/internal/TaggedEncoder : kotlinx/ser
protected fun encodeTaggedDouble (Ljava/lang/Object;D)V
protected fun encodeTaggedEnum (Ljava/lang/Object;Lkotlinx/serialization/descriptors/SerialDescriptor;I)V
protected fun encodeTaggedFloat (Ljava/lang/Object;F)V
protected fun encodeTaggedInline (Ljava/lang/Object;Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/Encoder;
protected fun encodeTaggedInt (Ljava/lang/Object;I)V
protected fun encodeTaggedLong (Ljava/lang/Object;J)V
protected fun encodeTaggedNull (Ljava/lang/Object;)V
Expand All @@ -1074,6 +1102,42 @@ public final class kotlinx/serialization/internal/TripleSerializer : kotlinx/ser
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lkotlin/Triple;)V
}

public final class kotlinx/serialization/internal/UByteSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lkotlinx/serialization/internal/UByteSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize-Wa3L5BU (Lkotlinx/serialization/encoding/Decoder;)B
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize-EK-6454 (Lkotlinx/serialization/encoding/Encoder;B)V
}

public final class kotlinx/serialization/internal/UIntSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lkotlinx/serialization/internal/UIntSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize-OGnWXxg (Lkotlinx/serialization/encoding/Decoder;)I
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize-Qn1smSk (Lkotlinx/serialization/encoding/Encoder;I)V
}

public final class kotlinx/serialization/internal/ULongSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lkotlinx/serialization/internal/ULongSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize-I7RO_PI (Lkotlinx/serialization/encoding/Decoder;)J
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize-2TYgG_w (Lkotlinx/serialization/encoding/Encoder;J)V
}

public final class kotlinx/serialization/internal/UShortSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lkotlinx/serialization/internal/UShortSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize-BwKQO78 (Lkotlinx/serialization/encoding/Decoder;)S
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize-i8woANY (Lkotlinx/serialization/encoding/Encoder;S)V
}

public final class kotlinx/serialization/internal/UnitSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lkotlinx/serialization/internal/UnitSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,30 @@ public fun <K, V> MapSerializer(
valueSerializer: KSerializer<V>
): KSerializer<Map<K, V>> = LinkedHashMapSerializer(keySerializer, valueSerializer)

/**
* Returns serializer for [UInt].
*/
@ExperimentalSerializationApi
@ExperimentalUnsignedTypes
public fun UInt.Companion.serializer(): KSerializer<UInt> = UIntSerializer

/**
* Returns serializer for [ULong].
*/
@ExperimentalSerializationApi
@ExperimentalUnsignedTypes
public fun ULong.Companion.serializer(): KSerializer<ULong> = ULongSerializer

/**
* Returns serializer for [UByte].
*/
@ExperimentalSerializationApi
@ExperimentalUnsignedTypes
public fun UByte.Companion.serializer(): KSerializer<UByte> = UByteSerializer

/**
* Returns serializer for [UShort].
*/
@ExperimentalSerializationApi
@ExperimentalUnsignedTypes
public fun UShort.Companion.serializer(): KSerializer<UShort> = UShortSerializer
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ public interface SerialDescriptor {
@ExperimentalSerializationApi
public val isNullable: Boolean get() = false

/**
* Returns `true` if this descriptor describes a serializable inline class.
*/
@ExperimentalSerializationApi
public val isInline: Boolean get() = false

/**
* The number of elements this descriptor describes, besides from the class itself.
* [elementsCount] describes the number of **semantic** elements, not the number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public abstract class AbstractDecoder : Decoder, CompositeDecoder {
override fun decodeString(): String = decodeValue() as String
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = decodeValue() as Int

override fun decodeInline(inlineDescriptor: SerialDescriptor): Decoder = this

// overwrite by default
public open fun <T : Any?> decodeSerializableValue(
deserializer: DeserializationStrategy<T>,
Expand All @@ -55,6 +57,11 @@ public abstract class AbstractDecoder : Decoder, CompositeDecoder {
final override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char = decodeChar()
final override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String = decodeString()

final override fun decodeInlineElement(
descriptor: SerialDescriptor,
index: Int
): Decoder = decodeInline(descriptor.getElementDescriptor(index))

final override fun <T> decodeSerializableElement(
descriptor: SerialDescriptor,
index: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package kotlinx.serialization.encoding
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.modules.*
import kotlinx.serialization.internal.*

/**
* A skeleton implementation of both [Encoder] and [CompositeEncoder] that can be used
Expand Down Expand Up @@ -50,6 +51,8 @@ public abstract class AbstractEncoder : Encoder, CompositeEncoder {
override fun encodeString(value: String): Unit = encodeValue(value)
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int): Unit = encodeValue(index)

override fun encodeInline(inlineDescriptor: SerialDescriptor): Encoder = this

// Delegating implementation of CompositeEncoder
final override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean) { if (encodeElement(descriptor, index)) encodeBoolean(value) }
final override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte) { if (encodeElement(descriptor, index)) encodeByte(value) }
Expand All @@ -61,6 +64,12 @@ public abstract class AbstractEncoder : Encoder, CompositeEncoder {
final override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char) { if (encodeElement(descriptor, index)) encodeChar(value) }
final override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String) { if (encodeElement(descriptor, index)) encodeString(value) }

final override fun encodeInlineElement(
descriptor: SerialDescriptor,
index: Int
): Encoder =
if (encodeElement(descriptor, index)) encodeInline(descriptor.getElementDescriptor(index)) else NoOpEncoder

final override fun <T : Any?> encodeSerializableElement(
descriptor: SerialDescriptor,
index: Int,
Expand Down
Loading

0 comments on commit ac54504

Please sign in to comment.