diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt new file mode 100644 index 000000000..c6d68e2cf --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS") + +package net.mamoe.mirai.console.setting + +import net.mamoe.mirai.console.setting.internal.cast +import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl +import kotlin.internal.LowPriorityInOverloadResolution +import kotlin.reflect.KProperty +import kotlin.reflect.typeOf + + +// Shows public APIs such as deciding when to auto-save. +abstract class Setting : SettingImpl() + +/** + * Internal implementation for [Setting] including: + * - Reflection on Kotlin properties and Java fields + * - Auto-saving + */ +// TODO move to internal package. +internal abstract class SettingImpl { + private class Node( + val property: KProperty, + val value: Value, + val serializer: ValueSerializer + ) + + private val valueNodes: List> = kotlin.run { + TODO("reflection") + } +} + + +//// region Setting.value primitives CODEGEN START //// + +// TODO: 2020/6/19 CODEGEN + +fun Setting.value(value: Int): IntValue = TODO("codegen") + +//// endregion Setting.value primitives CODEGEN END //// + + +/** + * Creates a [Value] with [default]. + * + * @param T reified param type T. + * Supports only primitives, Kotlin built-in collections, + * and classes that are serializable with Kotlinx.serialization + * (typically annotated with [kotlinx.serialization.Serializable]) + */ +@LowPriorityInOverloadResolution +@OptIn(ExperimentalStdlibApi::class) // stable in 1.4 +inline fun Setting.value(default: T): Value = valueFromKTypeImpl(typeOf()).cast() \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt new file mode 100644 index 000000000..cdedff4b1 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -0,0 +1,142 @@ +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") + +package net.mamoe.mirai.console.setting + +import kotlinx.serialization.KSerializer +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.typeOf + +/** + * Represents a observable, immutable value wrapping. + * + * The value can be modified by delegation just like Kotlin's `var`, however it can also be done by the user, e.g. changing using the UI frontend. + * + * Some frequently used types are specially treated with performance enhancement by codegen. + * + * @see PrimitiveValue + * @see CompositeValue + */ +interface Value { + var value: T +} + +/** + * The serializer for a specific kind of [Value]. + */ +typealias ValueSerializer = KSerializer> + +/** + * Represents a observable *primitive* value wrapping. + * + * 8 types that are considered *primitive*: + * - Integers: [Byte], [Short], [Int], [Long] + * - Floating: [Float], [Double] + * - [Boolean] + * - [Char], [String] + * + * Note: The values are actually *boxed* because of the generic type T. + * *Primitive* indicates only it is one of the 8 types mentioned above. + */ +interface PrimitiveValue : Value + +interface MutablePrimitiveValue : Value + + +//// region PrimitiveValue CODEGEN START //// + +// TODO: 2020/6/19 CODEGEN + +/** + * Represents a non-null [Int] value. + */ +interface IntValue : PrimitiveValue + +//// endregion PrimitiveValue CODEGEN END //// + + +@MiraiExperimentalAPI +interface CompositeValue : Value + +/** + * Superclass of [CompositeListValue], [PrimitiveListValue]. + */ +interface ListValue : CompositeValue> + +/** + * Elements can by anything, wrapped as [Value]. + * @param T is not primitive types. + */ +interface CompositeListValue : ListValue> + +/** + * Elements can only be primitives, not wrapped. + * @param T is not primitive types. + */ +interface PrimitiveListValue : ListValue + + +//// region PrimitiveListValue CODEGEN START //// + +interface PrimitiveIntListValue : PrimitiveListValue +interface PrimitiveLongListValue : PrimitiveListValue +// TODO + codegen + +//// endregion PrimitiveListValue CODEGEN END //// + + +/** + * Superclass of [CompositeSetValue], [PrimitiveSetValue]. + */ +interface SetValue : CompositeValue> + +/** + * Elements can by anything, wrapped as [Value]. + * @param T is not primitive types. + */ +interface CompositeSetValue : SetValue> + +/** + * Elements can only be primitives, not wrapped. + * @param T is not primitive types. + */ +interface PrimitiveSetValue : SetValue + + +//// region PrimitiveSetValue CODEGEN START //// + +interface PrimitiveIntSetValue : PrimitiveSetValue +interface PrimitiveLongSetValue : PrimitiveSetValue +// TODO + codegen + +//// endregion PrimitiveSetValue CODEGEN END //// + + +/** + * Superclass of [CompositeMapValue], [PrimitiveMapValue]. + */ +interface MapValue : CompositeValue> + +interface CompositeMapValue : MapValue, Value> + +interface PrimitiveMapValue : MapValue + + +//// region PrimitiveMapValue CODEGEN START //// + +interface PrimitiveIntIntMapValue : PrimitiveMapValue +interface PrimitiveIntLongMapValue : PrimitiveMapValue +// TODO + codegen + +//// endregion PrimitiveSetValue CODEGEN END //// + + + + + + + + + diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt new file mode 100644 index 000000000..e6d80c495 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("NOTHING_TO_INLINE") + +package net.mamoe.mirai.console.setting.internal + +import net.mamoe.mirai.console.setting.Setting +import net.mamoe.mirai.console.setting.Value +import kotlin.reflect.KClass +import kotlin.reflect.KType +import kotlin.reflect.full.isSubclassOf + + +@PublishedApi +internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { + require(type.classifier is KClass<*>) + + if (type.classifier.isPrimitiveOrBuiltInSerializableValue()) { + TODO("是基础类型, 可以直接创建 ValueImpl. ") + } + + // 复合类型 + + when { + type.classifier.isSubclassOf(Map::class) -> { + + TODO() + } + type.classifier.isSubclassOf(List::class) -> { + + TODO() + } + type.classifier.isSubclassOf(Set::class) -> { + TODO() + } + else -> error("Custom composite value is not supported yet (${type.classifier.qualifiedName})") + } +} + +internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean { + when (this) { + Byte::class, Short::class, Int::class, Long::class, + Boolean::class, + Char::class, String::class, + Pair::class, Triple::class + -> return true + } + + return false +} + +@PublishedApi +@Suppress("UNCHECKED_CAST") +internal inline fun T.cast(): R = this as R \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt new file mode 100644 index 000000000..ce7a68627 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("unused") + +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 + +internal abstract class IntValueImpl : IntValue { + constructor() + constructor(default: Int) { + _value = default + } + + private var _value: Int? = null + + override var value: Int + get() = _value ?: throw IllegalStateException("IntValue should be initialized before get.") + set(v) { + if (v != this._value) { + this._value = v + onChanged() + } + } + + protected abstract fun onChanged() +} + +internal abstract class CompositeListValueImpl( + val tToValue: (T) -> Value +) : CompositeListValue { + private var _value: List> = mutableListOf() + override var value: List> + get() = _value + set(v) { + _value = v + } +} \ No newline at end of file