Skip to content

Instantly share code, notes, and snippets.

@pdvrieze
Last active June 5, 2024 09:08
Show Gist options
  • Save pdvrieze/0eb34ab2f914383a4d98cfc414272ac7 to your computer and use it in GitHub Desktop.
Save pdvrieze/0eb34ab2f914383a4d98cfc414272ac7 to your computer and use it in GitHub Desktop.
Example code for a delegating format.
/*
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
* This file is licenced to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You should have received a copy of the license with the source distribution.
* Alternatively, you may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package nl.adaptivity.serialutil
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.StringFormat
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule
abstract class DelegatingStringFormat(private val delegateFormat: StringFormat) : StringFormat {
abstract fun <T> determineEffectiveSerializer(serializer: SerializationStrategy<T>): SerializationStrategy<T>
abstract fun <T> determineEffectiveDeserializer(deserializer: DeserializationStrategy<T>): DeserializationStrategy<T>
override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String {
return delegateFormat.encodeToString(WrappingSerializationStrategy(serializer), value)
}
override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T {
return decodeFromString(WrappingDeserializationStrategy(deserializer), string)
}
private inner class WrappingSerializationStrategy<T>(val delegate: SerializationStrategy<T>) : SerializationStrategy<T> {
override val descriptor: SerialDescriptor
get() = delegate.descriptor
override fun serialize(encoder: Encoder, value: T) {
val wrappedEncoder: Encoder = WrappedEncoder(encoder)
delegate.serialize(wrappedEncoder, value)
}
}
private inner class WrappingDeserializationStrategy<T>(val delegate: DeserializationStrategy<T>) : DeserializationStrategy<T> {
override val descriptor: SerialDescriptor
get() = delegate.descriptor
override fun deserialize(decoder: Decoder): T {
val wrappedDecoder: Decoder = WrappedDecoder(decoder)
return delegate.deserialize(wrappedDecoder)
}
}
private inner class WrappedEncoder(val encoder: Encoder): Encoder {
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
val effectiveSerializer = determineEffectiveSerializer(serializer)
encoder.encodeSerializableValue(effectiveSerializer, value)
}
@ExperimentalSerializationApi
override fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) {
val effectiveSerializer = determineEffectiveSerializer(serializer)
encoder.encodeNullableSerializableValue(effectiveSerializer, value)
}
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
// Make sure to retain the "wrapping"
return WrappedCompositeEncoder(encoder.beginStructure(descriptor))
}
override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder {
// Overridden to ensure beginCollection on the delegate is called
// Make sure to retain the "wrapping"
return WrappedCompositeEncoder(encoder.beginCollection(descriptor, collectionSize))
}
override val serializersModule: SerializersModule get() = encoder.serializersModule
override fun encodeBoolean(value: Boolean) = encoder.encodeBoolean(value)
override fun encodeByte(value: Byte) = encoder.encodeByte(value)
override fun encodeChar(value: Char) = encoder.encodeChar(value)
override fun encodeDouble(value: Double) = encoder.encodeDouble(value)
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = encoder.encodeEnum(enumDescriptor, index)
override fun encodeFloat(value: Float) = encoder.encodeFloat(value)
override fun encodeInline(descriptor: SerialDescriptor): Encoder = encoder.encodeInline(descriptor)
override fun encodeInt(value: Int) = encoder.encodeInt(value)
override fun encodeLong(value: Long) = encoder.encodeLong(value)
override fun encodeShort(value: Short) = encoder.encodeShort(value)
override fun encodeString(value: String) = encoder.encodeString(value)
@ExperimentalSerializationApi
override fun encodeNotNullMark() = encoder.encodeNotNullMark()
@ExperimentalSerializationApi
override fun encodeNull() = encoder.encodeNull()
}
private inner class WrappedCompositeEncoder(val encoder: CompositeEncoder): CompositeEncoder {
@ExperimentalSerializationApi
override fun <T : Any> encodeNullableSerializableElement(
descriptor: SerialDescriptor,
index: Int,
serializer: SerializationStrategy<T>,
value: T?
) {
val effectiveSerializer = determineEffectiveSerializer(serializer)
encoder.encodeNullableSerializableElement(descriptor, index, effectiveSerializer, value)
}
override fun <T> encodeSerializableElement(
descriptor: SerialDescriptor,
index: Int,
serializer: SerializationStrategy<T>,
value: T
) {
val effectiveSerializer = determineEffectiveSerializer(serializer)
encoder.encodeSerializableElement(descriptor, index, effectiveSerializer, value)
}
override fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder {
return WrappedEncoder(encoder.encodeInlineElement(descriptor, index))
}
override val serializersModule: SerializersModule get() = encoder.serializersModule
@ExperimentalSerializationApi
override fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean {
return encoder.shouldEncodeElementDefault(descriptor, index)
}
override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean) {
encoder.encodeBooleanElement(descriptor, index, value)
}
override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte) {
encoder.encodeByteElement(descriptor, index, value)
}
override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char) {
encoder.encodeCharElement(descriptor, index, value)
}
override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double) {
encoder.encodeDoubleElement(descriptor, index, value)
}
override fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float) {
encoder.encodeFloatElement(descriptor, index, value)
}
override fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int) {
encoder.encodeIntElement(descriptor, index, value)
}
override fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long) {
encoder.encodeLongElement(descriptor, index, value)
}
override fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short) {
encoder.encodeShortElement(descriptor, index, value)
}
override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String) {
encoder.encodeStringElement(descriptor, index, value)
}
override fun endStructure(descriptor: SerialDescriptor) {
encoder.endStructure(descriptor)
}
}
private inner class WrappedDecoder(val decoder: Decoder) : Decoder {
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
return WrappedCompositeDecoder(beginStructure(descriptor))
}
@ExperimentalSerializationApi
override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? {
val effectiveDeserializer = determineEffectiveDeserializer(deserializer)
return super.decodeNullableSerializableValue(effectiveDeserializer)
}
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
val effectiveDeserializer = determineEffectiveDeserializer(deserializer)
return super.decodeSerializableValue(effectiveDeserializer)
}
override val serializersModule: SerializersModule get() = decoder.serializersModule
override fun decodeBoolean(): Boolean = decoder.decodeBoolean()
override fun decodeByte(): Byte =decoder.decodeByte()
override fun decodeChar(): Char =decoder.decodeChar()
override fun decodeDouble(): Double =decoder.decodeDouble()
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int =decoder.decodeEnum(enumDescriptor)
override fun decodeFloat(): Float =decoder.decodeFloat()
override fun decodeInline(descriptor: SerialDescriptor): Decoder =decoder.decodeInline(descriptor)
override fun decodeInt(): Int =decoder.decodeInt()
override fun decodeLong(): Long =decoder.decodeLong()
override fun decodeShort(): Short =decoder.decodeShort()
override fun decodeString(): String =decoder.decodeString()
@ExperimentalSerializationApi
override fun decodeNotNullMark(): Boolean =decoder.decodeNotNullMark()
@ExperimentalSerializationApi
override fun decodeNull(): Nothing? =decoder.decodeNull()
}
private inner class WrappedCompositeDecoder(val decoder: CompositeDecoder): CompositeDecoder {
@ExperimentalSerializationApi
override fun <T : Any> decodeNullableSerializableElement(
descriptor: SerialDescriptor,
index: Int,
deserializer: DeserializationStrategy<T?>,
previousValue: T?
): T? {
val effectiveDeserializer = determineEffectiveDeserializer(deserializer)
return decoder.decodeNullableSerializableElement(descriptor, index, effectiveDeserializer, previousValue)
}
override fun <T> decodeSerializableElement(
descriptor: SerialDescriptor,
index: Int,
deserializer: DeserializationStrategy<T>,
previousValue: T?
): T {
val effectiveDeserializer = determineEffectiveDeserializer(deserializer)
return decoder.decodeSerializableElement(descriptor, index, effectiveDeserializer, previousValue)
}
override val serializersModule: SerializersModule get() = decoder.serializersModule
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
return decoder.decodeCollectionSize(descriptor)
}
@ExperimentalSerializationApi
override fun decodeSequentially(): Boolean {
return decoder.decodeSequentially()
}
override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean {
return decoder.decodeBooleanElement(descriptor, index)
}
override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte {
return decoder.decodeByteElement(descriptor, index)
}
override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char {
return decoder.decodeCharElement(descriptor, index)
}
override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double {
return decoder.decodeDoubleElement(descriptor, index)
}
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
return decoder.decodeElementIndex(descriptor)
}
override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float {
return decoder.decodeFloatElement(descriptor, index)
}
override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder {
return WrappedDecoder(decoder.decodeInlineElement(descriptor, index))
}
override fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int {
return decoder.decodeIntElement(descriptor, index)
}
override fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long {
return decoder.decodeLongElement(descriptor, index)
}
override fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short {
return decoder.decodeShortElement(descriptor, index)
}
override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String {
return decoder.decodeStringElement(descriptor, index)
}
override fun endStructure(descriptor: SerialDescriptor) {
return decoder.endStructure(descriptor)
}
}
}
@Laxystem
Copy link

Laxystem commented Jun 5, 2024

I intentionally didn't use delegates as they have some design issues.

May I ask what design issues?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment