mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Values infrastructure
This commit is contained in:
parent
9f600a7855
commit
afc30c5357
@ -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<T>(
|
||||
val property: KProperty<T>,
|
||||
val value: Value<T>,
|
||||
val serializer: ValueSerializer<T>
|
||||
)
|
||||
|
||||
private val valueNodes: List<Node<*>> = 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 <reified T> Setting.value(default: T): Value<T> = valueFromKTypeImpl(typeOf<T>()).cast()
|
@ -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<T> {
|
||||
var value: T
|
||||
}
|
||||
|
||||
/**
|
||||
* The serializer for a specific kind of [Value].
|
||||
*/
|
||||
typealias ValueSerializer<T> = KSerializer<Value<T>>
|
||||
|
||||
/**
|
||||
* 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<T> : Value<T>
|
||||
|
||||
interface MutablePrimitiveValue<T> : Value<T>
|
||||
|
||||
|
||||
//// region PrimitiveValue CODEGEN START ////
|
||||
|
||||
// TODO: 2020/6/19 CODEGEN
|
||||
|
||||
/**
|
||||
* Represents a non-null [Int] value.
|
||||
*/
|
||||
interface IntValue : PrimitiveValue<Int>
|
||||
|
||||
//// endregion PrimitiveValue CODEGEN END ////
|
||||
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
interface CompositeValue<T> : Value<T>
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeListValue], [PrimitiveListValue].
|
||||
*/
|
||||
interface ListValue<T> : CompositeValue<List<T>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param T is not primitive types.
|
||||
*/
|
||||
interface CompositeListValue<T> : ListValue<Value<T>>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param T is not primitive types.
|
||||
*/
|
||||
interface PrimitiveListValue<T> : ListValue<T>
|
||||
|
||||
|
||||
//// region PrimitiveListValue CODEGEN START ////
|
||||
|
||||
interface PrimitiveIntListValue<T> : PrimitiveListValue<T>
|
||||
interface PrimitiveLongListValue<T> : PrimitiveListValue<T>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveListValue CODEGEN END ////
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeSetValue], [PrimitiveSetValue].
|
||||
*/
|
||||
interface SetValue<T> : CompositeValue<Set<T>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param T is not primitive types.
|
||||
*/
|
||||
interface CompositeSetValue<T> : SetValue<Value<T>>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param T is not primitive types.
|
||||
*/
|
||||
interface PrimitiveSetValue<T> : SetValue<T>
|
||||
|
||||
|
||||
//// region PrimitiveSetValue CODEGEN START ////
|
||||
|
||||
interface PrimitiveIntSetValue<T> : PrimitiveSetValue<T>
|
||||
interface PrimitiveLongSetValue<T> : PrimitiveSetValue<T>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN END ////
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeMapValue], [PrimitiveMapValue].
|
||||
*/
|
||||
interface MapValue<K, V> : CompositeValue<Map<K, V>>
|
||||
|
||||
interface CompositeMapValue<K, V> : MapValue<Value<K>, Value<V>>
|
||||
|
||||
interface PrimitiveMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
|
||||
//// region PrimitiveMapValue CODEGEN START ////
|
||||
|
||||
interface PrimitiveIntIntMapValue : PrimitiveMapValue<Int, Int>
|
||||
interface PrimitiveIntLongMapValue : PrimitiveMapValue<Int, Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN END ////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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 <R, T> T.cast(): R = this as R
|
@ -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<T>(
|
||||
val tToValue: (T) -> Value<T>
|
||||
) : CompositeListValue<T> {
|
||||
private var _value: List<Value<T>> = mutableListOf()
|
||||
override var value: List<Value<T>>
|
||||
get() = _value
|
||||
set(v) {
|
||||
_value = v
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user