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:
Him188 2020-06-24 03:45:27 +08:00
parent 70b9b012e1
commit 9a91c9b2a7
11 changed files with 866 additions and 120 deletions

View File

@ -22,9 +22,7 @@ object ValueSettingCodegen {
object PrimitiveValuesCodegen : RegionCodegen("Value.kt"), DefaultInvoke {
@JvmStatic
fun main(args: Array<String>) = super.startIndependent()
override val defaultInvokeArgs: List<KtType>
get() = KtPrimitives + KtString
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
@Suppress("ClassName")
@ -42,7 +40,6 @@ object ValueSettingCodegen {
object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
@JvmStatic
fun main(args: Array<String>) = super.startIndependent()
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
@ -60,14 +57,12 @@ object ValueSettingCodegen {
object PrimitiveValuesImplCodegen : RegionCodegen("_PrimitiveValueDeclarations.kt"), DefaultInvoke {
@JvmStatic
fun main(args: Array<String>) = super.startIndependent()
override val defaultInvokeArgs: List<KtType>
get() = KtPrimitives + KtString
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
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(default: ${ktType.standardName}) {
_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 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 deserialize(decoder: Decoder) {
value = ${ktType.standardName}.serializer().deserialize(decoder)
final override fun deserialize(decoder: Decoder) = setValueBySerializer(${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 {
@JvmStatic
fun main(args: Array<String>) = super.startIndependent()
override val defaultInvokeArgs: List<KtType>
get() = KtPrimitives + KtString
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
appendKCode(
@ -127,9 +125,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
object Setting_valueImplPrimitiveCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
@JvmStatic
fun main(args: Array<String>) = super.startIndependent()
override val defaultInvokeArgs: List<KtType>
get() = KtPrimitives + KtString
override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
override fun StringBuilder.apply(ktType: KtType) {
appendKCode(

View File

@ -15,6 +15,7 @@ import kotlinx.serialization.*
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import net.mamoe.mirai.console.setting.internal.cast
import net.mamoe.mirai.console.setting.internal.isOdd
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
import net.mamoe.mirai.console.setting.internal.valueImpl
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.ListSerialization.FLOW_SEQUENCE
import net.mamoe.yamlkt.YamlConfiguration.MapSerialization.FLOW_MAP
import java.util.*
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KProperty
import kotlin.reflect.KType
@ -39,7 +40,7 @@ abstract class Setting : SettingImpl() {
property: KProperty<*>
): SerializerAwareValue<T> {
val name = property.serialName
valueNodes.put(name, Node(name, this, this.serializer))
valueNodes.add(Node(name, this, this.serializer))
return this
}
@ -55,29 +56,82 @@ internal val KProperty<*>.serialName: String get() = this.findAnnotation<SerialN
*/
// TODO move to internal package.
internal abstract class SettingImpl {
internal fun findNodeInstance(name: String): Node<*>? = valueNodes[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 value: Value<T>,
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 {
val actual = MapSerializer(String.serializer(), String.serializer())
object : KSerializer<Unit> {
override val descriptor: SerialDescriptor
get() = actual.descriptor
override val descriptor: SerialDescriptor get() = settingUpdaterSerializerDescriptor
@Suppress("UNCHECKED_CAST")
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) {
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 {
private val ABSENT_STUB = Any()
private val settingUpdaterSerializerTypeArguments = arrayOf(String.serializer(), YamlNullableDynamicSerializer)
private val settingUpdaterSerializerDescriptor =
MapSerializer(settingUpdaterSerializerTypeArguments[0], settingUpdaterSerializerTypeArguments[1]).descriptor
val allFlow = Yaml(
YamlConfiguration(
nonStrictNullability = true,
@ -124,7 +185,8 @@ fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
@LowPriorityInOverloadResolution
@MiraiExperimentalAPI
@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
fun <T> Setting.valueFromKType(type: KType): SerializableValue<T> = valueFromKTypeImpl(type).cast()
fun <T> Setting.valueFromKType(type: KType): SerializerAwareValue<T> = valueFromKTypeImpl(type).cast()

View File

@ -15,6 +15,7 @@ import kotlinx.serialization.BinaryFormat
import kotlinx.serialization.KSerializer
import kotlinx.serialization.StringFormat
import net.mamoe.mirai.console.setting.internal.map
import net.mamoe.mirai.console.setting.internal.setValueBySerializer
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import kotlin.reflect.KProperty
@ -36,17 +37,22 @@ interface Value<T> {
* Typically returned by [Setting.value] functions.
*/
class SerializableValue<T>(
delegate: Value<T>,
private val delegate: Value<T>,
/**
* The serializer used to update and dump [delegate]
*/
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(
serializer: KSerializer<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>
//// endregion PrimitiveValues CODEGEN ////

View File

@ -25,7 +25,7 @@ internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>):
internal abstract class CompositeSetValueImpl<T>(
tToValue: (T) -> Value<T> // should override onChanged
) : CompositeSetValue<T> {
) : CompositeSetValue<T>, AbstractValueImpl<Set<T>>() {
private val internalSet: MutableSet<Value<T>> = mutableSetOf()
private var _value: Set<T> = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() }
@ -34,12 +34,30 @@ internal abstract class CompositeSetValueImpl<T>(
get() = _value
set(v) {
if (_value != v) {
@Suppress("LocalVariableName")
val _value = _value as MutableSet<T>
_value.clear()
_value.addAll(v)
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()
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>(
tToValue: (T) -> Value<T> // should override onChanged
) : CompositeListValue<T> {
) : CompositeListValue<T>, AbstractValueImpl<List<T>>() {
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>
get() = _value
set(v) {
if (_value != v) {
@Suppress("LocalVariableName")
val _value = _value as MutableList<T>
_value.clear()
_value.addAll(v)
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()
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
@ -77,28 +113,85 @@ internal fun <K, V> Setting.createCompositeMapValueImpl(
vToValue: (V) -> Value<V>
): CompositeMapValueImpl<K, V> {
return object : CompositeMapValueImpl<K, V>(kToValue, vToValue) {
override fun onChanged() {
this@createCompositeMapValueImpl.onValueChanged(this)
}
override fun onChanged() = this@createCompositeMapValueImpl.onValueChanged(this)
}
}
internal abstract class CompositeMapValueImpl<K, V>(
kToValue: (K) -> Value<K>, // 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 var _value: Map<K, V> =
private var _value: MutableMap<K, V> =
internalList.shadowMap({ it.value }, kToValue, { it.value }, vToValue).observable { onChanged() }
override var value: Map<K, V>
get() = _value
set(v) {
if (_value != v) {
@Suppress("LocalVariableName")
val _value = _value
_value.clear()
_value.putAll(v)
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()
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
}

View File

@ -13,7 +13,7 @@ package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.*
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.serializableValueWith
import net.mamoe.mirai.console.setting.valueFromKType
@ -22,43 +22,52 @@ import net.mamoe.yamlkt.YamlNullableDynamicSerializer
import kotlin.reflect.KClass
import kotlin.reflect.KType
private val primitiveCollectionsImplemented by lazy {
false
}
@PublishedApi
@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST")
internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
internal fun Setting.valueFromKTypeImpl(type: KType): SerializerAwareValue<*> {
val classifier = type.classifier
require(classifier is KClass<*>)
if (classifier.isPrimitiveOrBuiltInSerializableValue()) {
TODO("是基础类型, 可以直接创建 ValueImpl. ")
return valueImplPrimitive(classifier) as SerializerAwareValue<*>
}
// 复合类型
when (classifier) {
Map::class -> {
MutableMap::class,
Map::class
-> {
val keyClass = type.arguments[0].type?.classifier
require(keyClass is KClass<*>)
val valueClass = type.arguments[1].type?.classifier
require(valueClass is KClass<*>)
if (keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
if (primitiveCollectionsImplemented && keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
// PrimitiveIntIntMap
// ...
TODO()
} else {
return createCompositeMapValueImpl<Any?, Any?>(
kToValue = { valueFromKType(type.arguments[0].type!!) },
vToValue = { valueFromKType(type.arguments[1].type!!) }
kToValue = { k -> valueFromKType<Any?>(type.arguments[0].type!!).also { it.value = k } },
vToValue = { v -> valueFromKType<Any?>(type.arguments[1].type!!).also { it.value = v } }
).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
require(elementClass is KClass<*>)
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
if (primitiveCollectionsImplemented && elementClass.isPrimitiveOrBuiltInSerializableValue()) {
// PrimitiveIntList
// ...
TODO()
@ -67,11 +76,13 @@ internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
.serializableValueWith(serializerMirai(type) as KSerializer<List<Any?>>)
}
}
Set::class -> {
MutableSet::class,
Set::class
-> {
val elementClass = type.arguments[0].type?.classifier
require(elementClass is KClass<*>)
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
if (primitiveCollectionsImplemented && elementClass.isPrimitiveOrBuiltInSerializableValue()) {
// PrimitiveIntSet
// ...
TODO()
@ -85,7 +96,6 @@ internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
}
internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
return false // debug
when (this) {
Byte::class, Short::class, Int::class, Long::class,
Boolean::class,

View File

@ -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 ////

View File

@ -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 ////

View File

@ -12,10 +12,11 @@ package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.builtins.serializer
import net.mamoe.mirai.console.setting.SerializerAwareValue
import net.mamoe.mirai.console.setting.Setting
import kotlin.reflect.KClass
internal object BuiltInSerializerConstants {
//// region BuiltInSerializerConstants primitives CODEGEN ////
//// region BuiltInSerializerConstantsPrimitives CODEGEN ////
@JvmStatic
val ByteSerializerDescriptor = Byte.serializer().descriptor
@ -44,13 +45,55 @@ internal object BuiltInSerializerConstants {
@JvmStatic
val StringSerializerDescriptor = String.serializer().descriptor
//// endregion BuiltInSerializerConstants primitives CODEGEN ////
//// endregion BuiltInSerializerConstantsPrimitives 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> {
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 ////

View File

@ -16,6 +16,8 @@ import kotlinx.serialization.serializer
import net.mamoe.yamlkt.Yaml
import kotlin.reflect.KClass
// TODO: 2020/6/24 优化性能: 引入一个 comparator 之类来替代将 Int 包装为 Value<Int> 后进行 containsKey 比较的方法
internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
crossinline kTransform: (K) -> KR,
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 fun setValue(newValue: VR): VR =
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
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 fun setValue(newValue: V): V =
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 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 next(): R = delegate.next().let(transform)
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))
@ -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 removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
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 next(): R = delegate.next().let(transform)
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 }
@ -134,6 +158,8 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
override fun next(): R = delegate.next().let(transform)
override fun remove() = delegate.remove()
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> {
@ -147,6 +173,8 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
override fun next(): R = delegate.next().let(transform)
override fun remove() = delegate.remove()
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 }
@ -158,6 +186,9 @@ internal inline fun <E, R> MutableList<E>.shadowMap(
override fun subList(fromIndex: Int, toIndex: Int): MutableList<R> =
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 next(): R = delegate.next().let(transform)
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))
@ -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 removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
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(index: Int): ListIterator<T> = supplier().listIterator(index)
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 isEmpty(): Boolean = supplier().isEmpty()
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 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 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 removeAll(elements: Collection<T>): Boolean = supplier().removeAll(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 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 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 next(): T = delegate.next()
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)
@ -310,6 +357,8 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
override fun next(): T = delegate.next()
override fun remove() = delegate.remove().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> {
@ -323,6 +372,8 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
override fun next(): T = delegate.next()
override fun remove() = delegate.remove().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() }
@ -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 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 next(): T = delegate.next()
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() }
@ -360,6 +415,9 @@ internal inline fun <T> MutableCollection<T>.observable(crossinline onChanged: (
override fun retainAll(elements: Collection<T>): Boolean =
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 next(): T = delegate.next()
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() }
@ -385,6 +445,9 @@ internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Un
override fun retainAll(elements: Collection<T>): Boolean =
this@observable.retainAll(elements).also { onChanged() }
override fun toString(): String = this@observable.toString()
override fun hashCode(): Int = this@observable.hashCode()
}
}

View File

@ -15,6 +15,8 @@ import kotlin.reflect.full.findAnnotation
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(
crossinline setter: (E) -> Unit,
crossinline getter: () -> E

View File

@ -9,21 +9,121 @@
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 kotlin.test.assertEquals
import kotlin.test.assertSame
internal class SettingTest {
class MySetting : Setting() {
val int by value(1)
var int by value(1)
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
fun testPrimitive() {
fun testParseUpdate() {
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
}
}