mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Implement composite Values
This commit is contained in:
parent
7ac1d94db9
commit
4ce4c025ee
@ -38,7 +38,7 @@ internal object MiraiConsoleInitializer {
|
||||
|
||||
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
||||
@JvmStatic
|
||||
val buildDate: Date = Date(1592720608995) // 2020-06-21 14:23:28
|
||||
val buildDate: Date = Date(1592723625351) // 2020-06-21 15:13:45
|
||||
const val version: String = "0.5.1"
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,14 @@ package net.mamoe.mirai.console.setting
|
||||
|
||||
import net.mamoe.mirai.console.setting.internal.cast
|
||||
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import kotlin.internal.LowPriorityInOverloadResolution
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
|
||||
// TODO: 2020/6/21 move to JvmPlugin to inherit SettingStorage and CoroutineScope for saving
|
||||
// Shows public APIs such as deciding when to auto-save.
|
||||
abstract class Setting : SettingImpl()
|
||||
|
||||
@ -37,6 +40,13 @@ internal abstract class SettingImpl {
|
||||
private val valueNodes: List<Node<*>> = kotlin.run {
|
||||
TODO("reflection")
|
||||
}
|
||||
|
||||
/**
|
||||
* flatten
|
||||
*/
|
||||
internal fun onValueChanged(value: Value<*>) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,7 +60,7 @@ fun Setting.value(value: Int): IntValue = TODO("codegen")
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [Value] with [default].
|
||||
* Creates a [Value] with reified type.
|
||||
*
|
||||
* @param T reified param type T.
|
||||
* Supports only primitives, Kotlin built-in collections,
|
||||
@ -59,4 +69,7 @@ fun Setting.value(value: Int): IntValue = TODO("codegen")
|
||||
*/
|
||||
@LowPriorityInOverloadResolution
|
||||
@OptIn(ExperimentalStdlibApi::class) // stable in 1.4
|
||||
inline fun <reified T> Setting.value(default: T): Value<T> = valueFromKTypeImpl(typeOf<T>()).cast()
|
||||
inline fun <reified T> Setting.valueReified(default: T): Value<T> = valueFromKTypeImpl(typeOf<T>()).cast()
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
fun <T> Setting.valueFromKType(type: KType): Value<T> = valueFromKTypeImpl(type).cast()
|
@ -102,28 +102,29 @@ interface StringValue : PrimitiveValue<String>
|
||||
@MiraiExperimentalAPI
|
||||
interface CompositeValue<T> : Value<T>
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeListValue], [PrimitiveListValue].
|
||||
*/
|
||||
interface ListValue<T> : CompositeValue<List<T>>
|
||||
interface ListValue<E> : CompositeValue<List<E>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param T is not primitive types.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface CompositeListValue<T> : ListValue<Value<T>>
|
||||
interface CompositeListValue<E> : ListValue<E>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param T is not primitive types.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface PrimitiveListValue<T> : ListValue<T>
|
||||
interface PrimitiveListValue<E> : ListValue<E>
|
||||
|
||||
|
||||
//// region PrimitiveListValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntListValue<T> : PrimitiveListValue<T>
|
||||
interface PrimitiveLongListValue<T> : PrimitiveListValue<T>
|
||||
interface PrimitiveIntListValue : PrimitiveListValue<Int>
|
||||
interface PrimitiveLongListValue : PrimitiveListValue<Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveListValue CODEGEN ////
|
||||
@ -132,25 +133,25 @@ interface PrimitiveLongListValue<T> : PrimitiveListValue<T>
|
||||
/**
|
||||
* Superclass of [CompositeSetValue], [PrimitiveSetValue].
|
||||
*/
|
||||
interface SetValue<T> : CompositeValue<Set<T>>
|
||||
interface SetValue<E> : CompositeValue<Set<E>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param T is not primitive types.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface CompositeSetValue<T> : SetValue<Value<T>>
|
||||
interface CompositeSetValue<E> : SetValue<E>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param T is not primitive types.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface PrimitiveSetValue<T> : SetValue<T>
|
||||
interface PrimitiveSetValue<E> : SetValue<E>
|
||||
|
||||
|
||||
//// region PrimitiveSetValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntSetValue<T> : PrimitiveSetValue<T>
|
||||
interface PrimitiveLongSetValue<T> : PrimitiveSetValue<T>
|
||||
interface PrimitiveIntSetValue : PrimitiveSetValue<Int>
|
||||
interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN ////
|
||||
@ -161,7 +162,7 @@ interface PrimitiveLongSetValue<T> : PrimitiveSetValue<T>
|
||||
*/
|
||||
interface MapValue<K, V> : CompositeValue<Map<K, V>>
|
||||
|
||||
interface CompositeMapValue<K, V> : MapValue<Value<K>, Value<V>>
|
||||
interface CompositeMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
interface PrimitiveMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import net.mamoe.mirai.console.setting.Setting
|
||||
import net.mamoe.mirai.console.setting.Value
|
||||
import net.mamoe.mirai.console.setting.valueFromKType
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
@ -31,21 +32,53 @@ internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> {
|
||||
|
||||
when {
|
||||
classifier == Map::class -> {
|
||||
val keyClass = type.arguments[0].type?.classifier
|
||||
require(keyClass is KClass<*>)
|
||||
|
||||
TODO()
|
||||
val valueClass = type.arguments[1].type?.classifier
|
||||
require(valueClass is KClass<*>)
|
||||
|
||||
if (keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
// PrimitiveIntIntMap
|
||||
// ...
|
||||
TODO()
|
||||
} else {
|
||||
return createCompositeMapValueImpl<Any?, Any?>(
|
||||
kToValue = { valueFromKType(type.arguments[0].type!!) },
|
||||
vToValue = { valueFromKType(type.arguments[1].type!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
classifier == List::class -> {
|
||||
val elementClass = type.arguments[0].type?.classifier
|
||||
require(elementClass is KClass<*>)
|
||||
|
||||
TODO()
|
||||
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
// PrimitiveIntList
|
||||
// ...
|
||||
TODO()
|
||||
} else {
|
||||
return createCompositeListValueImpl<Any?> { valueFromKType(type.arguments[0].type!!) }
|
||||
}
|
||||
}
|
||||
classifier == Set::class -> {
|
||||
TODO()
|
||||
val elementClass = type.arguments[0].type?.classifier
|
||||
require(elementClass is KClass<*>)
|
||||
|
||||
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
// PrimitiveIntSet
|
||||
// ...
|
||||
TODO()
|
||||
} else {
|
||||
return createCompositeSetValueImpl<Any?> { valueFromKType(type.arguments[0].type!!) }
|
||||
}
|
||||
}
|
||||
else -> error("Custom composite value is not supported yet (${classifier.qualifiedName})")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
|
||||
return false // debug
|
||||
when (this) {
|
||||
Byte::class, Short::class, Int::class, Long::class,
|
||||
Boolean::class,
|
||||
|
@ -11,9 +11,7 @@
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import net.mamoe.mirai.console.setting.CompositeListValue
|
||||
import net.mamoe.mirai.console.setting.IntValue
|
||||
import net.mamoe.mirai.console.setting.Value
|
||||
import net.mamoe.mirai.console.setting.*
|
||||
|
||||
internal abstract class IntValueImpl : IntValue {
|
||||
constructor()
|
||||
@ -35,13 +33,91 @@ internal abstract class IntValueImpl : IntValue {
|
||||
protected abstract fun onChanged()
|
||||
}
|
||||
|
||||
internal abstract class CompositeListValueImpl<T>(
|
||||
val tToValue: (T) -> Value<T>
|
||||
) : CompositeListValue<T> {
|
||||
private var _value: List<Value<T>> = mutableListOf()
|
||||
override var value: List<Value<T>>
|
||||
// type inference bug
|
||||
internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> {
|
||||
return object : CompositeSetValueImpl<T>(tToValue) {
|
||||
override fun onChanged() {
|
||||
this@createCompositeSetValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CompositeSetValueImpl<T>(
|
||||
tToValue: (T) -> Value<T> // should override onChanged
|
||||
) : CompositeSetValue<T> {
|
||||
private val internalSet: MutableSet<Value<T>> = mutableSetOf()
|
||||
|
||||
private var _value: Set<T> = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||
|
||||
override var value: Set<T>
|
||||
get() = _value
|
||||
set(v) {
|
||||
_value = v
|
||||
if (_value != v) {
|
||||
onChanged()
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
||||
|
||||
|
||||
// type inference bug
|
||||
internal fun <T> Setting.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> {
|
||||
return object : CompositeListValueImpl<T>(tToValue) {
|
||||
override fun onChanged() {
|
||||
this@createCompositeListValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CompositeListValueImpl<T>(
|
||||
tToValue: (T) -> Value<T> // should override onChanged
|
||||
) : CompositeListValue<T> {
|
||||
private val internalList: MutableList<Value<T>> = mutableListOf()
|
||||
|
||||
private var _value: List<T> = internalList.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||
|
||||
override var value: List<T>
|
||||
get() = _value
|
||||
set(v) {
|
||||
if (_value != v) {
|
||||
onChanged()
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
||||
|
||||
// workaround to a type inference bug
|
||||
internal fun <K, V> Setting.createCompositeMapValueImpl(
|
||||
kToValue: (K) -> Value<K>,
|
||||
vToValue: (V) -> Value<V>
|
||||
): CompositeMapValueImpl<K, V> {
|
||||
return object : CompositeMapValueImpl<K, V>(kToValue, vToValue) {
|
||||
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> {
|
||||
private val internalList: MutableMap<Value<K>, Value<V>> = mutableMapOf()
|
||||
|
||||
private var _value: Map<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) {
|
||||
onChanged()
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
@ -7,6 +7,8 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("DuplicatedCode")
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||
@ -14,7 +16,89 @@ import kotlinx.serialization.serializer
|
||||
import net.mamoe.yamlkt.Yaml
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal fun <E, R> MutableList<E>.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableList<R> {
|
||||
internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
||||
crossinline kTransform: (K) -> KR,
|
||||
crossinline kTransformBack: (KR) -> K,
|
||||
crossinline vTransform: (V) -> VR,
|
||||
crossinline vTransformBack: (VR) -> V
|
||||
): MutableMap<KR, VR> {
|
||||
return object : MutableMap<KR, VR> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
override fun containsKey(key: KR): Boolean = this@shadowMap.containsKey(key.let(kTransformBack))
|
||||
override fun containsValue(value: VR): Boolean = this@shadowMap.containsValue(value.let(vTransformBack))
|
||||
override fun get(key: KR): VR? = this@shadowMap[key.let(kTransformBack)]?.let(vTransform)
|
||||
override fun isEmpty(): Boolean = this@shadowMap.isEmpty()
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<KR, VR>>
|
||||
get() = this@shadowMap.entries.shadowMap(
|
||||
transform = { entry: MutableMap.MutableEntry<K, V> ->
|
||||
object : MutableMap.MutableEntry<KR, VR> {
|
||||
override val key: KR get() = entry.key.let(kTransform)
|
||||
override val value: VR get() = entry.value.let(vTransform)
|
||||
override fun setValue(newValue: VR): VR =
|
||||
entry.setValue(newValue.let(vTransformBack)).let(vTransform)
|
||||
}
|
||||
} as ((MutableMap.MutableEntry<K, V>) -> MutableMap.MutableEntry<KR, VR>), // type inference bug
|
||||
transformBack = { entry ->
|
||||
object : MutableMap.MutableEntry<K, V> {
|
||||
override val key: K get() = entry.key.let(kTransformBack)
|
||||
override val value: V get() = entry.value.let(vTransformBack)
|
||||
override fun setValue(newValue: V): V =
|
||||
entry.setValue(newValue.let(vTransform)).let(vTransformBack)
|
||||
}
|
||||
}
|
||||
)
|
||||
override val keys: MutableSet<KR>
|
||||
get() = this@shadowMap.keys.shadowMap(kTransform, kTransformBack)
|
||||
override val values: MutableCollection<VR>
|
||||
get() = this@shadowMap.values.shadowMap(vTransform, vTransformBack)
|
||||
|
||||
override fun clear() = this@shadowMap.clear()
|
||||
override fun put(key: KR, value: VR): VR? =
|
||||
this@shadowMap.put(key.let(kTransformBack), value.let(vTransformBack))?.let(vTransform)
|
||||
|
||||
override fun putAll(from: Map<out KR, VR>) {
|
||||
from.forEach { (kr, vr) ->
|
||||
this@shadowMap[kr.let(kTransformBack)] = vr.let(vTransformBack)
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(key: KR): VR? = this@shadowMap.remove(key.let(kTransformBack))?.let(vTransform)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <E, R> MutableCollection<E>.shadowMap(
|
||||
crossinline transform: (E) -> R,
|
||||
crossinline transformBack: (R) -> E
|
||||
): MutableCollection<R> {
|
||||
return object : MutableCollection<R> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
|
||||
override fun contains(element: R): Boolean = this@shadowMap.any { it.let(transform) == element }
|
||||
override fun containsAll(elements: Collection<R>): Boolean = elements.all(::contains)
|
||||
override fun isEmpty(): Boolean = this@shadowMap.isEmpty()
|
||||
override fun iterator(): MutableIterator<R> = object : MutableIterator<R> {
|
||||
private val delegate = this@shadowMap.iterator()
|
||||
override fun hasNext(): Boolean = delegate.hasNext()
|
||||
override fun next(): R = delegate.next().let(transform)
|
||||
override fun remove() = delegate.remove()
|
||||
}
|
||||
|
||||
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
||||
|
||||
override fun addAll(elements: Collection<R>): Boolean = this@shadowMap.addAll(elements.map(transformBack))
|
||||
override fun clear() = this@shadowMap.clear()
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <E, R> MutableList<E>.shadowMap(
|
||||
crossinline transform: (E) -> R,
|
||||
crossinline transformBack: (R) -> E
|
||||
): MutableList<R> {
|
||||
return object : MutableList<R> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
|
||||
@ -78,7 +162,10 @@ internal fun <E, R> MutableList<E>.shadowMap(transform: (E) -> R, transformBack:
|
||||
}
|
||||
|
||||
|
||||
internal fun <E, R> MutableSet<E>.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableSet<R> {
|
||||
internal inline fun <E, R> MutableSet<E>.shadowMap(
|
||||
crossinline transform: (E) -> R,
|
||||
crossinline transformBack: (R) -> E
|
||||
): MutableSet<R> {
|
||||
return object : MutableSet<R> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
|
||||
@ -102,7 +189,7 @@ internal fun <E, R> MutableSet<E>.shadowMap(transform: (E) -> R, transformBack:
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> dynamicList(supplier: () -> List<T>): List<T> {
|
||||
internal inline fun <T> dynamicList(crossinline supplier: () -> List<T>): List<T> {
|
||||
return object : List<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -118,7 +205,7 @@ internal fun <T> dynamicList(supplier: () -> List<T>): List<T> {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> dynamicSet(supplier: () -> Set<T>): Set<T> {
|
||||
internal inline fun <T> dynamicSet(crossinline supplier: () -> Set<T>): Set<T> {
|
||||
return object : Set<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -129,7 +216,7 @@ internal fun <T> dynamicSet(supplier: () -> Set<T>): Set<T> {
|
||||
}
|
||||
|
||||
|
||||
internal fun <T> dynamicMutableList(supplier: () -> MutableList<T>): MutableList<T> {
|
||||
internal inline fun <T> dynamicMutableList(crossinline supplier: () -> MutableList<T>): MutableList<T> {
|
||||
return object : MutableList<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -156,7 +243,7 @@ internal fun <T> dynamicMutableList(supplier: () -> MutableList<T>): MutableList
|
||||
}
|
||||
|
||||
|
||||
internal fun <T> dynamicMutableSet(supplier: () -> MutableSet<T>): MutableSet<T> {
|
||||
internal inline fun <T> dynamicMutableSet(crossinline supplier: () -> MutableSet<T>): MutableSet<T> {
|
||||
return object : MutableSet<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -172,6 +259,23 @@ internal fun <T> dynamicMutableSet(supplier: () -> MutableSet<T>): MutableSet<T>
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST", "USELESS_CAST") // type inference bug
|
||||
internal inline fun <K, V> MutableMap<K, V>.observable(crossinline onChanged: () -> Unit): MutableMap<K, V> {
|
||||
return object : MutableMap<K, V>, Map<K, V> by (this as Map<K, V>) {
|
||||
override val keys: MutableSet<K>
|
||||
get() = this@observable.keys.observable(onChanged)
|
||||
override val values: MutableCollection<V>
|
||||
get() = this@observable.values.observable(onChanged)
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() = this@observable.entries.observable(onChanged)
|
||||
|
||||
override fun clear() = this@observable.clear().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 remove(key: K): V? = this@observable.remove(key).also { onChanged() }
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> Unit): MutableList<T> {
|
||||
return object : MutableList<T> {
|
||||
override val size: Int get() = this@observable.size
|
||||
@ -234,6 +338,31 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T> MutableCollection<T>.observable(crossinline onChanged: () -> Unit): MutableCollection<T> {
|
||||
return object : MutableCollection<T> {
|
||||
override val size: Int get() = this@observable.size
|
||||
override fun contains(element: T): Boolean = this@observable.contains(element)
|
||||
override fun containsAll(elements: Collection<T>): Boolean = this@observable.containsAll(elements)
|
||||
override fun isEmpty(): Boolean = this@observable.isEmpty()
|
||||
override fun iterator(): MutableIterator<T> = object : MutableIterator<T> {
|
||||
private val delegate = this@observable.iterator()
|
||||
override fun hasNext(): Boolean = delegate.hasNext()
|
||||
override fun next(): T = delegate.next()
|
||||
override fun remove() = delegate.remove().also { onChanged() }
|
||||
}
|
||||
|
||||
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
||||
override fun addAll(elements: Collection<T>): Boolean = this@observable.addAll(elements).also { onChanged() }
|
||||
override fun clear() = this@observable.clear().also { onChanged() }
|
||||
override fun remove(element: T): Boolean = this@observable.remove(element).also { onChanged() }
|
||||
override fun removeAll(elements: Collection<T>): Boolean =
|
||||
this@observable.removeAll(elements).also { onChanged() }
|
||||
|
||||
override fun retainAll(elements: Collection<T>): Boolean =
|
||||
this@observable.retainAll(elements).also { onChanged() }
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Unit): MutableSet<T> {
|
||||
return object : MutableSet<T> {
|
||||
override val size: Int get() = this@observable.size
|
||||
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class SettingTest {
|
||||
|
||||
@Test
|
||||
fun testPrimitive() {
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user