Values infrastructure

This commit is contained in:
Him188 2020-06-19 04:26:29 +08:00
parent 9f600a7855
commit afc30c5357
4 changed files with 312 additions and 0 deletions

View File

@ -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()

View File

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

View File

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

View File

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