mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Add BuiltInSerializerConstants, update relevant codegen;
Enhance generated primitive values; Improve SettingImpl.serializer
This commit is contained in:
parent
d204d1f28e
commit
7de3445353
@ -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")
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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\((.*)\) //(.*)""")) {
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()}. " +
|
||||
|
@ -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 ////
|
||||
|
@ -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 ////
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user