diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt index 4d75b33d2..7139245b0 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt @@ -6,8 +6,7 @@ * * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("ClassName") - +@file:Suppress("ClassName", "unused") package net.mamoe.mirai.console.codegen import org.intellij.lang.annotations.Language @@ -196,4 +195,45 @@ sealed class Value : ReadWriteProperty { } appendln() + + // FOR COMPLEX TYPES + + appendln( + """ + abstract class SettingValue internal constructor() : Value() + + internal fun Setting.valueImpl(default: T): Value { + return object : SettingValue() { + private var internalValue: T = default + override var value: T + get() = internalValue + set(new) { + if (new != internalValue) { + internalValue = new + onElementChanged(this) + } + } + override val serializer = object : KSerializer{ + override val descriptor: SerialDescriptor + get() = internalValue.updaterSerializer.descriptor + + override fun deserialize(decoder: Decoder): T { + internalValue.updaterSerializer.deserialize(decoder) + return internalValue + } + + override fun serialize(encoder: Encoder, value: T) { + internalValue.updaterSerializer.serialize(encoder, SettingSerializerMark) + } + + }.bind( + getter = { internalValue }, + setter = { internalValue = it } + ) + } + } + """ + ) + + appendln() } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index 121fa563f..c03ff53e9 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -13,6 +13,9 @@ package net.mamoe.mirai.console.setting import kotlinx.serialization.* import net.mamoe.yamlkt.Yaml +import net.mamoe.yamlkt.YamlConfiguration +import net.mamoe.yamlkt.YamlConfiguration.ListSerialization.FLOW_SEQUENCE +import net.mamoe.yamlkt.YamlConfiguration.MapSerialization.FLOW_MAP import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlin.reflect.full.findAnnotation @@ -57,17 +60,44 @@ abstract class Setting { internal var valueList: MutableList, KProperty<*>>> = mutableListOf() private var built: Boolean = false - internal val serializer: KSerializer by lazy { + internal val updaterSerializer: KSerializer by lazy { built = true - SettingSerializer(this) + SettingUpdaterSerializer(this) + } + + internal val kotlinSerializer: KSerializer by lazy { + object : KSerializer { + override val descriptor: SerialDescriptor + get() = this@Setting.updaterSerializer.descriptor + + override fun deserialize(decoder: Decoder): Setting { + this@Setting.updaterSerializer.deserialize(decoder) + return this@Setting + } + + override fun serialize(encoder: Encoder, value: Setting) { + this@Setting.updaterSerializer.serialize(encoder, SettingSerializerMark) + } + } } internal fun onElementChanged(value: Value<*>) { println("my value changed!") } + + companion object { + private val yaml = + Yaml(configuration = YamlConfiguration(classSerialization = FLOW_MAP, listSerialization = FLOW_SEQUENCE)) + } + + override fun toString(): String = yaml.stringify(this.serializer, this) } -internal class SettingSerializer( +@Suppress("UNCHECKED_CAST") +val T.serializer: KSerializer + get() = kotlinSerializer as KSerializer + +internal class SettingUpdaterSerializer( private val instance: Setting ) : KSerializer { override val descriptor: SerialDescriptor by lazy { @@ -120,4 +150,9 @@ internal class SettingSerializer( internal object SettingSerializerMark -internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation()?.value ?: this.name \ No newline at end of file +internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation()?.value ?: this.name + + +fun Setting.value(default: T): Value = valueImpl(default) +inline fun Setting.value(default: T, crossinline initializer: T.() -> Unit): Value = + value(default).also { it.value.apply(initializer) } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Value.kt index 3e052566a..1ffe99de5 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Value.kt @@ -9,12 +9,15 @@ package net.mamoe.mirai.console.setting +import kotlinx.serialization.Decoder +import kotlinx.serialization.Encoder import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialDescriptor import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty /** - * !!! These primitive types are auto-generated by backend/codegen/src/main/kotlin/net.mamoe.mirai.console.ValuesCodegen.kt + * !!! These primitive types are auto-generated by backend/codegen/src/main/kotlin/net.mamoe.mirai.console.ValuesCodegen.kt * !!! for better performance * !!! DO NOT MODIFY THIS FILE MANUALLY */ @@ -89,6 +92,7 @@ abstract class TypedStringArrayValue internal constructor() : TypedPrimitiveArra sealed class ListValue : Value>(), Iterable{ override fun iterator() = this.value.iterator() } + abstract class IntListValue internal constructor() : ListValue() abstract class ShortListValue internal constructor() : ListValue() abstract class ByteListValue internal constructor() : ListValue() @@ -99,3 +103,35 @@ abstract class BooleanListValue internal constructor() : ListValue() abstract class CharListValue internal constructor() : ListValue() abstract class StringListValue internal constructor() : ListValue() +abstract class SettingValue internal constructor() : Value() + +internal fun Setting.valueImpl(default: T): Value { + return object : SettingValue() { + private var internalValue: T = default + override var value: T + get() = internalValue + set(new) { + if (new != internalValue) { + internalValue = new + onElementChanged(this) + } + } + override val serializer = object : KSerializer { + override val descriptor: SerialDescriptor + get() = internalValue.updaterSerializer.descriptor + + override fun deserialize(decoder: Decoder): T { + internalValue.updaterSerializer.deserialize(decoder) + return internalValue + } + + override fun serialize(encoder: Encoder, value: T) { + internalValue.updaterSerializer.serialize(encoder, SettingSerializerMark) + } + + }.bind( + getter = { internalValue }, + setter = { internalValue = it } + ) + } +} \ No newline at end of file