Setting serializers

This commit is contained in:
Him188 2020-06-22 15:37:24 +08:00
parent 1f0b7e4f01
commit cbcb5aaccd
2 changed files with 99 additions and 3 deletions

View File

@ -11,15 +11,20 @@
package net.mamoe.mirai.console.setting
import kotlinx.serialization.KSerializer
import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.MapEntrySerializer
import kotlinx.serialization.builtins.serializer
import net.mamoe.mirai.console.setting.internal.cast
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
import net.mamoe.mirai.console.setting.internal.valueImpl
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.yamlkt.Yaml
import java.util.*
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.typeOf
@ -32,11 +37,15 @@ abstract class Setting : SettingImpl() {
property: KProperty<*>
): SerializerAwareValue<T> {
@Suppress("UNCHECKED_CAST")
valueNodes.add(Node(property as KProperty<T>, this, this.serializer))
valueNodes.add(Node(property.serialName, this, this.serializer))
return this
}
public override val updaterSerializer: KSerializer<Unit> get() = super.updaterSerializer
}
internal val KProperty<*>.serialName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
/**
* Internal implementation for [Setting] including:
* - Reflection on Kotlin properties and Java fields
@ -44,14 +53,91 @@ abstract class Setting : SettingImpl() {
*/
// TODO move to internal package.
internal abstract class SettingImpl {
internal fun findNodeInstance(name: String): Node<*>? = valueNodes.firstOrNull { it.serialName == name }
internal class Node<T>(
val property: KProperty<T>,
val serialName: String,
val value: Value<T>,
val updaterSerializer: KSerializer<Unit>
)
/**
* Serializing like a [Map.Entry] but with higher performance
*/
internal inner class NodeSerializer : KSerializer<Node<*>?> {
override val descriptor: SerialDescriptor
get() = MapEntrySerializer(String.serializer(), String.serializer()).descriptor
private val keySerializer = String.serializer()
private val valueSerializer = String.serializer()
override fun deserialize(decoder: Decoder): Node<*>? =
with(decoder.beginStructure(descriptor, keySerializer, valueSerializer)) {
if (decodeSequentially()) {
val name = decodeStringElement(descriptor, 0)
val value = decodeStringElement(descriptor, 1)
val node = findNodeInstance(name) ?: return@with null
Yaml.nonStrict.parse(node.updaterSerializer, value)
return@with node
}
var name: String? = null
var value: String? = null
loop@ while (true) {
when (decodeElementIndex(descriptor)) {
0 -> name = decodeStringElement(descriptor, 0)
1 -> value = decodeStringElement(descriptor, 1)
CompositeDecoder.READ_DONE -> break@loop
}
}
requireNotNull(name) { throw MissingFieldException("name") }
requireNotNull(value) { throw MissingFieldException("value") }
endStructure(descriptor)
val node = findNodeInstance(name) ?: return@with null
Yaml.nonStrict.parse(node.updaterSerializer, value)
return@with node
}
override fun serialize(encoder: Encoder, value: Node<*>?) {
if (value == null) {
encoder.encodeNull()
} else {
val structuredEncoder = encoder.beginStructure(descriptor, keySerializer, valueSerializer)
structuredEncoder.encodeStringElement(descriptor, 0, value.serialName)
structuredEncoder.encodeStringElement(
descriptor, 1,
Yaml.nonStrict.stringify(value.updaterSerializer, Unit)
)
structuredEncoder.endStructure(descriptor)
}
}
}
internal val valueNodes: MutableList<Node<*>> = Collections.synchronizedList(mutableListOf())
internal open val updaterSerializer: KSerializer<Unit> by lazy {
val actual = ListSerializer(NodeSerializer())
object : KSerializer<Unit> {
override val descriptor: SerialDescriptor
get() = actual.descriptor
override fun deserialize(decoder: Decoder) {
actual.deserialize(decoder)
}
override fun serialize(encoder: Encoder, value: Unit) {
actual.serialize(encoder, valueNodes)
}
}
}
/**
* flatten
*/

View File

@ -11,7 +11,9 @@
package net.mamoe.mirai.console.setting
import kotlinx.serialization.BinaryFormat
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
import net.mamoe.mirai.console.setting.internal.map
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import kotlin.reflect.KProperty
@ -54,6 +56,14 @@ interface SerializerAwareValue<T> : Value<T> {
val serializer: KSerializer<Unit>
}
fun <T> SerializerAwareValue<T>.serialize(format: StringFormat): String {
return format.stringify(this.serializer, Unit)
}
fun <T> SerializerAwareValue<T>.serialize(format: BinaryFormat): ByteArray {
return format.dump(this.serializer, Unit)
}
inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value
inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
this.value = value