API stabilization for PluginData:

Enforce explicit saveName on init
This commit is contained in:
Him188 2020-09-18 20:53:08 +08:00
parent 2fe2d2a681
commit da68027b7c
11 changed files with 76 additions and 46 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(
"""
账号和明文密码列表

View File

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

View File

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

View File

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