diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt index 314c9092d..57fa7e63e 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt @@ -16,7 +16,7 @@ object ValueKtCodegen { object SettingCodegen { object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke { override val defaultInvokeArgs: List - get() = KtType.Primitives + KtString + get() = KtPrimitives + KtString override fun StringBuilder.apply(ktType: KtType) { @Suppress("ClassName") diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/_Setting.value.kt codegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/_Setting.value.kt codegen.kt new file mode 100644 index 000000000..096cc1fe3 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/_Setting.value.kt codegen.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("ClassName") + +package net.mamoe.mirai.console.codegen + +object _Setting_value_ktCodegen { + object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("BuiltInSerializerConstants primitives"), + DefaultInvoke { + override val defaultInvokeArgs: List = KtPrimitives + KtString + + override fun StringBuilder.apply(ktType: KtType) { + appendKCode( + """ + val ${ktType.standardName}SerializerDescriptor = ${ktType.standardName}.serializer().descriptor + """ + ) + } + } + + @JvmStatic + fun main(args: Array) { + codegen("_Setting.value.kt") { + BuiltInSerializerConstantsPrimitivesCodegen() + } + } +} \ No newline at end of file diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt index d5101dc7b..9ccff0c00 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -71,18 +71,16 @@ sealed class KtType { object KtMap : KtType() { override val standardName: String get() = "Map" } - - companion object { - val PrimitiveIntegers = listOf(KtByte, KtShort, KtInt, KtLong) - val PrimitiveFloatings = listOf(KtFloat, KtDouble) - - val PrimitiveNumbers = PrimitiveIntegers + PrimitiveFloatings - val PrimitiveNonNumbers = listOf(KtChar, KtBoolean) - - val Primitives = PrimitiveNumbers + PrimitiveNonNumbers - } } +val KtPrimitiveIntegers = listOf(KtByte, KtShort, KtInt, KtLong) +val KtPrimitiveFloatings = listOf(KtFloat, KtDouble) + +val KtPrimitiveNumbers = KtPrimitiveIntegers + KtPrimitiveFloatings +val KtPrimitiveNonNumbers = listOf(KtChar, KtBoolean) + +val KtPrimitives = KtPrimitiveNumbers + KtPrimitiveNonNumbers + operator fun KtType.plus(type: KtType): List { return listOf(this, type) } diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index c04b32633..a9c523f20 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -81,6 +81,7 @@ tasks { val fillBuildConstants by registering { doLast { + return@doLast // (compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file -> file.writeText(file.readText() .replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) { 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 9dd407898..d09acd8db 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 @@ -12,14 +12,16 @@ package net.mamoe.mirai.console.setting import kotlinx.serialization.* -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.builtins.MapEntrySerializer +import kotlinx.serialization.builtins.MapSerializer 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 net.mamoe.yamlkt.YamlConfiguration +import net.mamoe.yamlkt.YamlConfiguration.ListSerialization.FLOW_SEQUENCE +import net.mamoe.yamlkt.YamlConfiguration.MapSerialization.FLOW_MAP import java.util.* import kotlin.internal.LowPriorityInOverloadResolution import kotlin.reflect.KProperty @@ -36,8 +38,8 @@ abstract class Setting : SettingImpl() { thisRef: Any?, property: KProperty<*> ): SerializerAwareValue { - @Suppress("UNCHECKED_CAST") - valueNodes.add(Node(property.serialName, this, this.serializer)) + val name = property.serialName + valueNodes.put(name, Node(name, this, this.serializer)) return this } @@ -53,7 +55,7 @@ internal val KProperty<*>.serialName: String get() = this.findAnnotation? = valueNodes.firstOrNull { it.serialName == name } + internal fun findNodeInstance(name: String): Node<*>? = valueNodes[name] internal class Node( val serialName: String, @@ -61,67 +63,10 @@ internal abstract class SettingImpl { val updaterSerializer: KSerializer ) - /** - * Serializing like a [Map.Entry] but with higher performance - */ - internal inner class NodeSerializer : KSerializer?> { - 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> = Collections.synchronizedList(mutableListOf()) + internal val valueNodes: MutableMap> = Collections.synchronizedMap(mutableMapOf()) internal open val updaterSerializer: KSerializer by lazy { - val actual = ListSerializer(NodeSerializer()) + val actual = MapSerializer(String.serializer(), String.serializer()) object : KSerializer { override val descriptor: SerialDescriptor @@ -132,7 +77,7 @@ internal abstract class SettingImpl { } override fun serialize(encoder: Encoder, value: Unit) { - actual.serialize(encoder, valueNodes) + TODO() } } @@ -144,6 +89,18 @@ internal abstract class SettingImpl { internal fun onValueChanged(value: Value<*>) { // TODO: 2020/6/22 } + + companion object { + val allFlow = Yaml( + YamlConfiguration( + nonStrictNullability = true, + nonStrictNumber = true, + mapSerialization = FLOW_MAP, + listSerialization = FLOW_SEQUENCE, + classSerialization = FLOW_MAP + ) + ) + } } @@ -151,7 +108,7 @@ internal abstract class SettingImpl { // TODO: 2020/6/19 CODEGEN -fun Setting.value(default: Int): SerializableValue = valueImpl(default) +fun Setting.value(default: Int): SerializerAwareValue = valueImpl(default) //// endregion Setting.value primitives CODEGEN //// @@ -165,6 +122,7 @@ fun Setting.value(default: Int): SerializableValue = valueImpl(default) * (typically annotated with [kotlinx.serialization.Serializable]) */ @LowPriorityInOverloadResolution +@MiraiExperimentalAPI @OptIn(ExperimentalStdlibApi::class) // stable in 1.4 inline fun Setting.valueReified(default: T): SerializableValue = valueFromKTypeImpl(typeOf()).cast() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt index 83f29ea69..4c2ecabb8 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt @@ -134,7 +134,11 @@ internal fun serializerMirai(type: KType): KSerializer { /* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer else -> { if (isReferenceArray(type, rootClass)) { - return ArraySerializer(typeArguments[0].classifier as KClass, serializers[0]).cast() + @Suppress("RemoveExplicitTypeArguments") + return ArraySerializer( + typeArguments[0].classifier as KClass, + serializers[0] + ).cast() } requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) { "Can't find a method to construct serializer for type ${rootClass.simpleName()}. " + diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt index 650200b97..cb9bee61b 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt @@ -9,14 +9,20 @@ package net.mamoe.mirai.console.setting.internal +import kotlinx.serialization.Decoder +import kotlinx.serialization.Encoder +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialDescriptor +import kotlinx.serialization.builtins.serializer import net.mamoe.mirai.console.setting.IntValue +import net.mamoe.mirai.console.setting.SerializerAwareValue //// region PrimitiveValues CODEGEN //// // TODO: 2020/6/21 CODEGEN -internal abstract class IntValueImpl : IntValue { +internal abstract class IntValueImpl : IntValue, SerializerAwareValue, KSerializer { constructor() constructor(default: Int) { _value = default @@ -24,8 +30,8 @@ internal abstract class IntValueImpl : IntValue { private var _value: Int? = null - override var value: Int - get() = _value ?: throw IllegalStateException("IntValue should be initialized before get.") + final override var value: Int + get() = _value ?: error("IntValue.value should be initialized before get.") set(v) { if (v != this._value) { this._value = v @@ -34,6 +40,13 @@ internal abstract class IntValueImpl : IntValue { } protected abstract fun onChanged() + + final override val serializer: KSerializer get() = this + final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.IntSerializerDescriptor + final override fun serialize(encoder: Encoder, value: Unit) = Int.serializer().serialize(encoder, this.value) + final override fun deserialize(decoder: Decoder) { + value = Int.serializer().deserialize(decoder) + } } //// endregion PrimitiveValues CODEGEN //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt index 019b42489..0f0d9a5b1 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt @@ -9,23 +9,36 @@ package net.mamoe.mirai.console.setting.internal +import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.serializer -import net.mamoe.mirai.console.setting.SerializableValue +import net.mamoe.mirai.console.setting.SerializerAwareValue import net.mamoe.mirai.console.setting.Setting +internal object BuiltInSerializerConstants { + //// region BuiltInSerializerConstants primitives CODEGEN //// + + val ByteSerializerDescriptor = Byte.serializer().descriptor + val ShortSerializerDescriptor = Short.serializer().descriptor + val IntSerializerDescriptor = Int.serializer().descriptor + val LongSerializerDescriptor = Long.serializer().descriptor + val FloatSerializerDescriptor = Float.serializer().descriptor + val DoubleSerializerDescriptor = Double.serializer().descriptor + val CharSerializerDescriptor = Char.serializer().descriptor + val BooleanSerializerDescriptor = Boolean.serializer().descriptor + val StringSerializerDescriptor = String.serializer().descriptor + + //// endregion BuiltInSerializerConstants primitives CODEGEN //// +} + //// region Setting.value primitives impl CODEGEN //// // TODO: 2020/6/21 CODEGEN -internal fun Setting.valueImpl(default: Int): SerializableValue { - val instance = object : IntValueImpl(default) { +internal fun Setting.valueImpl(default: Int): SerializerAwareValue { + return object : IntValueImpl(default), SerializerAwareValue, KSerializer { override fun onChanged() = this@valueImpl.onValueChanged(this) } - return SerializableValue(instance, Int.serializer().map( - serializer = { instance.value }, - deserializer = { instance.value = it } - )) } //// endregion Setting.value primitives impl CODEGEN //// diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt index 011486cc5..a0abf50e5 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.console.setting +import net.mamoe.yamlkt.Yaml import org.junit.jupiter.api.Test internal class SettingTest { @@ -21,6 +22,8 @@ internal class SettingTest { @Test fun testPrimitive() { - + val setting = MySetting() + val string = Yaml.nonStrict.stringify(setting.updaterSerializer, Unit) + println(string) } } \ No newline at end of file