Skip to content

Commit

Permalink
feat: add function for changes encoder for formats. fix InlineEncoder…
Browse files Browse the repository at this point in the history
…. add tests for InlineEncoder
  • Loading branch information
EdmonDantes committed Aug 9, 2023
1 parent 0931531 commit e5de268
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 170 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2023. Ilia Loginov
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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 io.github.edmondantes.serialization

import io.github.edmondantes.serialization.decoding.CustomDeserializationStrategy
import io.github.edmondantes.serialization.encoding.CustomSerializationStrategy
import kotlinx.serialization.BinaryFormat
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

public class BinaryFormatDelegate(
private val delegate: BinaryFormat,
private val serializationModify: Encoder.() -> Encoder = { this },
private val deserializationModify: Decoder.() -> Decoder = { this },
) : BinaryFormat by delegate {

override fun <T> encodeToByteArray(serializer: SerializationStrategy<T>, value: T): ByteArray =
delegate.encodeToByteArray(CustomSerializationStrategy(serializer) { it.serializationModify() }, value)

override fun <T> decodeFromByteArray(deserializer: DeserializationStrategy<T>, bytes: ByteArray): T =
delegate.decodeFromByteArray(CustomDeserializationStrategy(deserializer) { it.deserializationModify() }, bytes)
}

public fun BinaryFormat.modifySerializer(block: Encoder.() -> Encoder): BinaryFormat =
BinaryFormatDelegate(this, serializationModify = block)

public fun BinaryFormat.modifyDeserializer(block: Decoder.() -> Decoder): BinaryFormat =
BinaryFormatDelegate(this, deserializationModify = block)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2023. Ilia Loginov
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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 io.github.edmondantes.serialization

import io.github.edmondantes.serialization.decoding.CustomDeserializationStrategy
import io.github.edmondantes.serialization.encoding.CustomSerializationStrategy
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.StringFormat
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

public class StringFormatDelegate(
private val delegate: StringFormat,
private val serializationModify: Encoder.() -> Encoder = { this },
private val deserializationModify: Decoder.() -> Decoder = { this },
) : StringFormat by delegate {

override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String =
delegate.encodeToString(CustomSerializationStrategy(serializer) { it.serializationModify() }, value)

override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T =
delegate.decodeFromString(CustomDeserializationStrategy(deserializer) { it.deserializationModify() }, string)
}

public fun StringFormat.modifySerializer(block: Encoder.() -> Encoder): StringFormat =
StringFormatDelegate(this, serializationModify = block)

public fun StringFormat.modifyDeserializer(block: Decoder.() -> Decoder): StringFormat =
StringFormatDelegate(this, deserializationModify = block)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2023. Ilia Loginov
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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 io.github.edmondantes.serialization.decoding

import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.encoding.Decoder

public class CustomDeserializationStrategy<T>(
private val delegate: DeserializationStrategy<T>,
private val decoderTransformer: (Decoder) -> Decoder,
) : DeserializationStrategy<T> by delegate {

override fun deserialize(decoder: Decoder): T =
delegate.deserialize(decoderTransformer(decoder))
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ public class BroadcastEncoder(private val encoders: List<Encoder>) : Encoder {
},
)

// TODO: Remove this in future release
public fun supportInline(): BroadcastEncoder =
BroadcastEncoder(encoders.map { it.supportInline() })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,32 @@ public open class DefaultStructureEncodingElementBuilder(
}
}

override fun switch(
descriptor: SerialDescriptor,
block: StructureEncodingElementBuilder.() -> Unit,
): StructureEncodingElementBuilder {
DefaultStructureEncodingElementBuilder(descriptor, null, null, null).apply(block).builder.value.also {
if (builder.value == null) {
builder.value = it
} else if (it != null) {
builder.value?.addAll(it)
}
}
return this
}

override fun build(): StructureEncodingElement =
builder.build()

private fun <T> childPrepare(name: String, block: (SerialDescriptor?, Int) -> T): T {
val index = descriptor.getElementIndex(name)
return block(if (descriptor.kind is PrimitiveKind) null else descriptor.getElementDescriptor(index), index)
private fun <T> childPrepare(
name: String,
block: (SerialDescriptor?, Int) -> T,
): T {
val currDescriptor = childDescriptor ?: descriptor
val index = currDescriptor.getElementIndex(name)
return block(
if (currDescriptor.kind is PrimitiveKind) null else currDescriptor.getElementDescriptor(index),
index,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public interface StructureEncodingElementBuilder {
block: ElementFactory.() -> EncodingElement<*>,
): StructureEncodingElementBuilder

public fun switch(
descriptor: SerialDescriptor,
block: StructureEncodingElementBuilder.() -> Unit,
): StructureEncodingElementBuilder

public fun build(): StructureEncodingElement
}

Expand All @@ -54,6 +59,9 @@ public fun StructureEncodingElementBuilder.element(name: String, value: Any?): S
element(name = name).value(value)
}

public inline fun <reified T> StructureEncodingElementBuilder.switch(noinline block: StructureEncodingElementBuilder.() -> Unit): StructureEncodingElementBuilder =
switch(serialDescriptor<T>(), block)

@JvmName("elementWithType")
public inline fun <reified T> StructureEncodingElementBuilder.element(
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ import io.github.edmondantes.serialization.getElementAllAnnotation
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Encoder

//FIXME: rewrite
public class InlineCompositeEncoder(
private val delegate: CompositeEncoder,
private val inlineEncoder: InlineEncoder,
private val endStructureHandler: () -> Boolean,
private val encoderDelegate: Encoder,
) : CompositeEncoder by delegate {

override fun <T : Any?> encodeSerializableElement(
Expand All @@ -37,12 +36,12 @@ public class InlineCompositeEncoder(
val isInline = descriptor.getElementAllAnnotation(index).filterIsInstance<InlineSerialization>().isNotEmpty()

if (isInline) {
serializer.serialize(inlineEncoder, value)
serializer.serialize(InlineEncoder(encoderDelegate, this, true), value)
return
}

val inlineEncodingStrategy = CustomSerializationStrategy(serializer) {
inlineEncoder.changeEncoder(it, isInline)
InlineEncoder(it, this)
}

delegate.encodeSerializableElement(
Expand All @@ -53,9 +52,7 @@ public class InlineCompositeEncoder(
)
}

override fun endStructure(descriptor: SerialDescriptor) {
if (endStructureHandler()) {
delegate.endStructure(descriptor)
}
override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String) {
delegate.encodeStringElement(descriptor, index, value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,52 +20,24 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Encoder

//FIXME: rewrite
public class InlineEncoder(
private val delegate: Encoder,
private val compositeEncoderQueue: ArrayDeque<CompositeEncoder> = ArrayDeque(),
private var inline: Int = 0,
private val parentCompositeEncoder: InlineCompositeEncoder? = null,
private val isInline: Boolean = false,
) : Encoder by delegate {

private var nextIsInline: Boolean = false

@OptIn(ExperimentalSerializationApi::class)
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder =
if (nextIsInline || descriptor.annotations.filterIsInstance<InlineSerialization>().isNotEmpty()) {
nextIsInline = false
inline++
compositeEncoderQueue.last()
if ((descriptor.annotations.filterIsInstance<InlineSerialization>().isNotEmpty() || isInline) &&
parentCompositeEncoder != null
) {
parentCompositeEncoder
} else {
InlineCompositeEncoder(
delegate.beginStructure(descriptor),
this,
::endStructure,
).also(compositeEncoderQueue::addLast)
}

public fun changeEncoder(delegate: Encoder, isInline: Boolean = false): InlineEncoder =
if (this.delegate === delegate) {
this
} else {
InlineEncoder(delegate, compositeEncoderQueue, inline).also {
if (isInline) {
inline++
}
}
}.also {
it.nextIsInline = isInline
)
}

private fun endStructure(): Boolean {
if (inline == 0) {
compositeEncoderQueue.removeLast()
return true
} else {
inline--
}

return false
}
}

public fun Encoder.supportInline(): InlineEncoder = InlineEncoder(this)
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import io.github.edmondantes.serialization.encoding.BroadcastEncoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.serializer

public inline fun <reified T> T.serialize(vararg encoders: Encoder, block: BroadcastEncoder.() -> Encoder = { this }) {
serializer<T>().serialize(if (encoders.size == 1) encoders[0] else BroadcastEncoder(*encoders).block(), this)
public inline fun <reified T> T.serialize(vararg encoders: Encoder, block: Encoder.() -> Encoder = { this }) {
serializer<T>().serialize(if (encoders.size == 1) encoders[0].block() else BroadcastEncoder(encoders.map(block)), this)
}

public inline fun <reified T> T.serialize(encoders: List<Encoder>, block: BroadcastEncoder.() -> Encoder = { this }) {
serializer<T>().serialize(if (encoders.size == 1) encoders[0] else BroadcastEncoder(encoders).block(), this)
public inline fun <reified T> T.serialize(encoders: List<Encoder>, block: Encoder.() -> Encoder = { this }) {
serializer<T>().serialize(if (encoders.size == 1) encoders[0].block() else BroadcastEncoder(encoders.map(block)), this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.github.edmondantes.entity.TestDataCircleEntity
import io.github.edmondantes.serialization.encoding.element.ElementEncoder
import io.github.edmondantes.serialization.encoding.element.factory.element
import io.github.edmondantes.serialization.encoding.element.factory.structureElement
import io.github.edmondantes.serialization.encoding.supportCircular
import io.github.edmondantes.util.assertEquals
import io.github.edmondantes.util.serializeWithLog
import kotlin.test.Test
Expand Down

0 comments on commit e5de268

Please sign in to comment.