From 31cd77febf73d5ba29033cc386293aba3318036a Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 26 Aug 2020 22:27:34 +0800 Subject: [PATCH] Introduce PluginDataExtensions --- .../mamoe/mirai/console/data/PluginData.kt | 2 +- .../console/data/PluginDataExtensions.kt | 211 +++++++++++++----- .../net/mamoe/mirai/console/data/Value.kt | 3 + .../console/internal/data/collectionUtil.kt | 34 +-- .../console/internal/util/BotManagerImpl.kt | 6 +- 5 files changed, 179 insertions(+), 77 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt index 7f3970128..b4e70316d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt @@ -76,7 +76,7 @@ import kotlin.reflect.full.findAnnotation * @see JvmPlugin.reloadPluginData 通过 [JvmPlugin] 获取指定 [PluginData] 实例. * @see PluginDataStorage [PluginData] 存储仓库 */ -public interface PluginData : PluginDataExtensions { +public interface PluginData { /** * 添加了追踪的 [ValueNode] 列表 (即使用 `by value()` 委托的属性), 即通过 `by value` 初始化的属性列表. * diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataExtensions.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataExtensions.kt index 5b0120859..a97ed4d66 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataExtensions.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataExtensions.kt @@ -1,59 +1,114 @@ +@file:Suppress("unused", "INAPPLICABLE_JVM_NAME") + package net.mamoe.mirai.console.data -import net.mamoe.mirai.console.internal.data.CompositeMapValueImpl -import net.mamoe.mirai.console.internal.data.castOrInternalError -import net.mamoe.mirai.console.internal.data.createCompositeMapValueImpl +import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault +import net.mamoe.mirai.console.internal.data.ShadowMap +import net.mamoe.mirai.console.util.ConsoleExperimentalAPI -@Suppress("INAPPLICABLE_JVM_NAME", "UNCHECKED_CAST") -public interface PluginDataExtensions { +/** + * [PluginData] 相关一些扩展 + */ +@ConsoleExperimentalAPI +public object PluginDataExtensions { - @JvmName("withDefaultImmutable") - public fun SerializerAwareValue>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue> { + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先放入一个 [LinkedHashMap], 再返回这个 [LinkedHashMap] + * @see withDefault + */ + @JvmName("withEmptyDefaultMapImmutable") + @JvmStatic + public fun SerializerAwareValue>>.withEmptyDefault(): SerializerAwareValue>> { + return this.withDefault { LinkedHashMap() } + } + + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先放入一个 [LinkedHashMap], 再返回这个 [LinkedHashMap] + * @see withDefault + */ + @JvmName("withEmptyDefaultMap") + @JvmStatic + public fun SerializerAwareValue>>.withEmptyDefault(): SerializerAwareValue>> { + return this.withDefault { LinkedHashMap() } + } + + + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先放入一个 [ArrayList], 再返回这个 [ArrayList] + * @see withDefault + */ + @JvmName("withEmptyDefaultListImmutable") + @JvmStatic + public fun SerializerAwareValue>>.withEmptyDefault(): SerializerAwareValue>> { + return this.withDefault { ArrayList() } + } + + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先放入一个 [ArrayList], 再返回这个 [ArrayList] + * @see withDefault + */ + @JvmName("withEmptyDefaultList") + @JvmStatic + public fun SerializerAwareValue>>.withEmptyDefault(): SerializerAwareValue>> { + return this.withDefault { ArrayList() } + } + + + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先放入一个 [LinkedHashSet], 再返回这个 [LinkedHashSet] + * @see withDefault + */ + @JvmName("withEmptyDefaultSetImmutable") + @JvmStatic + public fun SerializerAwareValue>>.withEmptyDefault(): SerializerAwareValue>> { + return this.withDefault { LinkedHashSet() } + } + + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先放入一个 [LinkedHashSet], 再返回这个 [LinkedHashSet] + * @see withDefault + */ + @JvmName("withEmptyDefaultSet") + @JvmStatic + public fun SerializerAwareValue>>.withEmptyDefault(): SerializerAwareValue>> { + return this.withDefault { LinkedHashSet() } + } + + + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先调用 [defaultValueComputer] 并放入 [Map], 再返回调用的返回值 + */ + @JvmStatic + @JvmName("withDefaultMapImmutable") + public fun SerializerAwareValue>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue> { + @Suppress("UNCHECKED_CAST") // magic return (this as SerializerAwareValue>).withDefault(defaultValueComputer) as SerializerAwareValue> } - @JvmName("withDefaultImmutableMap") - public fun , V : Map<*, *>, K> SerializerAwareValue.withEmptyDefault(): SerializerAwareValue { - return this.withDefault { LinkedHashMap() as V } - } - - @JvmName("withDefaultImmutableSet") - public fun , V : Set<*>, K> SerializerAwareValue.withEmptyDefault(): SerializerAwareValue { - return this.withDefault { LinkedHashSet() as V } - } - - @JvmName("withDefaultImmutableList") - public fun , V : List<*>, K> SerializerAwareValue.withEmptyDefault(): SerializerAwareValue { - return this.withDefault { ArrayList() as V } - } - - public fun , V, K> SerializerAwareValue.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue { - val pluginData = this@PluginDataExtensions.castOrInternalError() - - - val origin = (this as SerializableValue).delegate.castOrInternalError>() + /** + * 创建一个代理对象, 当 [Map.get] 返回 `null` 时先调用 [defaultValueComputer] 并放入 [Map], 再返回调用的返回值 + */ + @JvmStatic + @JvmName("withDefaultMap") + public fun SerializerAwareValue>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue> { + val origin = this + @Suppress("UNCHECKED_CAST") return SerializableValue( object : CompositeMapValue { - private val instance = object : MutableMap { - override val size: Int get() = origin.value.size - override fun containsKey(key: K): Boolean = origin.value.containsKey(key) - override fun containsValue(value: V): Boolean = origin.value.containsValue(value) - override fun isEmpty(): Boolean = origin.value.isEmpty() - override val entries: MutableSet> get() = origin.value.entries as MutableSet> - override val keys: MutableSet get() = origin.value.keys as MutableSet - override val values: MutableCollection get() = origin.value.values as MutableCollection - override fun clear() = (origin.value as MutableMap).clear() - override fun putAll(from: Map) = (origin.value as MutableMap).putAll(from) - override fun remove(key: K): V? = (origin.value as MutableMap).remove(key) - override fun put(key: K, value: V): V? = (origin.value as MutableMap).put(key, value) + private val instance = object : MutableMap, AbstractMap() { + override val entries: MutableSet> get() = origin.value.entries + override val keys: MutableSet get() = origin.value.keys + override val values: MutableCollection get() = origin.value.values + override fun clear() = origin.value.clear() + override fun putAll(from: Map) = origin.value.putAll(from) + override fun remove(key: K): V? = origin.value.remove(key) + override fun put(key: K, value: V): V? = origin.value.put(key, value) override fun get(key: K): V? { // the only difference val result = origin.value[key] - if (result != null) { - return result - } + if (result != null) return result put(key, defaultValueComputer(key)) return origin.value[key] } @@ -62,25 +117,65 @@ public interface PluginDataExtensions { override var value: Map get() = instance set(value) { - origin.value = value + origin.value = value as MutableMap // erased cast } - } as Value, + } as Value>, // erased cast this.serializer ) - return pluginData.createCompositeMapValueImpl( - kToValue = origin.kToValue, - vToValue = origin.vToValue, - applyToShadowedMap = { theMap -> - object : MutableMap by theMap { - override fun get(key: K): V? { - val result = theMap[key] - if (result != null) return result - theMap[key] = defaultValueComputer(key) - return theMap[key] - } - } - } - ).let { SerializableValue(it, serializer) } as SerializerAwareValue } + + /** + * 替换 [MutableMap] 的 key + */ + @JvmName("mapKeys") + @JvmStatic + public fun SerializerAwareValue>.mapKeys( + oldToNew: (OldK) -> NewK, + newToOld: (NewK) -> OldK, + ): SerializerAwareValue> { + val origin = this + + @Suppress("UNCHECKED_CAST") + return SerializableValue( + object : CompositeMapValue { + private val instance = ShadowMap({ origin.value }, oldToNew, newToOld, { it }, { it }) + + override var value: Map + get() = instance + set(value) { + origin.value = value.mapKeysTo(LinkedHashMap()) { it.key.let(newToOld) } // erased cast + } + } as Value>, // erased cast + this.serializer + ) + } + + /** + * 替换 [Map] 的 key + */ + @JvmName("mapKeysImmutable") + @JvmStatic + public fun SerializerAwareValue>.mapKeys( + oldToNew: (OldK) -> NewK, + newToOld: (NewK) -> OldK, + ): SerializerAwareValue> { + val origin = this + + @Suppress("UNCHECKED_CAST") + return SerializableValue( + object : CompositeMapValue { + // casting Map to MutableMap is OK here, as we don't call mutable functions + private val instance = + ShadowMap({ origin.value as MutableMap }, oldToNew, newToOld, { it }, { it }) + + override var value: Map + get() = instance + set(value) { + origin.value = value.mapKeysTo(LinkedHashMap()) { it.key.let(newToOld) } // erased cast + } + } as Value>, // erased cast + this.serializer + ) + } } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt index 9719df5a9..2aa802f1e 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt @@ -240,10 +240,13 @@ public interface PrimitiveLongSetValue : PrimitiveSetValue * @see [CompositeMapValue] * @see [PrimitiveMapValue] */ +@ConsoleExperimentalAPI public interface MapValue : CompositeValue> +@ConsoleExperimentalAPI public interface CompositeMapValue : MapValue +@ConsoleExperimentalAPI public interface PrimitiveMapValue : MapValue diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt index 0218f3a3e..c9260c82d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt @@ -20,20 +20,20 @@ import kotlin.reflect.KClass internal open class ShadowMap( - private val originMap: MutableMap, + private val originMapComputer: () -> MutableMap, private val kTransform: (K) -> KR, private val kTransformBack: (KR) -> K, private val vTransform: (V) -> VR, private val vTransformBack: (VR) -> V ) : MutableMap { - override val size: Int get() = originMap.size - override fun containsKey(key: KR): Boolean = originMap.containsKey(key.let(kTransformBack)) - override fun containsValue(value: VR): Boolean = originMap.containsValue(value.let(vTransformBack)) - override fun get(key: KR): VR? = originMap[key.let(kTransformBack)]?.let(vTransform) - override fun isEmpty(): Boolean = originMap.isEmpty() + override val size: Int get() = originMapComputer().size + override fun containsKey(key: KR): Boolean = originMapComputer().containsKey(key.let(kTransformBack)) + override fun containsValue(value: VR): Boolean = originMapComputer().containsValue(value.let(vTransformBack)) + override fun get(key: KR): VR? = originMapComputer()[key.let(kTransformBack)]?.let(vTransform) + override fun isEmpty(): Boolean = originMapComputer().isEmpty() override val entries: MutableSet> - get() = originMap.entries.shadowMap( + get() = originMapComputer().entries.shadowMap( transform = { entry: MutableMap.MutableEntry -> object : MutableMap.MutableEntry { override val key: KR get() = entry.key.let(kTransform) @@ -66,30 +66,30 @@ internal open class ShadowMap( } ) override val keys: MutableSet - get() = originMap.keys.shadowMap(kTransform, kTransformBack) + get() = originMapComputer().keys.shadowMap(kTransform, kTransformBack) override val values: MutableCollection - get() = originMap.values.shadowMap(vTransform, vTransformBack) + get() = originMapComputer().values.shadowMap(vTransform, vTransformBack) - override fun clear() = originMap.clear() + override fun clear() = originMapComputer().clear() override fun put(key: KR, value: VR): VR? = - originMap.put(key.let(kTransformBack), value.let(vTransformBack))?.let(vTransform) + originMapComputer().put(key.let(kTransformBack), value.let(vTransformBack))?.let(vTransform) override fun putAll(from: Map) { from.forEach { (kr, vr) -> - originMap[kr.let(kTransformBack)] = vr.let(vTransformBack) + originMapComputer()[kr.let(kTransformBack)] = vr.let(vTransformBack) } } - override fun remove(key: KR): VR? = originMap.remove(key.let(kTransformBack))?.let(vTransform) - override fun toString(): String = originMap.toString() - override fun hashCode(): Int = originMap.hashCode() + override fun remove(key: KR): VR? = originMapComputer().remove(key.let(kTransformBack))?.let(vTransform) + override fun toString(): String = originMapComputer().toString() + override fun hashCode(): Int = originMapComputer().hashCode() override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as ShadowMap<*, *, *, *> - if (originMap != other.originMap) return false + if (originMapComputer != other.originMapComputer) return false if (kTransform != other.kTransform) return false if (kTransformBack != other.kTransformBack) return false if (vTransform != other.vTransform) return false @@ -104,7 +104,7 @@ internal fun MutableMap.shadowMap( kTransformBack: (KR) -> K, vTransform: (V) -> VR, vTransformBack: (VR) -> V -): MutableMap = ShadowMap(this, kTransform, kTransformBack, vTransform, vTransformBack) +): MutableMap = ShadowMap({ this }, kTransform, kTransformBack, vTransform, vTransformBack) internal inline fun MutableCollection.shadowMap( crossinline transform: (E) -> R, diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt index 6c4515c2b..dcff96398 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt @@ -17,6 +17,8 @@ import kotlinx.coroutines.SupervisorJob import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.data.* +import net.mamoe.mirai.console.data.PluginDataExtensions.mapKeys +import net.mamoe.mirai.console.data.PluginDataExtensions.withEmptyDefault import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.util.BotManager import net.mamoe.mirai.contact.User @@ -44,7 +46,9 @@ internal object BotManagerImpl : BotManager { internal object ManagersConfig : AutoSavePluginConfig() { private val managers by value>>().withEmptyDefault() - internal operator fun get(bot: Bot): MutableSet = managers[bot.id]!! + .mapKeys(Bot::getInstance, Bot::id) + + internal operator fun get(bot: Bot): MutableSet = managers[bot]!! }