Skip to content

Instantly share code, notes, and snippets.

@Laxystem
Created June 4, 2024 17:37
Show Gist options
  • Save Laxystem/9b82754ca5e82cc8f1659b5ae1870c3c to your computer and use it in GitHub Desktop.
Save Laxystem/9b82754ca5e82cc8f1659b5ae1870c3c to your computer and use it in GitHub Desktop.
Delegating StringFormat for KotlinX Serialization

Delegating StringFormat for KotlinX Serialization

An Example of Usage

public abstract class DelegatingFormat(
    private val delegateFormat: StringFormat,
    private val deserializerDelegator: DeserializerDelegator,
    private val serializerDelegator: SerializerDelegator
) : StringFormat by delegateFormat {
    override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T =
        delegateFormat.decodeFromString(deserializerDelegator.wrap(deserializer), string)

    override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String =
        delegateFormat.encodeToString(serializerDelegator.wrap(serializer), value)
}

Licensing

The original gist is licensed under the Apache License, Version 2.0. The modifications made by Laxystem are licensed under the Mozilla Public License 2.0, with approval from the original creator, Paul de Vrieze.

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package quest.laxla.khuzdul
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
/**
* @author @pdvrieze@github.com
* @author @Laxystem@codeberg.org
*/
public interface DeserializerDelegator {
@InternalSerializationApi
public fun <T> determineEffectiveDeserializer(deserializer: DeserializationStrategy<T>): DeserializationStrategy<T>
public companion object {
public fun <T> DeserializerDelegator.wrap(deserializer: DeserializationStrategy<T>): DeserializationStrategy<T> =
WrappingStrategy(delegate = deserializer, delegator = this)
}
private class WrappingStrategy<T>(
val delegate: DeserializationStrategy<T>,
val delegator: DeserializerDelegator
) : DeserializationStrategy<T> {
override val descriptor: SerialDescriptor
get() = delegate.descriptor
override fun deserialize(decoder: Decoder): T {
return delegate.deserialize(WrappedDecoder(decoder, delegator))
}
}
private class WrappedDecoder(val delegate: Decoder, val delegator: DeserializerDelegator) : Decoder by delegate {
@OptIn(InternalSerializationApi::class)
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T =
super.decodeSerializableValue(delegator.determineEffectiveDeserializer(deserializer))
@OptIn(InternalSerializationApi::class)
@ExperimentalSerializationApi
override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? =
super.decodeNullableSerializableValue(delegator.determineEffectiveDeserializer(deserializer))
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
WrappedCompositeDecoder(delegate.beginStructure(descriptor), delegator)
}
private class WrappedCompositeDecoder(
val delegate: CompositeDecoder,
val delegator: DeserializerDelegator
) : CompositeDecoder by delegate {
@OptIn(InternalSerializationApi::class)
override fun <T> decodeSerializableElement(
descriptor: SerialDescriptor,
index: Int,
deserializer: DeserializationStrategy<T>,
previousValue: T?
): T = delegate.decodeSerializableElement(
descriptor = descriptor,
index = index,
deserializer = delegator.determineEffectiveDeserializer(deserializer),
previousValue = previousValue
)
@OptIn(InternalSerializationApi::class)
@ExperimentalSerializationApi
override fun <T : Any> decodeNullableSerializableElement(
descriptor: SerialDescriptor,
index: Int,
deserializer: DeserializationStrategy<T?>,
previousValue: T?
): T? = delegate.decodeNullableSerializableElement(
descriptor = descriptor,
index = index,
deserializer = delegator.determineEffectiveDeserializer(deserializer),
previousValue = previousValue
)
override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder =
WrappedDecoder(delegate.decodeInlineElement(descriptor, index), delegator)
}
}
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package quest.laxla.khuzdul
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Encoder
/**
* @author @pdvrieze@github.com
* @author @Laxystem@codeberg.org
*/
public interface SerializerDelegator {
@InternalSerializationApi
public fun <T> determineEffectiveSerializer(serializer: SerializationStrategy<T>): SerializationStrategy<T>
public companion object {
public fun <T> SerializerDelegator.wrap(serializer: SerializationStrategy<T>): SerializationStrategy<T> =
WrappingStrategy(delegate = serializer, delegator = this)
}
private class WrappingStrategy<T>(
val delegate: SerializationStrategy<T>,
val delegator: SerializerDelegator
) : SerializationStrategy<T> {
override val descriptor: SerialDescriptor
get() = delegate.descriptor
override fun serialize(encoder: Encoder, value: T) {
delegate.serialize(WrappedEncoder(encoder, delegator), value)
}
}
private class WrappedEncoder(val delegate: Encoder, val delegator: SerializerDelegator) : Encoder by delegate {
@OptIn(InternalSerializationApi::class)
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) =
delegate.encodeSerializableValue(delegator.determineEffectiveSerializer(serializer), value)
@OptIn(InternalSerializationApi::class)
@ExperimentalSerializationApi
override fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) =
delegate.encodeNullableSerializableValue(delegator.determineEffectiveSerializer(serializer), value)
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder =
WrappedCompositeEncoder(delegate.beginStructure(descriptor), delegator)
override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder =
WrappedCompositeEncoder(delegate.beginCollection(descriptor, collectionSize), delegator)
}
private class WrappedCompositeEncoder(
val delegate: CompositeEncoder,
val delegator: SerializerDelegator
) : CompositeEncoder by delegate {
@OptIn(InternalSerializationApi::class)
override fun <T> encodeSerializableElement(
descriptor: SerialDescriptor,
index: Int,
serializer: SerializationStrategy<T>,
value: T
) = delegate.encodeSerializableElement(
descriptor = descriptor,
index = index,
serializer = delegator.determineEffectiveSerializer(serializer),
value = value
)
@OptIn(InternalSerializationApi::class)
@ExperimentalSerializationApi
override fun <T : Any> encodeNullableSerializableElement(
descriptor: SerialDescriptor,
index: Int,
serializer: SerializationStrategy<T>,
value: T?
) = delegate.encodeNullableSerializableElement(
descriptor = descriptor,
index = index,
serializer = delegator.determineEffectiveSerializer(serializer),
value = value
)
override fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder =
WrappedEncoder(delegate.encodeInlineElement(descriptor, index), delegator)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment