Browse Source

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`

Him188 5 years ago
parent
commit
2fe2d2a681

+ 107 - 4
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt

@@ -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 { [email protected](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>?
 }

+ 1 - 0
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AutoSavePluginData.kt

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

+ 5 - 112
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt

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

+ 1 - 0
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt

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

+ 3 - 0
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/ValueName.kt

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

+ 3 - 6
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/MultiFilePluginDataStorageImpl.kt

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

+ 1 - 1
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt

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