API stabilization for PluginData:

Move members valueNodes, ValueNode, track from PluginData to AbstractPluginData;
Move findBackingFieldValue, findBackingFieldValueNode from PluginData.kt to AbstractPluginData.kt;
Mark unstable APIs with `@ConsoleExperimentalApi`
This commit is contained in:
Him188 2020-09-18 20:35:36 +08:00
parent 53890bcb5d
commit 2fe2d2a681
7 changed files with 121 additions and 123 deletions

View File

@ -12,10 +12,10 @@
package net.mamoe.mirai.console.data package net.mamoe.mirai.console.data
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import net.mamoe.mirai.console.data.PluginData.ValueNode
import net.mamoe.mirai.console.internal.data.PluginDataImpl import net.mamoe.mirai.console.internal.data.PluginDataImpl
import net.mamoe.mirai.console.internal.data.getAnnotationListForValueSerialization import net.mamoe.mirai.console.internal.data.getAnnotationListForValueSerialization
import net.mamoe.mirai.console.internal.data.valueName import net.mamoe.mirai.console.internal.data.valueName
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
/** /**
@ -31,13 +31,26 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
* *
* @see provideDelegate * @see provideDelegate
*/ */
@ConsoleExperimentalApi
public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf() public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf()
/** /**
* 供手动实现时值跟踪使用 ( Java 用户). 一般 Kotlin 用户需使用 [provideDelegate] * 供手动实现时值跟踪使用 ( Java 用户). 一般 Kotlin 用户需使用 [provideDelegate]
*/ */
public override fun <T : SerializerAwareValue<*>> T.track(valueName: String, annotations: List<Annotation>): T = @ConsoleExperimentalApi
apply { valueNodes.add(ValueNode(valueName, this, annotations, this.serializer)) } public fun <T : SerializerAwareValue<*>> track(
value: T,
/**
* 值名称.
*
* 如果属性带有 [ValueName], 则使用 [ValueName.value],
* 否则使用 [属性名称][KProperty.name]
*
* @see [ValueNode.value]
*/
valueName: String,
annotations: List<Annotation>,
): T = value.apply { this@AbstractPluginData.valueNodes.add(ValueNode(valueName, this, annotations, this.serializer)) }
/** /**
* 使用 `by value()` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪, 并创建 [ValueNode] 加入 [valueNodes] * 使用 `by value()` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪, 并创建 [ValueNode] 加入 [valueNodes]
@ -45,17 +58,19 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
public operator fun <T : SerializerAwareValue<*>> T.provideDelegate( public operator fun <T : SerializerAwareValue<*>> T.provideDelegate(
thisRef: Any?, thisRef: Any?,
property: KProperty<*>, property: KProperty<*>,
): T = track(property.valueName, property.getAnnotationListForValueSerialization()) ): T = track(this, property.valueName, property.getAnnotationListForValueSerialization())
/** /**
* 所有 [valueNodes] 更新和保存序列化器. 仅供内部使用 * 所有 [valueNodes] 更新和保存序列化器. 仅供内部使用
*/ */
@ConsoleExperimentalApi
public final override val updaterSerializer: KSerializer<Unit> public final override val updaterSerializer: KSerializer<Unit>
get() = super.updaterSerializer get() = super.updaterSerializer
/** /**
* 当所属于这个 [PluginData] [Value] [][Value.value] 被修改时被调用. * 当所属于这个 [PluginData] [Value] [][Value.value] 被修改时被调用.
*/ */
@ConsoleExperimentalApi
public override fun onValueChanged(value: Value<*>) { public override fun onValueChanged(value: Value<*>) {
// no-op by default // no-op by default
} }
@ -63,7 +78,95 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
/** /**
* 当这个 [PluginData] 被放入一个 [PluginDataStorage] 时调用 * 当这个 [PluginData] 被放入一个 [PluginDataStorage] 时调用
*/ */
@ConsoleExperimentalApi
public override fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) { public override fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) {
// no-op by default // no-op by default
} }
/**
* [track] 创建, 来自一个通过 `by value` 初始化的属性节点.
*/
@ConsoleExperimentalApi
public data class ValueNode<T>(
/**
* 节点名称.
*
* 如果属性带有 [ValueName], 则使用 [ValueName.value],
* 否则使用 [属性名称][KProperty.name]
*/
val valueName: String,
/**
* 属性值代理
*/
val value: Value<out T>,
/**
* 注解列表
*/
val annotations: List<Annotation>,
/**
* 属性值更新器
*/
val updaterSerializer: KSerializer<Unit>,
)
}
/**
* 获取这个 [KProperty] 委托的 [Value]
*
* 示例:
* ```
* object MyData : AutoSavePluginData(PluginMain) {
* val list: List<String> by value()
* }
*
* val value: Value<List<String>> = MyData.findBackingFieldValue(MyData::list)
* ```
*
* @see PluginData
*/
@ConsoleExperimentalApi
public fun <T> AbstractPluginData.findBackingFieldValue(property: KProperty<T>): Value<out T>? =
findBackingFieldValue(property.valueName)
/**
* 获取这个 [KProperty] 委托的 [Value]
*
* 示例:
* ```
* object MyData : AutoSavePluginData(PluginMain) {
* @ValueName("theList")
* val list: List<String> by value()
* val int: Int by value()
* }
*
* val value: Value<List<String>> = MyData.findBackingFieldValue("theList") // 需使用 @ValueName 标注的名称
* val intValue: Value<Int> = MyData.findBackingFieldValue("int")
* ```
*
* @see PluginData
*/
@ConsoleExperimentalApi
public fun <T> AbstractPluginData.findBackingFieldValue(propertyValueName: String): Value<out T>? {
@Suppress("UNCHECKED_CAST")
return this.valueNodes.find { it.valueName == propertyValueName }?.value as Value<out T>
}
/**
* 获取这个 [KProperty] 委托的 [Value]
*
* 示例:
* ```
* object MyData : AutoSavePluginData(PluginMain) {
* val list: List<String> by value()
* }
*
* val value: PluginData.ValueNode<List<String>> = MyData.findBackingFieldValueNode(MyData::list)
* ```
*
* @see PluginData
*/
@ConsoleExperimentalApi
public fun <T> AbstractPluginData.findBackingFieldValueNode(property: KProperty<T>): AbstractPluginData.ValueNode<out T>? {
@Suppress("UNCHECKED_CAST")
return this.valueNodes.find { it == property } as AbstractPluginData.ValueNode<out T>?
} }

View File

@ -121,6 +121,7 @@ public open class AutoSavePluginData private constructor(
} }
} }
@ConsoleExperimentalApi
public final override fun onValueChanged(value: Value<*>) { public final override fun onValueChanged(value: Value<*>) {
debuggingLogger1.error { "onValueChanged: $value" } debuggingLogger1.error { "onValueChanged: $value" }
if (::owner_.isInitialized) { if (::owner_.isInitialized) {

View File

@ -21,14 +21,16 @@ import kotlinx.serialization.KSerializer
import net.mamoe.mirai.console.compiler.common.ResolveContext import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.RESTRICTED_NO_ARG_CONSTRUCTOR import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.RESTRICTED_NO_ARG_CONSTRUCTOR
import net.mamoe.mirai.console.data.java.JAutoSavePluginData import net.mamoe.mirai.console.data.java.JAutoSavePluginData
import net.mamoe.mirai.console.internal.data.* import net.mamoe.mirai.console.internal.data.createInstanceSmart
import net.mamoe.mirai.console.internal.data.typeOf0
import net.mamoe.mirai.console.internal.data.valueFromKTypeImpl
import net.mamoe.mirai.console.internal.data.valueImpl
import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.jvm.reloadPluginData import net.mamoe.mirai.console.plugin.jvm.reloadPluginData
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import kotlin.internal.LowPriorityInOverloadResolution import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotation
@ -107,16 +109,6 @@ import kotlin.reflect.full.findAnnotation
* @see PluginDataExtensions 相关 [SerializerAwareValue] 映射函数 * @see PluginDataExtensions 相关 [SerializerAwareValue] 映射函数
*/ */
public interface PluginData { public interface PluginData {
/**
* 添加了追踪的 [ValueNode] 列表 (即使用 `by value()` 委托的属性), 即通过 `by value` 初始化的属性列表.
*
* 他们的修改会被跟踪, 并触发 [onValueChanged].
*
* @see provideDelegate
* @see track
*/
public val valueNodes: MutableList<ValueNode<*>>
/** /**
* 这个 [PluginData] 保存时使用的名称. 默认通过 [ValueName] 获取, 否则使用 [类全名][KClass.qualifiedName] ( [Class.getCanonicalName]) * 这个 [PluginData] 保存时使用的名称. 默认通过 [ValueName] 获取, 否则使用 [类全名][KClass.qualifiedName] ( [Class.getCanonicalName])
*/ */
@ -129,56 +121,13 @@ public interface PluginData {
?: throw IllegalArgumentException("Cannot find a serial name for ${this::class}") ?: throw IllegalArgumentException("Cannot find a serial name for ${this::class}")
} }
/**
* [provideDelegate] 创建, 来自一个通过 `by value` 初始化的属性节点.
*/
@ConsoleExperimentalApi @ConsoleExperimentalApi
public data class ValueNode<T>(
/**
* 节点名称.
*
* 如果属性带有 [ValueName], 则使用 [ValueName.value],
* 否则使用 [属性名称][KProperty.name]
*/
val valueName: String,
/**
* 属性值代理
*/
val value: Value<out T>,
/**
* 注解列表
*/
val annotations: List<Annotation>,
/**
* 属性值更新器
*/
val updaterSerializer: KSerializer<Unit>
)
/**
* 供手动实现时值跟踪使用 ( Java 用户). 一般 Kotlin 用户需使用 [provideDelegate]
*/
public fun <T : SerializerAwareValue<*>> T.track(
/**
* 值名称.
*
* 如果属性带有 [ValueName], 则使用 [ValueName.value],
* 否则使用 [属性名称][KProperty.name]
*
* @see [ValueNode.value]
*/
valueName: String,
annotations: List<Annotation>
): T
/**
* 所有 [valueNodes] 更新和保存序列化器. 仅供内部使用
*/
public val updaterSerializer: KSerializer<Unit> public val updaterSerializer: KSerializer<Unit>
/** /**
* 当所属于这个 [PluginData] [Value] [][Value.value] 被修改时被调用. * 当所属于这个 [PluginData] [Value] [][Value.value] 被修改时被调用.
*/ */
@ConsoleExperimentalApi
public fun onValueChanged(value: Value<*>) public fun onValueChanged(value: Value<*>)
/** /**
@ -188,62 +137,6 @@ public interface PluginData {
public fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) public fun onInit(owner: PluginDataHolder, storage: PluginDataStorage)
} }
/**
* 获取这个 [KProperty] 委托的 [Value]
*
* , 对于
* ```
* object MyData : AutoSavePluginData(PluginMain) {
* val list: List<String> by value()
* }
*
* val value: Value<List<String>> = MyData.findBackingFieldValue(MyData::list)
* ```
*
* @see PluginData
*/
public fun <T> PluginData.findBackingFieldValue(property: KProperty<T>): Value<out T>? =
findBackingFieldValue(property.valueName)
/**
* 获取这个 [KProperty] 委托的 [Value]
*
* , 对于
* ```
* object MyData : AutoSavePluginData(PluginMain) {
* @ValueName("theList")
* val list: List<String> by value()
* val int: Int by value()
* }
*
* val value: Value<List<String>> = MyData.findBackingFieldValue("theList") // 需使用 @ValueName 标注的名称
* val intValue: Value<Int> = MyData.findBackingFieldValue("int")
* ```
*
* @see PluginData
*/
public fun <T> PluginData.findBackingFieldValue(propertyValueName: String): Value<out T>? {
return this.valueNodes.find { it.valueName == propertyValueName }?.value as Value<T>
}
/**
* 获取这个 [KProperty] 委托的 [Value]
*
* , 对于
* ```
* object MyData : AutoSavePluginData(PluginMain) {
* val list: List<String> by value()
* }
*
* val value: PluginData.ValueNode<List<String>> = MyData.findBackingFieldValueNode(MyData::list)
* ```
*
* @see PluginData
*/
public fun <T> PluginData.findBackingFieldValueNode(property: KProperty<T>): PluginData.ValueNode<out T>? {
return this.valueNodes.find { it == property } as PluginData.ValueNode<out T>?
}
// don't default = 0, cause ambiguity // don't default = 0, cause ambiguity
//// region PluginData_value_primitives CODEGEN //// //// region PluginData_value_primitives CODEGEN ////

View File

@ -135,6 +135,7 @@ public interface MultiFilePluginDataStorage : PluginDataStorage {
} }
} }
@ConsoleExperimentalApi
@get:JvmSynthetic @get:JvmSynthetic
public inline val MultiFilePluginDataStorage.directory: File public inline val MultiFilePluginDataStorage.directory: File
get() = this.directoryPath.toFile() get() = this.directoryPath.toFile()

View File

@ -9,6 +9,8 @@
package net.mamoe.mirai.console.data package net.mamoe.mirai.console.data
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
/** /**
* 序列化之后的名称. * 序列化之后的名称.
* *
@ -27,6 +29,7 @@ package net.mamoe.mirai.console.data
* a: b * a: b
* ``` * ```
*/ */
@ConsoleExperimentalApi
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS) @Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
public annotation class ValueName(val value: String) public annotation class ValueName(val value: String)

View File

@ -9,10 +9,7 @@
package net.mamoe.mirai.console.internal.data package net.mamoe.mirai.console.internal.data
import net.mamoe.mirai.console.data.MultiFilePluginDataStorage import net.mamoe.mirai.console.data.*
import net.mamoe.mirai.console.data.PluginData
import net.mamoe.mirai.console.data.PluginDataHolder
import net.mamoe.mirai.console.data.PluginDataStorage
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
@ -42,7 +39,7 @@ internal open class MultiFilePluginDataStorageImpl(
} else { } else {
this.store(holder, instance) // save an initial copy this.store(holder, instance) // save an initial copy
} }
logger.debug { "Successfully loaded PluginData: ${instance.saveName} (containing ${instance.valueNodes.size} properties)" } logger.debug { "Successfully loaded PluginData: ${instance.saveName} (containing ${instance.castOrNull<AbstractPluginData>()?.valueNodes?.size} properties)" }
} }
protected open fun getPluginDataFile(holder: PluginDataHolder, instance: PluginData): File { protected open fun getPluginDataFile(holder: PluginDataHolder, instance: PluginData): File {
@ -83,7 +80,7 @@ internal open class MultiFilePluginDataStorageImpl(
throw IllegalStateException("Exception while saving $instance, saveName=${instance.saveName}", it) throw IllegalStateException("Exception while saving $instance, saveName=${instance.saveName}", it)
} }
) )
logger.debug { "Successfully saved PluginData: ${instance.saveName} (containing ${instance.valueNodes.size} properties)" } logger.debug { "Successfully saved PluginData: ${instance.saveName} (containing ${instance.castOrNull<AbstractPluginData>()?.valueNodes?.size} properties)" }
} }
} }

View File

@ -18,8 +18,8 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import net.mamoe.mirai.console.data.AbstractPluginData.ValueNode
import net.mamoe.mirai.console.data.PluginData import net.mamoe.mirai.console.data.PluginData
import net.mamoe.mirai.console.data.PluginData.ValueNode
import net.mamoe.mirai.console.data.Value import net.mamoe.mirai.console.data.Value
import net.mamoe.mirai.console.data.ValueDescription import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.ValueName import net.mamoe.mirai.console.data.ValueName