mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-13 14:50:43 +08:00
Introduce AbstractValueImpl as superclass to all ValueImpl;
Implement CompositeSetValueImpl, CompositeMapValueImpl, CompositeListValueImpl; Implement value patching and reference tracking; Add SettingTest.kt; Implement SettingImpl.updaterSerializer; `Setting.valueReified` and `Setting.valueFromKType` supports All primitives, Collections and Maps now.
This commit is contained in:
parent
70b9b012e1
commit
9a91c9b2a7
@ -22,9 +22,7 @@ object ValueSettingCodegen {
|
|||||||
object PrimitiveValuesCodegen : RegionCodegen("Value.kt"), DefaultInvoke {
|
object PrimitiveValuesCodegen : RegionCodegen("Value.kt"), DefaultInvoke {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) = super.startIndependent()
|
fun main(args: Array<String>) = super.startIndependent()
|
||||||
|
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
|
||||||
override val defaultInvokeArgs: List<KtType>
|
|
||||||
get() = KtPrimitives + KtString
|
|
||||||
|
|
||||||
override fun StringBuilder.apply(ktType: KtType) {
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
@Suppress("ClassName")
|
@Suppress("ClassName")
|
||||||
@ -42,7 +40,6 @@ object ValueSettingCodegen {
|
|||||||
object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
|
object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) = super.startIndependent()
|
fun main(args: Array<String>) = super.startIndependent()
|
||||||
|
|
||||||
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
|
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
|
||||||
|
|
||||||
override fun StringBuilder.apply(ktType: KtType) {
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
@ -60,14 +57,12 @@ object ValueSettingCodegen {
|
|||||||
object PrimitiveValuesImplCodegen : RegionCodegen("_PrimitiveValueDeclarations.kt"), DefaultInvoke {
|
object PrimitiveValuesImplCodegen : RegionCodegen("_PrimitiveValueDeclarations.kt"), DefaultInvoke {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) = super.startIndependent()
|
fun main(args: Array<String>) = super.startIndependent()
|
||||||
|
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
|
||||||
override val defaultInvokeArgs: List<KtType>
|
|
||||||
get() = KtPrimitives + KtString
|
|
||||||
|
|
||||||
override fun StringBuilder.apply(ktType: KtType) {
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
appendKCode(
|
appendKCode(
|
||||||
"""
|
"""
|
||||||
internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName}Value, SerializerAwareValue<${ktType.standardName}>, KSerializer<Unit> {
|
internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName}Value, SerializerAwareValue<${ktType.standardName}>, KSerializer<Unit>, AbstractValueImpl<${ktType.standardName}> {
|
||||||
constructor()
|
constructor()
|
||||||
constructor(default: ${ktType.standardName}) {
|
constructor(default: ${ktType.standardName}) {
|
||||||
_value = default
|
_value = default
|
||||||
@ -89,8 +84,13 @@ internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName}
|
|||||||
final override val serializer: KSerializer<Unit> get() = this
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.${ktType.standardName}SerializerDescriptor
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.${ktType.standardName}SerializerDescriptor
|
||||||
final override fun serialize(encoder: Encoder, value: Unit) = ${ktType.standardName}.serializer().serialize(encoder, this.value)
|
final override fun serialize(encoder: Encoder, value: Unit) = ${ktType.standardName}.serializer().serialize(encoder, this.value)
|
||||||
final override fun deserialize(decoder: Decoder) {
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(${ktType.standardName}.serializer().deserialize(decoder))
|
||||||
value = ${ktType.standardName}.serializer().deserialize(decoder)
|
override fun toString(): String = _value${if (ktType != KtString) "?.toString()" else ""} ?: "${ktType.standardName}Value.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean = other is ${ktType.standardName}ValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -102,9 +102,7 @@ internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName}
|
|||||||
object Setting_value_PrimitivesImplCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
|
object Setting_value_PrimitivesImplCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) = super.startIndependent()
|
fun main(args: Array<String>) = super.startIndependent()
|
||||||
|
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
|
||||||
override val defaultInvokeArgs: List<KtType>
|
|
||||||
get() = KtPrimitives + KtString
|
|
||||||
|
|
||||||
override fun StringBuilder.apply(ktType: KtType) {
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
appendKCode(
|
appendKCode(
|
||||||
@ -127,9 +125,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
|
|||||||
object Setting_valueImplPrimitiveCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
|
object Setting_valueImplPrimitiveCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) = super.startIndependent()
|
fun main(args: Array<String>) = super.startIndependent()
|
||||||
|
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
|
||||||
override val defaultInvokeArgs: List<KtType>
|
|
||||||
get() = KtPrimitives + KtString
|
|
||||||
|
|
||||||
override fun StringBuilder.apply(ktType: KtType) {
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
appendKCode(
|
appendKCode(
|
||||||
|
@ -15,6 +15,7 @@ import kotlinx.serialization.*
|
|||||||
import kotlinx.serialization.builtins.MapSerializer
|
import kotlinx.serialization.builtins.MapSerializer
|
||||||
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.isOdd
|
||||||
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
|
||||||
@ -22,7 +23,7 @@ import net.mamoe.yamlkt.Yaml
|
|||||||
import net.mamoe.yamlkt.YamlConfiguration
|
import net.mamoe.yamlkt.YamlConfiguration
|
||||||
import net.mamoe.yamlkt.YamlConfiguration.ListSerialization.FLOW_SEQUENCE
|
import net.mamoe.yamlkt.YamlConfiguration.ListSerialization.FLOW_SEQUENCE
|
||||||
import net.mamoe.yamlkt.YamlConfiguration.MapSerialization.FLOW_MAP
|
import net.mamoe.yamlkt.YamlConfiguration.MapSerialization.FLOW_MAP
|
||||||
import java.util.*
|
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
|
||||||
import kotlin.internal.LowPriorityInOverloadResolution
|
import kotlin.internal.LowPriorityInOverloadResolution
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
@ -39,7 +40,7 @@ abstract class Setting : SettingImpl() {
|
|||||||
property: KProperty<*>
|
property: KProperty<*>
|
||||||
): SerializerAwareValue<T> {
|
): SerializerAwareValue<T> {
|
||||||
val name = property.serialName
|
val name = property.serialName
|
||||||
valueNodes.put(name, Node(name, this, this.serializer))
|
valueNodes.add(Node(name, this, this.serializer))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,29 +56,82 @@ 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[name]
|
internal fun findNodeInstance(name: String): Node<*>? = valueNodes.firstOrNull { it.serialName == name }
|
||||||
|
|
||||||
internal class Node<T>(
|
internal data class Node<T>(
|
||||||
val serialName: String,
|
val serialName: String,
|
||||||
val value: Value<T>,
|
val value: Value<T>,
|
||||||
val updaterSerializer: KSerializer<Unit>
|
val updaterSerializer: KSerializer<Unit>
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val valueNodes: MutableMap<String, Node<*>> = Collections.synchronizedMap(mutableMapOf())
|
internal val valueNodes: MutableList<Node<*>> = mutableListOf()
|
||||||
|
|
||||||
internal open val updaterSerializer: KSerializer<Unit> by lazy {
|
internal open val updaterSerializer: KSerializer<Unit> by lazy {
|
||||||
val actual = MapSerializer(String.serializer(), String.serializer())
|
|
||||||
|
|
||||||
object : KSerializer<Unit> {
|
object : KSerializer<Unit> {
|
||||||
override val descriptor: SerialDescriptor
|
override val descriptor: SerialDescriptor get() = settingUpdaterSerializerDescriptor
|
||||||
get() = actual.descriptor
|
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun deserialize(decoder: Decoder) {
|
override fun deserialize(decoder: Decoder) {
|
||||||
actual.deserialize(decoder)
|
val descriptor = descriptor
|
||||||
|
with(decoder.beginStructure(descriptor, *settingUpdaterSerializerTypeArguments)) {
|
||||||
|
if (decodeSequentially()) {
|
||||||
|
var index = 0
|
||||||
|
repeat(decodeCollectionSize(descriptor)) {
|
||||||
|
val serialName = decodeSerializableElement(descriptor, index++, String.serializer())
|
||||||
|
val node = findNodeInstance(serialName)
|
||||||
|
if (node == null) {
|
||||||
|
decodeSerializableElement(descriptor, index++, YamlNullableDynamicSerializer)
|
||||||
|
} else {
|
||||||
|
decodeSerializableElement(descriptor, index++, node.updaterSerializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outerLoop@ while (true) {
|
||||||
|
var serialName: String? = null
|
||||||
|
innerLoop@ while (true) {
|
||||||
|
val index = decodeElementIndex(descriptor)
|
||||||
|
if (index == CompositeDecoder.READ_DONE) {
|
||||||
|
check(serialName == null) { "name must be null at this moment." }
|
||||||
|
break@outerLoop
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!index.isOdd()) { // key
|
||||||
|
check(serialName == null) { "name must be null at this moment" }
|
||||||
|
serialName = decodeSerializableElement(descriptor, index, String.serializer())
|
||||||
|
} else {
|
||||||
|
check(serialName != null) { "name must not be null at this moment" }
|
||||||
|
|
||||||
|
val node = findNodeInstance(serialName)
|
||||||
|
if (node == null) {
|
||||||
|
decodeSerializableElement(descriptor, index, YamlNullableDynamicSerializer)
|
||||||
|
} else {
|
||||||
|
decodeSerializableElement(descriptor, index, node.updaterSerializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
break@innerLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endStructure(descriptor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun serialize(encoder: Encoder, value: Unit) {
|
override fun serialize(encoder: Encoder, value: Unit) {
|
||||||
TODO()
|
val descriptor = descriptor
|
||||||
|
with(encoder.beginCollection(descriptor, valueNodes.size, *settingUpdaterSerializerTypeArguments)) {
|
||||||
|
var index = 0
|
||||||
|
|
||||||
|
// val vSerializer = settingUpdaterSerializerTypeArguments[1] as KSerializer<Any?>
|
||||||
|
valueNodes.forEach { (serialName, _, valueSerializer) ->
|
||||||
|
encodeSerializableElement(descriptor, index++, String.serializer(), serialName)
|
||||||
|
encodeSerializableElement(descriptor, index++, valueSerializer, Unit)
|
||||||
|
}
|
||||||
|
endStructure(descriptor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -91,6 +145,13 @@ internal abstract class SettingImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
private val ABSENT_STUB = Any()
|
||||||
|
|
||||||
|
private val settingUpdaterSerializerTypeArguments = arrayOf(String.serializer(), YamlNullableDynamicSerializer)
|
||||||
|
private val settingUpdaterSerializerDescriptor =
|
||||||
|
MapSerializer(settingUpdaterSerializerTypeArguments[0], settingUpdaterSerializerTypeArguments[1]).descriptor
|
||||||
|
|
||||||
val allFlow = Yaml(
|
val allFlow = Yaml(
|
||||||
YamlConfiguration(
|
YamlConfiguration(
|
||||||
nonStrictNullability = true,
|
nonStrictNullability = true,
|
||||||
@ -124,7 +185,8 @@ fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
|
|||||||
@LowPriorityInOverloadResolution
|
@LowPriorityInOverloadResolution
|
||||||
@MiraiExperimentalAPI
|
@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): SerializerAwareValue<T> =
|
||||||
|
valueFromKTypeImpl(typeOf<T>()).cast()
|
||||||
|
|
||||||
@MiraiExperimentalAPI
|
@MiraiExperimentalAPI
|
||||||
fun <T> Setting.valueFromKType(type: KType): SerializableValue<T> = valueFromKTypeImpl(type).cast()
|
fun <T> Setting.valueFromKType(type: KType): SerializerAwareValue<T> = valueFromKTypeImpl(type).cast()
|
@ -15,6 +15,7 @@ import kotlinx.serialization.BinaryFormat
|
|||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.StringFormat
|
import kotlinx.serialization.StringFormat
|
||||||
import net.mamoe.mirai.console.setting.internal.map
|
import net.mamoe.mirai.console.setting.internal.map
|
||||||
|
import net.mamoe.mirai.console.setting.internal.setValueBySerializer
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@ -36,17 +37,22 @@ interface Value<T> {
|
|||||||
* Typically returned by [Setting.value] functions.
|
* Typically returned by [Setting.value] functions.
|
||||||
*/
|
*/
|
||||||
class SerializableValue<T>(
|
class SerializableValue<T>(
|
||||||
delegate: Value<T>,
|
private val delegate: Value<T>,
|
||||||
/**
|
/**
|
||||||
* The serializer used to update and dump [delegate]
|
* The serializer used to update and dump [delegate]
|
||||||
*/
|
*/
|
||||||
override val serializer: KSerializer<Unit>
|
override val serializer: KSerializer<Unit>
|
||||||
) : Value<T> by delegate, SerializerAwareValue<T>
|
) : Value<T> by delegate, SerializerAwareValue<T> {
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> Value<T>.serializableValueWith(
|
fun <T> Value<T>.serializableValueWith(
|
||||||
serializer: KSerializer<T>
|
serializer: KSerializer<T>
|
||||||
): SerializableValue<T> {
|
): SerializableValue<T> {
|
||||||
return SerializableValue(this, serializer.map(serializer = { this.value }, deserializer = { this.value = it }))
|
return SerializableValue(
|
||||||
|
this,
|
||||||
|
serializer.map(serializer = { this.value }, deserializer = { this.setValueBySerializer(it) })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +142,6 @@ interface BooleanValue : PrimitiveValue<Boolean>
|
|||||||
*/
|
*/
|
||||||
interface StringValue : PrimitiveValue<String>
|
interface StringValue : PrimitiveValue<String>
|
||||||
|
|
||||||
|
|
||||||
//// endregion PrimitiveValues CODEGEN ////
|
//// endregion PrimitiveValues CODEGEN ////
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>):
|
|||||||
|
|
||||||
internal abstract class CompositeSetValueImpl<T>(
|
internal abstract class CompositeSetValueImpl<T>(
|
||||||
tToValue: (T) -> Value<T> // should override onChanged
|
tToValue: (T) -> Value<T> // should override onChanged
|
||||||
) : CompositeSetValue<T> {
|
) : CompositeSetValue<T>, AbstractValueImpl<Set<T>>() {
|
||||||
private val internalSet: MutableSet<Value<T>> = mutableSetOf()
|
private val internalSet: MutableSet<Value<T>> = mutableSetOf()
|
||||||
|
|
||||||
private var _value: Set<T> = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
private var _value: Set<T> = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||||
@ -34,12 +34,30 @@ internal abstract class CompositeSetValueImpl<T>(
|
|||||||
get() = _value
|
get() = _value
|
||||||
set(v) {
|
set(v) {
|
||||||
if (_value != v) {
|
if (_value != v) {
|
||||||
|
@Suppress("LocalVariableName")
|
||||||
|
val _value = _value as MutableSet<T>
|
||||||
|
_value.clear()
|
||||||
|
_value.addAll(v)
|
||||||
onChanged()
|
onChanged()
|
||||||
_value = v
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setValueBySerializer(value: Set<T>) {
|
||||||
|
val thisValue = this.value
|
||||||
|
if (!thisValue.tryPatch(value)) {
|
||||||
|
this.value = value // deep set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun onChanged()
|
protected abstract fun onChanged()
|
||||||
|
override fun toString(): String = _value.toString()
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is CompositeSetValueImpl<*> && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return value.hashCode() * 31 + super.hashCode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -54,21 +72,39 @@ internal fun <T> Setting.createCompositeListValueImpl(tToValue: (T) -> Value<T>)
|
|||||||
|
|
||||||
internal abstract class CompositeListValueImpl<T>(
|
internal abstract class CompositeListValueImpl<T>(
|
||||||
tToValue: (T) -> Value<T> // should override onChanged
|
tToValue: (T) -> Value<T> // should override onChanged
|
||||||
) : CompositeListValue<T> {
|
) : CompositeListValue<T>, AbstractValueImpl<List<T>>() {
|
||||||
private val internalList: MutableList<Value<T>> = mutableListOf()
|
private val internalList: MutableList<Value<T>> = mutableListOf()
|
||||||
|
|
||||||
private var _value: List<T> = internalList.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
private val _value: List<T> = internalList.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||||
|
|
||||||
override var value: List<T>
|
override var value: List<T>
|
||||||
get() = _value
|
get() = _value
|
||||||
set(v) {
|
set(v) {
|
||||||
if (_value != v) {
|
if (_value != v) {
|
||||||
|
@Suppress("LocalVariableName")
|
||||||
|
val _value = _value as MutableList<T>
|
||||||
|
_value.clear()
|
||||||
|
_value.addAll(v)
|
||||||
onChanged()
|
onChanged()
|
||||||
_value = v
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setValueBySerializer(value: List<T>) {
|
||||||
|
val thisValue = this.value
|
||||||
|
if (!thisValue.tryPatch(value)) {
|
||||||
|
this.value = value // deep set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun onChanged()
|
protected abstract fun onChanged()
|
||||||
|
override fun toString(): String = _value.toString()
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is CompositeListValueImpl<*> && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return value.hashCode() * 31 + super.hashCode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround to a type inference bug
|
// workaround to a type inference bug
|
||||||
@ -77,28 +113,85 @@ internal fun <K, V> Setting.createCompositeMapValueImpl(
|
|||||||
vToValue: (V) -> Value<V>
|
vToValue: (V) -> Value<V>
|
||||||
): CompositeMapValueImpl<K, V> {
|
): CompositeMapValueImpl<K, V> {
|
||||||
return object : CompositeMapValueImpl<K, V>(kToValue, vToValue) {
|
return object : CompositeMapValueImpl<K, V>(kToValue, vToValue) {
|
||||||
override fun onChanged() {
|
override fun onChanged() = this@createCompositeMapValueImpl.onValueChanged(this)
|
||||||
this@createCompositeMapValueImpl.onValueChanged(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class CompositeMapValueImpl<K, V>(
|
internal abstract class CompositeMapValueImpl<K, V>(
|
||||||
kToValue: (K) -> Value<K>, // should override onChanged
|
kToValue: (K) -> Value<K>, // should override onChanged
|
||||||
vToValue: (V) -> Value<V> // should override onChanged
|
vToValue: (V) -> Value<V> // should override onChanged
|
||||||
) : CompositeMapValue<K, V> {
|
) : CompositeMapValue<K, V>, AbstractValueImpl<Map<K, V>>() {
|
||||||
private val internalList: MutableMap<Value<K>, Value<V>> = mutableMapOf()
|
private val internalList: MutableMap<Value<K>, Value<V>> = mutableMapOf()
|
||||||
|
|
||||||
private var _value: Map<K, V> =
|
private var _value: MutableMap<K, V> =
|
||||||
internalList.shadowMap({ it.value }, kToValue, { it.value }, vToValue).observable { onChanged() }
|
internalList.shadowMap({ it.value }, kToValue, { it.value }, vToValue).observable { onChanged() }
|
||||||
override var value: Map<K, V>
|
override var value: Map<K, V>
|
||||||
get() = _value
|
get() = _value
|
||||||
set(v) {
|
set(v) {
|
||||||
if (_value != v) {
|
if (_value != v) {
|
||||||
|
@Suppress("LocalVariableName")
|
||||||
|
val _value = _value
|
||||||
|
_value.clear()
|
||||||
|
_value.putAll(v)
|
||||||
onChanged()
|
onChanged()
|
||||||
_value = v
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setValueBySerializer(value: Map<K, V>) {
|
||||||
|
val thisValue = this.value as MutableMap<K, V>
|
||||||
|
if (!thisValue.tryPatch(value)) {
|
||||||
|
this.value = value // deep set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun onChanged()
|
protected abstract fun onChanged()
|
||||||
|
override fun toString(): String = _value.toString()
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is CompositeMapValueImpl<*, *> && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return value.hashCode() * 31 + super.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <K, V> MutableMap<K, V>.patchImpl(_new: Map<K, V>) {
|
||||||
|
val new = _new.toMutableMap()
|
||||||
|
val iterator = this.iterator()
|
||||||
|
for (entry in iterator) {
|
||||||
|
val newValue = new.remove(entry.key)
|
||||||
|
|
||||||
|
if (newValue != null) {
|
||||||
|
// has replacer
|
||||||
|
if (entry.value?.tryPatch(newValue) != true) {
|
||||||
|
// patch not supported, or old value is null
|
||||||
|
entry.setValue(newValue)
|
||||||
|
} // else: patched, no remove
|
||||||
|
} else {
|
||||||
|
// no replacer
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putAll(new)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <C : MutableCollection<E>, E> C.patchImpl(_new: Collection<E>) {
|
||||||
|
this.retainAll(_new)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if successfully patched
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
internal fun Any.tryPatch(any: Any): Boolean = when {
|
||||||
|
this is MutableCollection<*> && any is Collection<*> -> {
|
||||||
|
(this as MutableCollection<Any?>).patchImpl(any as Collection<Any?>)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
this is MutableMap<*, *> && any is Map<*, *> -> {
|
||||||
|
(this as MutableMap<Any?, Any?>).patchImpl(any as Map<Any?, Any?>)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
this is Value<*> && any is Value<*> -> any.value?.let { otherValue -> this.value?.tryPatch(otherValue) } == true
|
||||||
|
else -> false
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ package net.mamoe.mirai.console.setting.internal
|
|||||||
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.builtins.*
|
import kotlinx.serialization.builtins.*
|
||||||
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
|
||||||
import net.mamoe.mirai.console.setting.serializableValueWith
|
import net.mamoe.mirai.console.setting.serializableValueWith
|
||||||
import net.mamoe.mirai.console.setting.valueFromKType
|
import net.mamoe.mirai.console.setting.valueFromKType
|
||||||
@ -22,43 +22,52 @@ import net.mamoe.yamlkt.YamlNullableDynamicSerializer
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
|
private val primitiveCollectionsImplemented by lazy {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST")
|
@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST")
|
||||||
internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
|
internal fun Setting.valueFromKTypeImpl(type: KType): SerializerAwareValue<*> {
|
||||||
val classifier = type.classifier
|
val classifier = type.classifier
|
||||||
require(classifier is KClass<*>)
|
require(classifier is KClass<*>)
|
||||||
|
|
||||||
if (classifier.isPrimitiveOrBuiltInSerializableValue()) {
|
if (classifier.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
TODO("是基础类型, 可以直接创建 ValueImpl. ")
|
return valueImplPrimitive(classifier) as SerializerAwareValue<*>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复合类型
|
// 复合类型
|
||||||
|
|
||||||
when (classifier) {
|
when (classifier) {
|
||||||
Map::class -> {
|
MutableMap::class,
|
||||||
|
Map::class
|
||||||
|
-> {
|
||||||
val keyClass = type.arguments[0].type?.classifier
|
val keyClass = type.arguments[0].type?.classifier
|
||||||
require(keyClass is KClass<*>)
|
require(keyClass is KClass<*>)
|
||||||
|
|
||||||
val valueClass = type.arguments[1].type?.classifier
|
val valueClass = type.arguments[1].type?.classifier
|
||||||
require(valueClass is KClass<*>)
|
require(valueClass is KClass<*>)
|
||||||
|
|
||||||
if (keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
|
if (primitiveCollectionsImplemented && keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
// PrimitiveIntIntMap
|
// PrimitiveIntIntMap
|
||||||
// ...
|
// ...
|
||||||
TODO()
|
TODO()
|
||||||
} else {
|
} else {
|
||||||
return createCompositeMapValueImpl<Any?, Any?>(
|
return createCompositeMapValueImpl<Any?, Any?>(
|
||||||
kToValue = { valueFromKType(type.arguments[0].type!!) },
|
kToValue = { k -> valueFromKType<Any?>(type.arguments[0].type!!).also { it.value = k } },
|
||||||
vToValue = { valueFromKType(type.arguments[1].type!!) }
|
vToValue = { v -> valueFromKType<Any?>(type.arguments[1].type!!).also { it.value = v } }
|
||||||
).serializableValueWith(serializerMirai(type) as KSerializer<Map<Any?, Any?>>) // erased
|
).serializableValueWith(serializerMirai(type) as KSerializer<Map<Any?, Any?>>) // erased
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List::class -> {
|
Collection::class,
|
||||||
|
MutableCollection::class,
|
||||||
|
MutableList::class,
|
||||||
|
List::class
|
||||||
|
-> {
|
||||||
val elementClass = type.arguments[0].type?.classifier
|
val elementClass = type.arguments[0].type?.classifier
|
||||||
require(elementClass is KClass<*>)
|
require(elementClass is KClass<*>)
|
||||||
|
|
||||||
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
if (primitiveCollectionsImplemented && elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
// PrimitiveIntList
|
// PrimitiveIntList
|
||||||
// ...
|
// ...
|
||||||
TODO()
|
TODO()
|
||||||
@ -67,11 +76,13 @@ internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
|
|||||||
.serializableValueWith(serializerMirai(type) as KSerializer<List<Any?>>)
|
.serializableValueWith(serializerMirai(type) as KSerializer<List<Any?>>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set::class -> {
|
MutableSet::class,
|
||||||
|
Set::class
|
||||||
|
-> {
|
||||||
val elementClass = type.arguments[0].type?.classifier
|
val elementClass = type.arguments[0].type?.classifier
|
||||||
require(elementClass is KClass<*>)
|
require(elementClass is KClass<*>)
|
||||||
|
|
||||||
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
if (primitiveCollectionsImplemented && elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
// PrimitiveIntSet
|
// PrimitiveIntSet
|
||||||
// ...
|
// ...
|
||||||
TODO()
|
TODO()
|
||||||
@ -85,7 +96,6 @@ internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
|
internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
|
||||||
return false // debug
|
|
||||||
when (this) {
|
when (this) {
|
||||||
Byte::class, Short::class, Int::class, Long::class,
|
Byte::class, Short::class, Int::class, Long::class,
|
||||||
Boolean::class,
|
Boolean::class,
|
||||||
|
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The super class to all ValueImpl s
|
||||||
|
*/
|
||||||
|
internal abstract class AbstractValueImpl<T> : Value<T> {
|
||||||
|
open fun setValueBySerializer(value: T) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <T> Value<T>.setValueBySerializer(value: T) = (this as AbstractValueImpl<T>).setValueBySerializer(value)
|
||||||
|
|
||||||
|
//// region PrimitiveValuesImpl CODEGEN ////
|
||||||
|
|
||||||
|
internal abstract class ByteValueImpl : ByteValue, SerializerAwareValue<Byte>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Byte> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Byte) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Byte? = null
|
||||||
|
|
||||||
|
final override var value: Byte
|
||||||
|
get() = _value ?: error("ByteValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.ByteSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Byte.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Byte.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "ByteValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is ByteValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class ShortValueImpl : ShortValue, SerializerAwareValue<Short>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Short> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Short) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Short? = null
|
||||||
|
|
||||||
|
final override var value: Short
|
||||||
|
get() = _value ?: error("ShortValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.ShortSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Short.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Short.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "ShortValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is ShortValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit>, AbstractValueImpl<Int> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Int) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Int? = null
|
||||||
|
|
||||||
|
final override var value: Int
|
||||||
|
get() = _value ?: error("IntValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
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) = setValueBySerializer(Int.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "IntValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is IntValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class LongValueImpl : LongValue, SerializerAwareValue<Long>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Long> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Long) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Long? = null
|
||||||
|
|
||||||
|
final override var value: Long
|
||||||
|
get() = _value ?: error("LongValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.LongSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Long.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Long.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "LongValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is LongValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class FloatValueImpl : FloatValue, SerializerAwareValue<Float>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Float> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Float) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Float? = null
|
||||||
|
|
||||||
|
final override var value: Float
|
||||||
|
get() = _value ?: error("FloatValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.FloatSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Float.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Float.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "FloatValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is FloatValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class DoubleValueImpl : DoubleValue, SerializerAwareValue<Double>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Double> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Double) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Double? = null
|
||||||
|
|
||||||
|
final override var value: Double
|
||||||
|
get() = _value ?: error("DoubleValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.DoubleSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Double.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Double.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "DoubleValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is DoubleValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class CharValueImpl : CharValue, SerializerAwareValue<Char>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Char> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Char) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Char? = null
|
||||||
|
|
||||||
|
final override var value: Char
|
||||||
|
get() = _value ?: error("CharValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.CharSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Char.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Char.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "CharValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is CharValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class BooleanValueImpl : BooleanValue, SerializerAwareValue<Boolean>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<Boolean> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Boolean) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Boolean? = null
|
||||||
|
|
||||||
|
final override var value: Boolean
|
||||||
|
get() = _value ?: error("BooleanValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.BooleanSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = Boolean.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(Boolean.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value?.toString() ?: "BooleanValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is BooleanValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class StringValueImpl : StringValue, SerializerAwareValue<String>, KSerializer<Unit>,
|
||||||
|
AbstractValueImpl<String> {
|
||||||
|
constructor()
|
||||||
|
constructor(default: String) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: String? = null
|
||||||
|
|
||||||
|
final override var value: String
|
||||||
|
get() = _value ?: error("StringValue.value should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
|
||||||
|
final override val serializer: KSerializer<Unit> get() = this
|
||||||
|
final override val descriptor: SerialDescriptor get() = BuiltInSerializerConstants.StringSerializerDescriptor
|
||||||
|
final override fun serialize(encoder: Encoder, value: Unit) = String.serializer().serialize(encoder, this.value)
|
||||||
|
final override fun deserialize(decoder: Decoder) = setValueBySerializer(String.serializer().deserialize(decoder))
|
||||||
|
override fun toString(): String = _value ?: "StringValue.value not yet initialized."
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
other is StringValueImpl && other::class.java == this::class.java && other._value == this._value
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
val value = _value
|
||||||
|
return if (value == null) 1
|
||||||
|
else value.hashCode() * 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// endregion PrimitiveValuesImpl CODEGEN ////
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
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, SerializerAwareValue<Int>, KSerializer<Unit> {
|
|
||||||
constructor()
|
|
||||||
constructor(default: Int) {
|
|
||||||
_value = default
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _value: Int? = null
|
|
||||||
|
|
||||||
final override var value: Int
|
|
||||||
get() = _value ?: error("IntValue.value should be initialized before get.")
|
|
||||||
set(v) {
|
|
||||||
if (v != this._value) {
|
|
||||||
this._value = v
|
|
||||||
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 ////
|
|
@ -12,10 +12,11 @@ package net.mamoe.mirai.console.setting.internal
|
|||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
import net.mamoe.mirai.console.setting.SerializerAwareValue
|
import net.mamoe.mirai.console.setting.SerializerAwareValue
|
||||||
import net.mamoe.mirai.console.setting.Setting
|
import net.mamoe.mirai.console.setting.Setting
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
internal object BuiltInSerializerConstants {
|
internal object BuiltInSerializerConstants {
|
||||||
//// region BuiltInSerializerConstants primitives CODEGEN ////
|
//// region BuiltInSerializerConstantsPrimitives CODEGEN ////
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val ByteSerializerDescriptor = Byte.serializer().descriptor
|
val ByteSerializerDescriptor = Byte.serializer().descriptor
|
||||||
@ -44,13 +45,55 @@ internal object BuiltInSerializerConstants {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
val StringSerializerDescriptor = String.serializer().descriptor
|
val StringSerializerDescriptor = String.serializer().descriptor
|
||||||
|
|
||||||
|
//// endregion BuiltInSerializerConstantsPrimitives CODEGEN ////
|
||||||
//// endregion BuiltInSerializerConstants primitives CODEGEN ////
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//// region Setting.value primitives impl CODEGEN ////
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
internal fun <T : Any> Setting.valueImplPrimitive(kClass: KClass<T>): SerializerAwareValue<T>? {
|
||||||
|
return when (kClass) {
|
||||||
|
//// region Setting_valueImplPrimitive CODEGEN ////
|
||||||
|
|
||||||
// TODO: 2020/6/21 CODEGEN
|
Byte::class -> byteValueImpl()
|
||||||
|
Short::class -> shortValueImpl()
|
||||||
|
Int::class -> intValueImpl()
|
||||||
|
Long::class -> longValueImpl()
|
||||||
|
Float::class -> floatValueImpl()
|
||||||
|
Double::class -> doubleValueImpl()
|
||||||
|
Char::class -> charValueImpl()
|
||||||
|
Boolean::class -> booleanValueImpl()
|
||||||
|
String::class -> stringValueImpl()
|
||||||
|
|
||||||
|
//// endregion Setting_valueImplPrimitive CODEGEN ////
|
||||||
|
else -> error("Internal error: unexpected type passed: ${kClass.qualifiedName}")
|
||||||
|
} as SerializerAwareValue<T>?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// region Setting_value_PrimitivesImpl CODEGEN ////
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Byte): SerializerAwareValue<Byte> {
|
||||||
|
return object : ByteValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.byteValueImpl(): SerializerAwareValue<Byte> {
|
||||||
|
return object : ByteValueImpl() {
|
||||||
|
override fun onChanged() = this@byteValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Short): SerializerAwareValue<Short> {
|
||||||
|
return object : ShortValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.shortValueImpl(): SerializerAwareValue<Short> {
|
||||||
|
return object : ShortValueImpl() {
|
||||||
|
override fun onChanged() = this@shortValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
|
internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
|
||||||
return object : IntValueImpl(default) {
|
return object : IntValueImpl(default) {
|
||||||
@ -58,4 +101,82 @@ internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// endregion Setting.value primitives impl CODEGEN ////
|
internal fun Setting.intValueImpl(): SerializerAwareValue<Int> {
|
||||||
|
return object : IntValueImpl() {
|
||||||
|
override fun onChanged() = this@intValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Long): SerializerAwareValue<Long> {
|
||||||
|
return object : LongValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.longValueImpl(): SerializerAwareValue<Long> {
|
||||||
|
return object : LongValueImpl() {
|
||||||
|
override fun onChanged() = this@longValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Float): SerializerAwareValue<Float> {
|
||||||
|
return object : FloatValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.floatValueImpl(): SerializerAwareValue<Float> {
|
||||||
|
return object : FloatValueImpl() {
|
||||||
|
override fun onChanged() = this@floatValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Double): SerializerAwareValue<Double> {
|
||||||
|
return object : DoubleValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.doubleValueImpl(): SerializerAwareValue<Double> {
|
||||||
|
return object : DoubleValueImpl() {
|
||||||
|
override fun onChanged() = this@doubleValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Char): SerializerAwareValue<Char> {
|
||||||
|
return object : CharValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.charValueImpl(): SerializerAwareValue<Char> {
|
||||||
|
return object : CharValueImpl() {
|
||||||
|
override fun onChanged() = this@charValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Boolean): SerializerAwareValue<Boolean> {
|
||||||
|
return object : BooleanValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.booleanValueImpl(): SerializerAwareValue<Boolean> {
|
||||||
|
return object : BooleanValueImpl() {
|
||||||
|
override fun onChanged() = this@booleanValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: String): SerializerAwareValue<String> {
|
||||||
|
return object : StringValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Setting.stringValueImpl(): SerializerAwareValue<String> {
|
||||||
|
return object : StringValueImpl() {
|
||||||
|
override fun onChanged() = this@stringValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// endregion Setting_value_PrimitivesImpl CODEGEN ////
|
||||||
|
@ -16,6 +16,8 @@ import kotlinx.serialization.serializer
|
|||||||
import net.mamoe.yamlkt.Yaml
|
import net.mamoe.yamlkt.Yaml
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
// TODO: 2020/6/24 优化性能: 引入一个 comparator 之类来替代将 Int 包装为 Value<Int> 后进行 containsKey 比较的方法
|
||||||
|
|
||||||
internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
||||||
crossinline kTransform: (K) -> KR,
|
crossinline kTransform: (K) -> KR,
|
||||||
crossinline kTransformBack: (KR) -> K,
|
crossinline kTransformBack: (KR) -> K,
|
||||||
@ -37,6 +39,13 @@ internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
|||||||
override val value: VR get() = entry.value.let(vTransform)
|
override val value: VR get() = entry.value.let(vTransform)
|
||||||
override fun setValue(newValue: VR): VR =
|
override fun setValue(newValue: VR): VR =
|
||||||
entry.setValue(newValue.let(vTransformBack)).let(vTransform)
|
entry.setValue(newValue.let(vTransformBack)).let(vTransform)
|
||||||
|
|
||||||
|
override fun hashCode(): Int = 17 * 31 + (key?.hashCode() ?: 0) + (value?.hashCode() ?: 0)
|
||||||
|
override fun toString(): String = "$key=$value"
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other == null || other !is Map.Entry<*, *>) return false
|
||||||
|
return other.key == key && other.value == value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} as ((MutableMap.MutableEntry<K, V>) -> MutableMap.MutableEntry<KR, VR>), // type inference bug
|
} as ((MutableMap.MutableEntry<K, V>) -> MutableMap.MutableEntry<KR, VR>), // type inference bug
|
||||||
transformBack = { entry ->
|
transformBack = { entry ->
|
||||||
@ -45,6 +54,13 @@ internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
|||||||
override val value: V get() = entry.value.let(vTransformBack)
|
override val value: V get() = entry.value.let(vTransformBack)
|
||||||
override fun setValue(newValue: V): V =
|
override fun setValue(newValue: V): V =
|
||||||
entry.setValue(newValue.let(vTransform)).let(vTransformBack)
|
entry.setValue(newValue.let(vTransform)).let(vTransformBack)
|
||||||
|
|
||||||
|
override fun hashCode(): Int = 17 * 31 + (key?.hashCode() ?: 0) + (value?.hashCode() ?: 0)
|
||||||
|
override fun toString(): String = "$key=$value"
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other == null || other !is Map.Entry<*, *>) return false
|
||||||
|
return other.key == key && other.value == value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -64,6 +80,8 @@ internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(key: KR): VR? = this@shadowMap.remove(key.let(kTransformBack))?.let(vTransform)
|
override fun remove(key: KR): VR? = this@shadowMap.remove(key.let(kTransformBack))?.let(vTransform)
|
||||||
|
override fun toString(): String = this@shadowMap.toString()
|
||||||
|
override fun hashCode(): Int = this@shadowMap.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +100,8 @@ internal inline fun <E, R> MutableCollection<E>.shadowMap(
|
|||||||
override fun hasNext(): Boolean = delegate.hasNext()
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
override fun next(): R = delegate.next().let(transform)
|
override fun next(): R = delegate.next().let(transform)
|
||||||
override fun remove() = delegate.remove()
|
override fun remove() = delegate.remove()
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
||||||
@ -92,6 +112,8 @@ internal inline fun <E, R> MutableCollection<E>.shadowMap(
|
|||||||
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
||||||
override fun removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
|
override fun removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
|
||||||
override fun retainAll(elements: Collection<R>): Boolean = this@shadowMap.retainAll(elements.map(transformBack))
|
override fun retainAll(elements: Collection<R>): Boolean = this@shadowMap.retainAll(elements.map(transformBack))
|
||||||
|
override fun toString(): String = this@shadowMap.toString()
|
||||||
|
override fun hashCode(): Int = this@shadowMap.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +134,8 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
|
|||||||
override fun hasNext(): Boolean = delegate.hasNext()
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
override fun next(): R = delegate.next().let(transform)
|
override fun next(): R = delegate.next().let(transform)
|
||||||
override fun remove() = delegate.remove()
|
override fun remove() = delegate.remove()
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastIndexOf(element: R): Int = this@shadowMap.indexOfLast { it.let(transform) == element }
|
override fun lastIndexOf(element: R): Int = this@shadowMap.indexOfLast { it.let(transform) == element }
|
||||||
@ -134,6 +158,8 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
|
|||||||
override fun next(): R = delegate.next().let(transform)
|
override fun next(): R = delegate.next().let(transform)
|
||||||
override fun remove() = delegate.remove()
|
override fun remove() = delegate.remove()
|
||||||
override fun set(element: R) = delegate.set(element.let(transformBack))
|
override fun set(element: R) = delegate.set(element.let(transformBack))
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun listIterator(index: Int): MutableListIterator<R> = object : MutableListIterator<R> {
|
override fun listIterator(index: Int): MutableListIterator<R> = object : MutableListIterator<R> {
|
||||||
@ -147,6 +173,8 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
|
|||||||
override fun next(): R = delegate.next().let(transform)
|
override fun next(): R = delegate.next().let(transform)
|
||||||
override fun remove() = delegate.remove()
|
override fun remove() = delegate.remove()
|
||||||
override fun set(element: R) = delegate.set(element.let(transformBack))
|
override fun set(element: R) = delegate.set(element.let(transformBack))
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
||||||
@ -158,6 +186,9 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
|
|||||||
|
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<R> =
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<R> =
|
||||||
this@shadowMap.subList(fromIndex, toIndex).map(transform).toMutableList()
|
this@shadowMap.subList(fromIndex, toIndex).map(transform).toMutableList()
|
||||||
|
|
||||||
|
override fun toString(): String = this@shadowMap.toString()
|
||||||
|
override fun hashCode(): Int = this@shadowMap.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +208,8 @@ internal inline fun <E, R> MutableSet<E>.shadowMap(
|
|||||||
override fun hasNext(): Boolean = delegate.hasNext()
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
override fun next(): R = delegate.next().let(transform)
|
override fun next(): R = delegate.next().let(transform)
|
||||||
override fun remove() = delegate.remove()
|
override fun remove() = delegate.remove()
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
||||||
@ -186,6 +219,8 @@ internal inline fun <E, R> MutableSet<E>.shadowMap(
|
|||||||
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
||||||
override fun removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
|
override fun removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
|
||||||
override fun retainAll(elements: Collection<R>): Boolean = this@shadowMap.retainAll(elements.map(transformBack))
|
override fun retainAll(elements: Collection<R>): Boolean = this@shadowMap.retainAll(elements.map(transformBack))
|
||||||
|
override fun toString(): String = this@shadowMap.toString()
|
||||||
|
override fun hashCode(): Int = this@shadowMap.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +237,8 @@ internal inline fun <T> dynamicList(crossinline supplier: () -> List<T>): List<T
|
|||||||
override fun listIterator(): ListIterator<T> = supplier().listIterator()
|
override fun listIterator(): ListIterator<T> = supplier().listIterator()
|
||||||
override fun listIterator(index: Int): ListIterator<T> = supplier().listIterator(index)
|
override fun listIterator(index: Int): ListIterator<T> = supplier().listIterator(index)
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): List<T> = supplier().subList(fromIndex, toIndex)
|
override fun subList(fromIndex: Int, toIndex: Int): List<T> = supplier().subList(fromIndex, toIndex)
|
||||||
|
override fun toString(): String = supplier().toString()
|
||||||
|
override fun hashCode(): Int = supplier().hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,6 +249,8 @@ internal inline fun <T> dynamicSet(crossinline supplier: () -> Set<T>): Set<T> {
|
|||||||
override fun containsAll(elements: Collection<T>): Boolean = supplier().containsAll(elements)
|
override fun containsAll(elements: Collection<T>): Boolean = supplier().containsAll(elements)
|
||||||
override fun isEmpty(): Boolean = supplier().isEmpty()
|
override fun isEmpty(): Boolean = supplier().isEmpty()
|
||||||
override fun iterator(): Iterator<T> = supplier().iterator()
|
override fun iterator(): Iterator<T> = supplier().iterator()
|
||||||
|
override fun toString(): String = supplier().toString()
|
||||||
|
override fun hashCode(): Int = supplier().hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,6 +278,8 @@ internal inline fun <T> dynamicMutableList(crossinline supplier: () -> MutableLi
|
|||||||
override fun retainAll(elements: Collection<T>): Boolean = supplier().retainAll(elements)
|
override fun retainAll(elements: Collection<T>): Boolean = supplier().retainAll(elements)
|
||||||
override fun set(index: Int, element: T): T = supplier().set(index, element)
|
override fun set(index: Int, element: T): T = supplier().set(index, element)
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> = supplier().subList(fromIndex, toIndex)
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> = supplier().subList(fromIndex, toIndex)
|
||||||
|
override fun toString(): String = supplier().toString()
|
||||||
|
override fun hashCode(): Int = supplier().hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,6 +297,8 @@ internal inline fun <T> dynamicMutableSet(crossinline supplier: () -> MutableSet
|
|||||||
override fun remove(element: T): Boolean = supplier().remove(element)
|
override fun remove(element: T): Boolean = supplier().remove(element)
|
||||||
override fun removeAll(elements: Collection<T>): Boolean = supplier().removeAll(elements)
|
override fun removeAll(elements: Collection<T>): Boolean = supplier().removeAll(elements)
|
||||||
override fun retainAll(elements: Collection<T>): Boolean = supplier().retainAll(elements)
|
override fun retainAll(elements: Collection<T>): Boolean = supplier().retainAll(elements)
|
||||||
|
override fun toString(): String = supplier().toString()
|
||||||
|
override fun hashCode(): Int = supplier().hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +316,8 @@ internal inline fun <K, V> MutableMap<K, V>.observable(crossinline onChanged: ()
|
|||||||
override fun put(key: K, value: V): V? = this@observable.put(key, value).also { onChanged() }
|
override fun put(key: K, value: V): V? = this@observable.put(key, value).also { onChanged() }
|
||||||
override fun putAll(from: Map<out K, V>) = this@observable.putAll(from).also { onChanged() }
|
override fun putAll(from: Map<out K, V>) = this@observable.putAll(from).also { onChanged() }
|
||||||
override fun remove(key: K): V? = this@observable.remove(key).also { onChanged() }
|
override fun remove(key: K): V? = this@observable.remove(key).also { onChanged() }
|
||||||
|
override fun toString(): String = this@observable.toString()
|
||||||
|
override fun hashCode(): Int = this@observable.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +334,8 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
|||||||
override fun hasNext(): Boolean = delegate.hasNext()
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
override fun next(): T = delegate.next()
|
override fun next(): T = delegate.next()
|
||||||
override fun remove() = delegate.remove().also { onChanged() }
|
override fun remove() = delegate.remove().also { onChanged() }
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastIndexOf(element: T): Int = this@observable.lastIndexOf(element)
|
override fun lastIndexOf(element: T): Int = this@observable.lastIndexOf(element)
|
||||||
@ -310,6 +357,8 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
|||||||
override fun next(): T = delegate.next()
|
override fun next(): T = delegate.next()
|
||||||
override fun remove() = delegate.remove().also { onChanged() }
|
override fun remove() = delegate.remove().also { onChanged() }
|
||||||
override fun set(element: T) = delegate.set(element).also { onChanged() }
|
override fun set(element: T) = delegate.set(element).also { onChanged() }
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun listIterator(index: Int): MutableListIterator<T> = object : MutableListIterator<T> {
|
override fun listIterator(index: Int): MutableListIterator<T> = object : MutableListIterator<T> {
|
||||||
@ -323,6 +372,8 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
|||||||
override fun next(): T = delegate.next()
|
override fun next(): T = delegate.next()
|
||||||
override fun remove() = delegate.remove().also { onChanged() }
|
override fun remove() = delegate.remove().also { onChanged() }
|
||||||
override fun set(element: T) = delegate.set(element).also { onChanged() }
|
override fun set(element: T) = delegate.set(element).also { onChanged() }
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(element: T): Boolean = this@observable.remove(element).also { onChanged() }
|
override fun remove(element: T): Boolean = this@observable.remove(element).also { onChanged() }
|
||||||
@ -335,6 +386,8 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
|||||||
|
|
||||||
override fun set(index: Int, element: T): T = this@observable.set(index, element).also { onChanged() }
|
override fun set(index: Int, element: T): T = this@observable.set(index, element).also { onChanged() }
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> = this@observable.subList(fromIndex, toIndex)
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> = this@observable.subList(fromIndex, toIndex)
|
||||||
|
override fun toString(): String = this@observable.toString()
|
||||||
|
override fun hashCode(): Int = this@observable.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,6 +402,8 @@ internal inline fun <T> MutableCollection<T>.observable(crossinline onChanged: (
|
|||||||
override fun hasNext(): Boolean = delegate.hasNext()
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
override fun next(): T = delegate.next()
|
override fun next(): T = delegate.next()
|
||||||
override fun remove() = delegate.remove().also { onChanged() }
|
override fun remove() = delegate.remove().also { onChanged() }
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
||||||
@ -360,6 +415,9 @@ internal inline fun <T> MutableCollection<T>.observable(crossinline onChanged: (
|
|||||||
|
|
||||||
override fun retainAll(elements: Collection<T>): Boolean =
|
override fun retainAll(elements: Collection<T>): Boolean =
|
||||||
this@observable.retainAll(elements).also { onChanged() }
|
this@observable.retainAll(elements).also { onChanged() }
|
||||||
|
|
||||||
|
override fun toString(): String = this@observable.toString()
|
||||||
|
override fun hashCode(): Int = this@observable.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,6 +432,8 @@ internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Un
|
|||||||
override fun hasNext(): Boolean = delegate.hasNext()
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
override fun next(): T = delegate.next()
|
override fun next(): T = delegate.next()
|
||||||
override fun remove() = delegate.remove().also { onChanged() }
|
override fun remove() = delegate.remove().also { onChanged() }
|
||||||
|
override fun toString(): String = delegate.toString()
|
||||||
|
override fun hashCode(): Int = delegate.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
||||||
@ -385,6 +445,9 @@ internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Un
|
|||||||
|
|
||||||
override fun retainAll(elements: Collection<T>): Boolean =
|
override fun retainAll(elements: Collection<T>): Boolean =
|
||||||
this@observable.retainAll(elements).also { onChanged() }
|
this@observable.retainAll(elements).also { onChanged() }
|
||||||
|
|
||||||
|
override fun toString(): String = this@observable.toString()
|
||||||
|
override fun hashCode(): Int = this@observable.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ import kotlin.reflect.full.findAnnotation
|
|||||||
|
|
||||||
internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
|
internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
|
||||||
|
|
||||||
|
internal fun Int.isOdd() = this and 0b1 != 0
|
||||||
|
|
||||||
internal inline fun <E> KSerializer<E>.bind(
|
internal inline fun <E> KSerializer<E>.bind(
|
||||||
crossinline setter: (E) -> Unit,
|
crossinline setter: (E) -> Unit,
|
||||||
crossinline getter: () -> E
|
crossinline getter: () -> E
|
||||||
|
@ -9,21 +9,121 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.setting
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
import net.mamoe.yamlkt.Yaml
|
import kotlinx.serialization.UnstableDefault
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertSame
|
||||||
|
|
||||||
internal class SettingTest {
|
internal class SettingTest {
|
||||||
|
|
||||||
class MySetting : Setting() {
|
class MySetting : Setting() {
|
||||||
val int by value(1)
|
var int by value(1)
|
||||||
val map by valueReified(mapOf("" to ""))
|
val map by valueReified(mapOf("" to ""))
|
||||||
val map2 by valueReified(mapOf("" to mapOf("" to mapOf("" to ""))))
|
val map2 by valueReified(mutableMapOf("" to mutableMapOf("" to "")))
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableDefault::class)
|
||||||
|
private val jsonPrettyPrint = Json(JsonConfiguration(prettyPrint = true))
|
||||||
|
private val json = Json(JsonConfiguration.Stable)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testStringify() {
|
||||||
|
val setting = MySetting()
|
||||||
|
|
||||||
|
var string = json.stringify(setting.updaterSerializer, Unit)
|
||||||
|
assertEquals("""{"int":1,"map":{},"map2":{}}""", string)
|
||||||
|
|
||||||
|
setting.int = 2
|
||||||
|
|
||||||
|
string = json.stringify(setting.updaterSerializer, Unit)
|
||||||
|
assertEquals("""{"int":2,"map":{},"map2":{}}""", string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPrimitive() {
|
fun testParseUpdate() {
|
||||||
val setting = MySetting()
|
val setting = MySetting()
|
||||||
val string = Yaml.nonStrict.stringify(setting.updaterSerializer, Unit)
|
|
||||||
println(string)
|
assertEquals(1, setting.int)
|
||||||
|
|
||||||
|
json.parse(
|
||||||
|
setting.updaterSerializer, """
|
||||||
|
{"int":3,"map":{},"map2":{}}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(3, setting.int)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNestedParseUpdate() {
|
||||||
|
val setting = MySetting()
|
||||||
|
|
||||||
|
fun delegation() = setting.map
|
||||||
|
|
||||||
|
val refBefore = setting.map
|
||||||
|
fun reference() = refBefore
|
||||||
|
|
||||||
|
assertEquals(mapOf(), delegation()) // delegation
|
||||||
|
|
||||||
|
json.parse(
|
||||||
|
setting.updaterSerializer, """
|
||||||
|
{"int":1,"map":{"t":"test"},"map2":{}}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(mapOf("t" to "test").toString(), delegation().toString())
|
||||||
|
assertEquals(mapOf("t" to "test").toString(), reference().toString())
|
||||||
|
|
||||||
|
assertSame(reference(), delegation()) // check shadowing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDeepNestedParseUpdate() {
|
||||||
|
val setting = MySetting()
|
||||||
|
|
||||||
|
fun delegation() = setting.map2
|
||||||
|
|
||||||
|
val refBefore = setting.map2
|
||||||
|
fun reference() = refBefore
|
||||||
|
|
||||||
|
assertEquals(mutableMapOf(), delegation()) // delegation
|
||||||
|
|
||||||
|
json.parse(
|
||||||
|
setting.updaterSerializer, """
|
||||||
|
{"int":1,"map":{},"map2":{"t":{"f":"test"}}}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(mapOf("t" to mapOf("f" to "test")).toString(), delegation().toString())
|
||||||
|
assertEquals(mapOf("t" to mapOf("f" to "test")).toString(), reference().toString())
|
||||||
|
|
||||||
|
assertSame(reference(), delegation()) // check shadowing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDeepNestedTrackingParseUpdate() {
|
||||||
|
val setting = MySetting()
|
||||||
|
|
||||||
|
setting.map2["t"] = mutableMapOf()
|
||||||
|
|
||||||
|
fun delegation() = setting.map2["t"]!!
|
||||||
|
|
||||||
|
val refBefore = setting.map2["t"]!!
|
||||||
|
fun reference() = refBefore
|
||||||
|
|
||||||
|
assertEquals(mutableMapOf(), delegation()) // delegation
|
||||||
|
|
||||||
|
json.parse(
|
||||||
|
setting.updaterSerializer, """
|
||||||
|
{"int":1,"map":{},"map2":{"t":{"f":"test"}}}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(mapOf("f" to "test").toString(), delegation().toString())
|
||||||
|
assertEquals(mapOf("f" to "test").toString(), reference().toString())
|
||||||
|
|
||||||
|
assertSame(reference(), delegation()) // check shadowing
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user