Add BuiltInSerializerConstants, update relevant codegen;

Enhance generated primitive values;
Improve SettingImpl.serializer
This commit is contained in:
Him188 2020-06-23 22:25:43 +08:00
parent d204d1f28e
commit 7de3445353
9 changed files with 113 additions and 89 deletions

View File

@ -16,7 +16,7 @@ object ValueKtCodegen {
object SettingCodegen {
object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke {
override val defaultInvokeArgs: List<KtType>
get() = KtType.Primitives + KtString
get() = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
@Suppress("ClassName")

View File

@ -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<KtType> = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
appendKCode(
"""
val ${ktType.standardName}SerializerDescriptor = ${ktType.standardName}.serializer().descriptor
"""
)
}
}
@JvmStatic
fun main(args: Array<String>) {
codegen("_Setting.value.kt") {
BuiltInSerializerConstantsPrimitivesCodegen()
}
}
}

View File

@ -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<KtType> {
return listOf(this, type)
}

View File

@ -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\((.*)\) //(.*)""")) {

View File

@ -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<T> {
@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<SerialN
*/
// TODO move to internal package.
internal abstract class SettingImpl {
internal fun findNodeInstance(name: String): Node<*>? = valueNodes.firstOrNull { it.serialName == name }
internal fun findNodeInstance(name: String): Node<*>? = valueNodes[name]
internal class Node<T>(
val serialName: String,
@ -61,67 +63,10 @@ internal abstract class SettingImpl {
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: MutableMap<String, Node<*>> = Collections.synchronizedMap(mutableMapOf())
internal open val updaterSerializer: KSerializer<Unit> by lazy {
val actual = ListSerializer(NodeSerializer())
val actual = MapSerializer(String.serializer(), String.serializer())
object : KSerializer<Unit> {
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<Int> = valueImpl(default)
fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
//// endregion Setting.value primitives CODEGEN ////
@ -165,6 +122,7 @@ fun Setting.value(default: Int): SerializableValue<Int> = valueImpl(default)
* (typically annotated with [kotlinx.serialization.Serializable])
*/
@LowPriorityInOverloadResolution
@MiraiExperimentalAPI
@OptIn(ExperimentalStdlibApi::class) // stable in 1.4
inline fun <reified T> Setting.valueReified(default: T): SerializableValue<T> = valueFromKTypeImpl(typeOf<T>()).cast()

View File

@ -134,7 +134,11 @@ internal fun serializerMirai(type: KType): KSerializer<Any?> {
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
else -> {
if (isReferenceArray(type, rootClass)) {
return ArraySerializer(typeArguments[0].classifier as KClass<Any>, serializers[0]).cast()
@Suppress("RemoveExplicitTypeArguments")
return ArraySerializer<Any, Any?>(
typeArguments[0].classifier as KClass<Any>,
serializers[0]
).cast()
}
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
"Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +

View File

@ -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<Int>, KSerializer<Unit> {
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<Unit> 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 ////

View File

@ -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<Int> {
val instance = object : IntValueImpl(default) {
internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
return object : IntValueImpl(default), SerializerAwareValue<Int>, KSerializer<Unit> {
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 ////

View File

@ -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)
}
}