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
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.getAnnotationListForValueSerialization
import net.mamoe.mirai.console.internal.data.valueName
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import kotlin.reflect.KProperty
/**
@ -31,13 +31,26 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
*
* @see provideDelegate
*/
@ConsoleExperimentalApi
public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf()
/**
* 供手动实现时值跟踪使用 ( Java 用户). 一般 Kotlin 用户需使用 [provideDelegate]
*/
public override fun <T : SerializerAwareValue<*>> T.track(valueName: String, annotations: List<Annotation>): T =
apply { valueNodes.add(ValueNode(valueName, this, annotations, this.serializer)) }
@ConsoleExperimentalApi
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]
@ -45,17 +58,19 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
public operator fun <T : SerializerAwareValue<*>> T.provideDelegate(
thisRef: Any?,
property: KProperty<*>,
): T = track(property.valueName, property.getAnnotationListForValueSerialization())
): T = track(this, property.valueName, property.getAnnotationListForValueSerialization())
/**
* 所有 [valueNodes] 更新和保存序列化器. 仅供内部使用
*/
@ConsoleExperimentalApi
public final override val updaterSerializer: KSerializer<Unit>
get() = super.updaterSerializer
/**
* 当所属于这个 [PluginData] [Value] [][Value.value] 被修改时被调用.
*/
@ConsoleExperimentalApi
public override fun onValueChanged(value: Value<*>) {
// no-op by default
}
@ -63,7 +78,95 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
/**
* 当这个 [PluginData] 被放入一个 [PluginDataStorage] 时调用
*/
@ConsoleExperimentalApi
public override fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) {
// 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<*>) {
debuggingLogger1.error { "onValueChanged: $value" }
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.Kind.RESTRICTED_NO_ARG_CONSTRUCTOR
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.JvmPlugin
import net.mamoe.mirai.console.plugin.jvm.reloadPluginData
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.full.findAnnotation
@ -107,16 +109,6 @@ import kotlin.reflect.full.findAnnotation
* @see PluginDataExtensions 相关 [SerializerAwareValue] 映射函数
*/
public interface PluginData {
/**
* 添加了追踪的 [ValueNode] 列表 (即使用 `by value()` 委托的属性), 即通过 `by value` 初始化的属性列表.
*
* 他们的修改会被跟踪, 并触发 [onValueChanged].
*
* @see provideDelegate
* @see track
*/
public val valueNodes: MutableList<ValueNode<*>>
/**
* 这个 [PluginData] 保存时使用的名称. 默认通过 [ValueName] 获取, 否则使用 [类全名][KClass.qualifiedName] ( [Class.getCanonicalName])
*/
@ -129,56 +121,13 @@ public interface PluginData {
?: throw IllegalArgumentException("Cannot find a serial name for ${this::class}")
}
/**
* [provideDelegate] 创建, 来自一个通过 `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>
)
/**
* 供手动实现时值跟踪使用 ( 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>
/**
* 当所属于这个 [PluginData] [Value] [][Value.value] 被修改时被调用.
*/
@ConsoleExperimentalApi
public fun onValueChanged(value: Value<*>)
/**
@ -188,62 +137,6 @@ public interface PluginData {
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
//// region PluginData_value_primitives CODEGEN ////

View File

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

View File

@ -9,6 +9,8 @@
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
* ```
*/
@ConsoleExperimentalApi
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
public annotation class ValueName(val value: String)

View File

@ -9,10 +9,7 @@
package net.mamoe.mirai.console.internal.data
import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
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.data.*
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.utils.MiraiLogger
@ -42,7 +39,7 @@ internal open class MultiFilePluginDataStorageImpl(
} else {
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 {
@ -83,7 +80,7 @@ internal open class MultiFilePluginDataStorageImpl(
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.Decoder
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.ValueNode
import net.mamoe.mirai.console.data.Value
import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.ValueName