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 SettingCodegen {
|
||||||
object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke {
|
object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke {
|
||||||
override val defaultInvokeArgs: List<KtType>
|
override val defaultInvokeArgs: List<KtType>
|
||||||
get() = KtType.Primitives + KtString
|
get() = KtPrimitives + KtString
|
||||||
|
|
||||||
override fun StringBuilder.apply(ktType: KtType) {
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
@Suppress("ClassName")
|
@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() {
|
object KtMap : KtType() {
|
||||||
override val standardName: String get() = "Map"
|
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> {
|
operator fun KtType.plus(type: KtType): List<KtType> {
|
||||||
return listOf(this, type)
|
return listOf(this, type)
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,7 @@ tasks {
|
|||||||
|
|
||||||
val fillBuildConstants by registering {
|
val fillBuildConstants by registering {
|
||||||
doLast {
|
doLast {
|
||||||
|
return@doLast //
|
||||||
(compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file ->
|
(compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file ->
|
||||||
file.writeText(file.readText()
|
file.writeText(file.readText()
|
||||||
.replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) {
|
.replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) {
|
||||||
|
@ -12,14 +12,16 @@
|
|||||||
package net.mamoe.mirai.console.setting
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.builtins.ListSerializer
|
import kotlinx.serialization.builtins.MapSerializer
|
||||||
import kotlinx.serialization.builtins.MapEntrySerializer
|
|
||||||
import kotlinx.serialization.builtins.serializer
|
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 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 java.util.*
|
||||||
import kotlin.internal.LowPriorityInOverloadResolution
|
import kotlin.internal.LowPriorityInOverloadResolution
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
@ -36,8 +38,8 @@ abstract class Setting : SettingImpl() {
|
|||||||
thisRef: Any?,
|
thisRef: Any?,
|
||||||
property: KProperty<*>
|
property: KProperty<*>
|
||||||
): SerializerAwareValue<T> {
|
): SerializerAwareValue<T> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
val name = property.serialName
|
||||||
valueNodes.add(Node(property.serialName, this, this.serializer))
|
valueNodes.put(name, Node(name, this, this.serializer))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ internal val KProperty<*>.serialName: String get() = this.findAnnotation<SerialN
|
|||||||
*/
|
*/
|
||||||
// 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 fun findNodeInstance(name: String): Node<*>? = valueNodes[name]
|
||||||
|
|
||||||
internal class Node<T>(
|
internal class Node<T>(
|
||||||
val serialName: String,
|
val serialName: String,
|
||||||
@ -61,67 +63,10 @@ internal abstract class SettingImpl {
|
|||||||
val updaterSerializer: KSerializer<Unit>
|
val updaterSerializer: KSerializer<Unit>
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
internal val valueNodes: MutableMap<String, Node<*>> = Collections.synchronizedMap(mutableMapOf())
|
||||||
* 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 open val updaterSerializer: KSerializer<Unit> by lazy {
|
internal open val updaterSerializer: KSerializer<Unit> by lazy {
|
||||||
val actual = ListSerializer(NodeSerializer())
|
val actual = MapSerializer(String.serializer(), String.serializer())
|
||||||
|
|
||||||
object : KSerializer<Unit> {
|
object : KSerializer<Unit> {
|
||||||
override val descriptor: SerialDescriptor
|
override val descriptor: SerialDescriptor
|
||||||
@ -132,7 +77,7 @@ internal abstract class SettingImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: Unit) {
|
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<*>) {
|
internal fun onValueChanged(value: Value<*>) {
|
||||||
// TODO: 2020/6/22
|
// 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
|
// 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 ////
|
//// endregion Setting.value primitives CODEGEN ////
|
||||||
|
|
||||||
@ -165,6 +122,7 @@ fun Setting.value(default: Int): SerializableValue<Int> = valueImpl(default)
|
|||||||
* (typically annotated with [kotlinx.serialization.Serializable])
|
* (typically annotated with [kotlinx.serialization.Serializable])
|
||||||
*/
|
*/
|
||||||
@LowPriorityInOverloadResolution
|
@LowPriorityInOverloadResolution
|
||||||
|
@MiraiExperimentalAPI
|
||||||
@OptIn(ExperimentalStdlibApi::class) // stable in 1.4
|
@OptIn(ExperimentalStdlibApi::class) // stable in 1.4
|
||||||
inline fun <reified T> Setting.valueReified(default: T): SerializableValue<T> = valueFromKTypeImpl(typeOf<T>()).cast()
|
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
|
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
|
||||||
else -> {
|
else -> {
|
||||||
if (isReferenceArray(type, rootClass)) {
|
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())) {
|
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
|
||||||
"Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +
|
"Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +
|
||||||
|
@ -9,14 +9,20 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.setting.internal
|
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.IntValue
|
||||||
|
import net.mamoe.mirai.console.setting.SerializerAwareValue
|
||||||
|
|
||||||
|
|
||||||
//// region PrimitiveValues CODEGEN ////
|
//// region PrimitiveValues CODEGEN ////
|
||||||
|
|
||||||
// TODO: 2020/6/21 CODEGEN
|
// TODO: 2020/6/21 CODEGEN
|
||||||
|
|
||||||
internal abstract class IntValueImpl : IntValue {
|
internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit> {
|
||||||
constructor()
|
constructor()
|
||||||
constructor(default: Int) {
|
constructor(default: Int) {
|
||||||
_value = default
|
_value = default
|
||||||
@ -24,8 +30,8 @@ internal abstract class IntValueImpl : IntValue {
|
|||||||
|
|
||||||
private var _value: Int? = null
|
private var _value: Int? = null
|
||||||
|
|
||||||
override var value: Int
|
final override var value: Int
|
||||||
get() = _value ?: throw IllegalStateException("IntValue should be initialized before get.")
|
get() = _value ?: error("IntValue.value should be initialized before get.")
|
||||||
set(v) {
|
set(v) {
|
||||||
if (v != this._value) {
|
if (v != this._value) {
|
||||||
this._value = v
|
this._value = v
|
||||||
@ -34,6 +40,13 @@ internal abstract class IntValueImpl : IntValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun onChanged()
|
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 ////
|
//// endregion PrimitiveValues CODEGEN ////
|
||||||
|
@ -9,23 +9,36 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.setting.internal
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.builtins.serializer
|
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
|
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 ////
|
//// region Setting.value primitives impl CODEGEN ////
|
||||||
|
|
||||||
// TODO: 2020/6/21 CODEGEN
|
// TODO: 2020/6/21 CODEGEN
|
||||||
|
|
||||||
internal fun Setting.valueImpl(default: Int): SerializableValue<Int> {
|
internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
|
||||||
val instance = object : IntValueImpl(default) {
|
return object : IntValueImpl(default), SerializerAwareValue<Int>, KSerializer<Unit> {
|
||||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
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 ////
|
//// endregion Setting.value primitives impl CODEGEN ////
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.setting
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
|
import net.mamoe.yamlkt.Yaml
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
internal class SettingTest {
|
internal class SettingTest {
|
||||||
@ -21,6 +22,8 @@ internal class SettingTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPrimitive() {
|
fun testPrimitive() {
|
||||||
|
val setting = MySetting()
|
||||||
|
val string = Yaml.nonStrict.stringify(setting.updaterSerializer, Unit)
|
||||||
|
println(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user