Skip to content

Commit

Permalink
Add encoding value classes
Browse files Browse the repository at this point in the history
  • Loading branch information
BOOMeranGG committed Aug 27, 2023
1 parent 873ce99 commit 75c562a
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.AbstractEncoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule

/**
Expand Down Expand Up @@ -104,6 +105,12 @@ public abstract class TomlAbstractEncoder protected constructor(
appendValue(TomlNull())
}

override fun encodeInline(descriptor: SerialDescriptor): Encoder {
// Value (inline) class always has one element
encodeElement(descriptor, 0)
return this
}

override fun encodeString(value: String) {
if (!encodeAsKey(value)) {
appendValue(
Expand All @@ -126,7 +133,9 @@ public abstract class TomlAbstractEncoder protected constructor(
}
else -> when (val kind = desc.kind) {
is StructureKind,
is PolymorphicKind -> if (!encodeAsKey(value as Any, desc.serialName)) {
is PolymorphicKind -> if (desc.isInline) {
serializer.serialize(this, value)
} else if (!encodeAsKey(value as Any, desc.serialName)) {
val encoder = encodeStructure(kind)

serializer.serialize(encoder, value)
Expand Down Expand Up @@ -204,7 +213,15 @@ public abstract class TomlAbstractEncoder protected constructor(

protected open fun isNextElementKey(descriptor: SerialDescriptor, index: Int): Boolean {
when (val kind = descriptor.kind) {
StructureKind.CLASS -> setKey(descriptor.getElementName(index))
StructureKind.CLASS -> {
// We should keep previous key when we have value (inline) class
// But if key is null, it means that value class isn't nested, and we have to use its own key
if (descriptor.isInline && attributes.key != null) {
// do nothing
} else {
setKey(descriptor.getElementName(index))
}
}
StructureKind.MAP -> {
// When the index is even (key) mark the next element as a key and
// skip annotations and element index incrementing.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package com.akuleshov7.ktoml.encoders

import com.akuleshov7.ktoml.Toml
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlin.jvm.JvmInline
import kotlin.test.Test
import kotlin.test.assertEquals

class ValueClassEncoderTest {

@Serializable
@JvmInline
value class Color(val rgb: Int)

@Serializable
data class NamedColor(val color: Color, val name: String)

@Test
fun testForSimpleValueClass() {
val color = Color(15)
val result = Toml.encodeToString(color)

assertEquals("rgb = 15", result)
}

@Test
fun testForNestedValueClass() {
val namedColor = NamedColor(
Color(150),
"black"
)

val result = Toml.encodeToString(namedColor)
assertEquals(
"""
color = 150
name = "black"
""".trimIndent(),
result
)
}

@Test
fun testForLisOfValueClass() {
@Serializable
class Palette(val colors: List<Color>)
val palette = Palette(
listOf(
Color(0),
Color(255),
Color(128),
)
)

val result = Toml.encodeToString(palette)
assertEquals("colors = [ 0, 255, 128 ]", result)
}

@Serializable
@JvmInline
value class Num(val int: Int)

@Serializable
data class Nums(
val num1: Num,
val num2: Num,
)

@Test
fun testForMultipleValueClass() {
val nums = Nums(
num1 = Num(5),
num2 = Num(111)
)
val result = Toml.encodeToString(nums)

assertEquals(
"""
num1 = 5
num2 = 111
""".trimIndent(),
result
)
}

@Serializable
data class MyObject(
val height: Int,
val width: Int
)

@Serializable
@JvmInline
value class Info(val obj: MyObject)

@Serializable
data class InfoWrapper(
val metaInfo1: Int,
val info: Info,
val metaInfo2: String
)

@Test
fun testForValueClassWithObjectInside() {
val obj = InfoWrapper(
metaInfo1 = 1,
info = Info(MyObject(10, 20)),
metaInfo2 = "test"
)
val result = Toml.encodeToString(obj)

assertEquals(
"""
metaInfo1 = 1
metaInfo2 = "test"
[info]
height = 10
width = 20
""".trimIndent(),
result
)
}

@Serializable
@JvmInline
value class AnotherInfoWrapper(val info: Info)

@Test
fun testForValueClassInsideValueClass() {
val obj = AnotherInfoWrapper(Info(MyObject(10, 20)))
val result = Toml.encodeToString(obj)

assertEquals(
"""
[info]
height = 10
width = 20
""".trimIndent(),
result
)
}

@Test
fun testDataClassInsideValueClass() {
val obj = Info(MyObject(32, 64))
val result = Toml.encodeToString(obj)

assertEquals(
"""
[obj]
height = 32
width = 64
""".trimIndent(),
result
)
}
}

0 comments on commit 75c562a

Please sign in to comment.