mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 00:30:17 +08:00
Setting serializers
This commit is contained in:
parent
1f0b7e4f01
commit
cbcb5aaccd
@ -11,15 +11,20 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.setting
|
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.cast
|
||||||
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
|
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
|
||||||
import net.mamoe.mirai.console.setting.internal.valueImpl
|
import net.mamoe.mirai.console.setting.internal.valueImpl
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import net.mamoe.yamlkt.Yaml
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.internal.LowPriorityInOverloadResolution
|
import kotlin.internal.LowPriorityInOverloadResolution
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.full.findAnnotation
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
|
|
||||||
@ -32,11 +37,15 @@ abstract class Setting : SettingImpl() {
|
|||||||
property: KProperty<*>
|
property: KProperty<*>
|
||||||
): SerializerAwareValue<T> {
|
): SerializerAwareValue<T> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
valueNodes.add(Node(property as KProperty<T>, this, this.serializer))
|
valueNodes.add(Node(property.serialName, this, this.serializer))
|
||||||
return this
|
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:
|
* Internal implementation for [Setting] including:
|
||||||
* - Reflection on Kotlin properties and Java fields
|
* - Reflection on Kotlin properties and Java fields
|
||||||
@ -44,14 +53,91 @@ abstract class Setting : SettingImpl() {
|
|||||||
*/
|
*/
|
||||||
// TODO move to internal package.
|
// TODO move to internal package.
|
||||||
internal abstract class SettingImpl {
|
internal abstract class SettingImpl {
|
||||||
|
internal fun findNodeInstance(name: String): Node<*>? = valueNodes.firstOrNull { it.serialName == name }
|
||||||
|
|
||||||
internal class Node<T>(
|
internal class Node<T>(
|
||||||
val property: KProperty<T>,
|
val serialName: String,
|
||||||
val value: Value<T>,
|
val value: Value<T>,
|
||||||
val updaterSerializer: KSerializer<Unit>
|
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 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
|
* flatten
|
||||||
*/
|
*/
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.setting
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
|
import kotlinx.serialization.BinaryFormat
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.StringFormat
|
||||||
import net.mamoe.mirai.console.setting.internal.map
|
import net.mamoe.mirai.console.setting.internal.map
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
@ -54,6 +56,14 @@ interface SerializerAwareValue<T> : Value<T> {
|
|||||||
val serializer: KSerializer<Unit>
|
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>.getValue(mySetting: Any?, property: KProperty<*>): T = value
|
||||||
inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
|
inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
|
||||||
this.value = value
|
this.value = value
|
||||||
|
Loading…
Reference in New Issue
Block a user