瀏覽代碼

API stabilization for PluginData:
Enforce explicit saveName on init

Him188 5 年之前
父節點
當前提交
da68027b7c

+ 7 - 2
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt

@@ -24,6 +24,11 @@ import kotlin.reflect.KProperty
  * @see PluginData
  */
 public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
+    /**
+     * 这个 [PluginData] 保存时使用的名称.
+     */
+    public abstract override val saveName: String
+
     /**
      * 添加了追踪的 [ValueNode] 列表, 即通过 `by value` 初始化的属性列表.
      *
@@ -32,7 +37,7 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
      * @see provideDelegate
      */
     @ConsoleExperimentalApi
-    public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf()
+    public val valueNodes: MutableList<ValueNode<*>> = mutableListOf()
 
     /**
      * 供手动实现时值跟踪使用 (如 Java 用户). 一般 Kotlin 用户需使用 [provideDelegate]
@@ -61,7 +66,7 @@ public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
     ): T = track(this, property.valueName, property.getAnnotationListForValueSerialization())
 
     /**
-     * 所有 [valueNodes] 更新和保存序列化器. 仅供内部使用
+     * 所有 [valueNodes] 更新和保存序列化器.
      */
     @ConsoleExperimentalApi
     public final override val updaterSerializer: KSerializer<Unit>

+ 7 - 1
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AutoSavePluginConfig.kt

@@ -23,4 +23,10 @@ import kotlinx.coroutines.Job
  * @see PluginConfig
  * @see AutoSavePluginData
  */
-public open class AutoSavePluginConfig : AutoSavePluginData(), PluginConfig
+public open class AutoSavePluginConfig : AutoSavePluginData, PluginConfig {
+    @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"改成保存的名称\")"))
+    @Suppress("DEPRECATION_ERROR")
+    public constructor() : super()
+
+    public constructor(saveName: String) : super(saveName)
+}

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

@@ -18,6 +18,7 @@ import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
 import net.mamoe.mirai.console.internal.plugin.updateWhen
 import net.mamoe.mirai.console.util.ConsoleExperimentalApi
 import net.mamoe.mirai.utils.*
+import kotlin.reflect.full.findAnnotation
 
 /**
  * 链接自动保存的 [PluginData].
@@ -35,8 +36,22 @@ public open class AutoSavePluginData private constructor(
     private val autoSaveIntervalMillis_: LongRange get() = owner_.autoSaveIntervalMillis
     private lateinit var storage_: PluginDataStorage
 
-    public constructor() : this(null)
+    public final override val saveName: String
+        get() = _saveName
 
+    private lateinit var _saveName: String
+
+    public constructor(saveName: String) : this(null) {
+        _saveName = saveName
+    }
+
+    @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig"))
+    public constructor() : this(null) {
+        val clazz = this::class
+        _saveName = clazz.findAnnotation<ValueName>()?.value
+            ?: clazz.qualifiedName
+                ?: throw IllegalArgumentException("Cannot find a serial name for ${this::class}")
+    }
 
     @ConsoleExperimentalApi
     override fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) {

+ 6 - 12
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt

@@ -32,12 +32,11 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalApi
 import kotlin.internal.LowPriorityInOverloadResolution
 import kotlin.reflect.KClass
 import kotlin.reflect.KType
-import kotlin.reflect.full.findAnnotation
 
 /**
- * 一个插件内部的, 对用户隐藏的数据对象. 可包含对多个 [Value] 的值变更的跟踪.
+ * 一个插件内部的, 对用户隐藏的数据对象. 可包含对多个 [Value] 的值变更的跟踪. 典型的实现为 [AbstractPluginData].
  *
- * [PluginData] 不涉及有关数据的存储, 而是只维护数据结构: [属性节点列表][valueNodes].
+ * [AbstractPluginData] 不涉及有关数据的存储, 而是只维护数据结构: [属性节点列表][AbstractPluginData.valueNodes].
  *
  * 有关存储方案, 请查看 [PluginDataStorage].
  *
@@ -74,7 +73,7 @@ import kotlin.reflect.full.findAnnotation
  * val theList: MutableList<String> = AccountPluginData.list
  * ```
  *
- * 但也注意, 不要存储 `AccountPluginData.list`. 它可能受不到值跟踪. 若必要存储, 请使用 [PluginData.findBackingFieldValue]
+ * 但也注意, 不要存储 `AccountPluginData.list`. 它可能受不到值跟踪. 若必要存储, 请使用 [AbstractPluginData.findBackingFieldValue]
  *
  * ### 使用 Java
  *
@@ -110,22 +109,17 @@ import kotlin.reflect.full.findAnnotation
  */
 public interface PluginData {
     /**
-     * 这个 [PluginData] 保存时使用的名称. 默认通过 [ValueName] 获取, 否则使用 [类全名][KClass.qualifiedName] (即 [Class.getCanonicalName])
+     * 这个 [PluginData] 保存时使用的名称.
      */
     @ConsoleExperimentalApi
     public val saveName: String
-        get() {
-            val clazz = this::class
-            return clazz.findAnnotation<ValueName>()?.value
-                ?: clazz.qualifiedName
-                ?: throw IllegalArgumentException("Cannot find a serial name for ${this::class}")
-        }
 
     @ConsoleExperimentalApi
     public val updaterSerializer: KSerializer<Unit>
 
     /**
      * 当所属于这个 [PluginData] 的 [Value] 的 [值][Value.value] 被修改时被调用.
+     * 调用者为 [Value] 的实现.
      */
     @ConsoleExperimentalApi
     public fun onValueChanged(value: Value<*>)
@@ -202,7 +196,7 @@ public fun PluginData.value(default: String): SerializerAwareValue<String> = val
 @LowPriorityInOverloadResolution
 public inline fun <reified T> PluginData.value(
     default: T,
-    crossinline apply: T.() -> Unit = {}
+    crossinline apply: T.() -> Unit = {},
 ): SerializerAwareValue<T> =
     valueFromKType(typeOf0<T>(), default).also { it.value.apply() }
 

+ 7 - 1
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/java/JAutoSavePluginConfig.kt

@@ -37,4 +37,10 @@ import net.mamoe.mirai.console.data.PluginData
  * @see JAutoSavePluginData
  * @see PluginConfig
  */
-public abstract class JAutoSavePluginConfig : AutoSavePluginConfig(), PluginConfig
+public abstract class JAutoSavePluginConfig : AutoSavePluginConfig, PluginConfig {
+    @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"改成保存的名称\")"))
+    @Suppress("DEPRECATION_ERROR")
+    public constructor() : super()
+
+    public constructor(saveName: String) : super(saveName)
+}

+ 7 - 1
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/java/JAutoSavePluginData.kt

@@ -66,7 +66,13 @@ import kotlin.reflect.full.createType
  *
  * @see PluginData
  */
-public abstract class JAutoSavePluginData : AutoSavePluginData(), PluginConfig {
+public abstract class JAutoSavePluginData : AutoSavePluginData, PluginConfig {
+    @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"改成保存的名称\")"))
+    @Suppress("DEPRECATION_ERROR")
+    public constructor() : super()
+
+    public constructor(saveName: String) : super(saveName)
+
     //// region JPluginData_value_primitives CODEGEN ////
 
     /**

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

@@ -18,9 +18,9 @@ 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
 import net.mamoe.mirai.console.data.AbstractPluginData.ValueNode
 import net.mamoe.mirai.console.data.PluginData
-import net.mamoe.mirai.console.data.Value
 import net.mamoe.mirai.console.data.ValueDescription
 import net.mamoe.mirai.console.data.ValueName
 import net.mamoe.yamlkt.Comment
@@ -34,12 +34,25 @@ import kotlin.reflect.KAnnotatedElement
  * - Auto-saving
  */
 internal abstract class PluginDataImpl {
-    internal fun findNodeInstance(name: String): ValueNode<*>? = valueNodes.firstOrNull { it.valueName == name }
+    init {
+        @Suppress("LeakingThis")
+        check(this is AbstractPluginData)
+    }
 
-    internal abstract val valueNodes: MutableList<ValueNode<*>>
+    private fun findNodeInstance(name: String): ValueNode<*>? {
+        check(this is AbstractPluginData)
+        return valueNodes.firstOrNull { it.valueName == name }
+    }
 
     internal open val updaterSerializer: KSerializer<Unit> = object : KSerializer<Unit> {
-        override val descriptor: SerialDescriptor get() = dataUpdaterSerializerDescriptor
+        override val descriptor: SerialDescriptor by lazy {
+            check(this@PluginDataImpl is AbstractPluginData)
+            kotlinx.serialization.descriptors.buildClassSerialDescriptor((this@PluginDataImpl as PluginData).saveName) {
+                for (valueNode in valueNodes) valueNode.run {
+                    element(valueName, updaterSerializer.descriptor, annotations = annotations, isOptional = true)
+                }
+            }
+        }
 
         @Suppress("UNCHECKED_CAST")
         override fun deserialize(decoder: Decoder) {
@@ -84,6 +97,8 @@ internal abstract class PluginDataImpl {
 
         @Suppress("UNCHECKED_CAST")
         override fun serialize(encoder: Encoder, value: Unit) {
+            check(this@PluginDataImpl is AbstractPluginData)
+
             val descriptor = descriptor
             with(encoder.beginStructure(descriptor)) {
                 repeat(descriptor.elementsCount) { index ->
@@ -100,18 +115,6 @@ internal abstract class PluginDataImpl {
         }
 
     }
-
-    /**
-     * flatten
-     */
-    abstract fun onValueChanged(value: Value<*>)
-    private val dataUpdaterSerializerDescriptor by lazy {
-        kotlinx.serialization.descriptors.buildClassSerialDescriptor((this as PluginData).saveName) {
-            for (valueNode in valueNodes) valueNode.run {
-                element(valueName, updaterSerializer.descriptor, annotations = annotations, isOptional = true)
-            }
-        }
-    }
 }
 
 internal fun KAnnotatedElement.getAnnotationListForValueSerialization(): List<Annotation> {

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

@@ -6,10 +6,7 @@ import net.mamoe.mirai.console.data.value
 import net.mamoe.mirai.console.internal.util.md5
 import net.mamoe.mirai.console.internal.util.toUHexString
 
-internal object AutoLoginConfig : AutoSavePluginConfig() {
-    override val saveName: String
-        get() = "AutoLogin"
-
+internal object AutoLoginConfig : AutoSavePluginConfig("AutoLogin") {
     @ValueDescription(
         """
         账号和明文密码列表

+ 1 - 3
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/extension/BuiltInSingletonExtensionSelector.kt

@@ -16,9 +16,7 @@ internal object BuiltInSingletonExtensionSelector : SingletonExtensionSelector {
 
     internal val config: SaveData = SaveData()
 
-    internal class SaveData : AutoSavePluginConfig() {
-        override val saveName: String get() = "ExtensionSelector"
-
+    internal class SaveData : AutoSavePluginConfig("ExtensionSelector") {
         val value: MutableMap<String, String> by value()
     }
 

+ 4 - 4
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/permission/BuiltInPermissionServices.kt

@@ -117,12 +117,12 @@ internal object BuiltInPermissionService : AbstractConcurrentPermissionService<P
 
     @Suppress("RedundantVisibilityModifier")
     internal class ConcurrentSaveData private constructor(
-        public override val saveName: String,
+        saveName: String,
         @Suppress("UNUSED_PARAMETER") primaryConstructorMark: Any?,
-    ) : AutoSavePluginConfig() {
+    ) : AutoSavePluginConfig(saveName) {
         public val grantedPermissionMap: PluginDataExtensions.NotNullMutableMap<PermissionId, MutableSet<AbstractPermitteeId>>
-                by value<MutableMap<PermissionId, MutableSet<AbstractPermitteeId>>>(ConcurrentHashMap())
-                    .withDefault { CopyOnWriteArraySet() }
+            by value<MutableMap<PermissionId, MutableSet<AbstractPermitteeId>>>(ConcurrentHashMap())
+                .withDefault { CopyOnWriteArraySet() }
 
         public companion object {
             @JvmStatic

+ 1 - 1
backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt

@@ -17,7 +17,7 @@ import kotlin.test.assertSame
 
 @OptIn(ConsoleInternalApi::class)
 internal class PluginDataTest {
-    class MyPluginData : AutoSavePluginData() {
+    class MyPluginData : AutoSavePluginData("test") {
         var int by value(1)
         val map: MutableMap<String, String> by value()
         val map2: MutableMap<String, MutableMap<String, String>> by value()