Introduce PluginDataExtensions

This commit is contained in:
Him188 2020-08-26 22:27:34 +08:00
parent a6aa160a97
commit 31cd77febf
5 changed files with 179 additions and 77 deletions

View File

@ -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` 初始化的属性列表.
*

View File

@ -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 <V, K> SerializerAwareValue<Map<K, V>>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue<Map<K, V>> {
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先放入一个 [LinkedHashMap], 再返回这个 [LinkedHashMap]
* @see withDefault
*/
@JvmName("withEmptyDefaultMapImmutable")
@JvmStatic
public fun <K, InnerE, InnerV> SerializerAwareValue<MutableMap<K, Map<InnerE, InnerV>>>.withEmptyDefault(): SerializerAwareValue<MutableMap<K, Map<InnerE, InnerV>>> {
return this.withDefault { LinkedHashMap() }
}
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先放入一个 [LinkedHashMap], 再返回这个 [LinkedHashMap]
* @see withDefault
*/
@JvmName("withEmptyDefaultMap")
@JvmStatic
public fun <K, InnerE, InnerV> SerializerAwareValue<MutableMap<K, MutableMap<InnerE, InnerV>>>.withEmptyDefault(): SerializerAwareValue<MutableMap<K, MutableMap<InnerE, InnerV>>> {
return this.withDefault { LinkedHashMap() }
}
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先放入一个 [ArrayList], 再返回这个 [ArrayList]
* @see withDefault
*/
@JvmName("withEmptyDefaultListImmutable")
@JvmStatic
public fun <K, E> SerializerAwareValue<MutableMap<K, List<E>>>.withEmptyDefault(): SerializerAwareValue<MutableMap<K, List<E>>> {
return this.withDefault { ArrayList() }
}
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先放入一个 [ArrayList], 再返回这个 [ArrayList]
* @see withDefault
*/
@JvmName("withEmptyDefaultList")
@JvmStatic
public fun <K, E> SerializerAwareValue<MutableMap<K, MutableList<E>>>.withEmptyDefault(): SerializerAwareValue<MutableMap<K, MutableList<E>>> {
return this.withDefault { ArrayList() }
}
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先放入一个 [LinkedHashSet], 再返回这个 [LinkedHashSet]
* @see withDefault
*/
@JvmName("withEmptyDefaultSetImmutable")
@JvmStatic
public fun <K, E> SerializerAwareValue<MutableMap<K, Set<E>>>.withEmptyDefault(): SerializerAwareValue<MutableMap<K, Set<E>>> {
return this.withDefault { LinkedHashSet() }
}
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先放入一个 [LinkedHashSet], 再返回这个 [LinkedHashSet]
* @see withDefault
*/
@JvmName("withEmptyDefaultSet")
@JvmStatic
public fun <K, E> SerializerAwareValue<MutableMap<K, MutableSet<E>>>.withEmptyDefault(): SerializerAwareValue<MutableMap<K, MutableSet<E>>> {
return this.withDefault { LinkedHashSet() }
}
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先调用 [defaultValueComputer] 并放入 [Map], 再返回调用的返回值
*/
@JvmStatic
@JvmName("withDefaultMapImmutable")
public fun <K, V> SerializerAwareValue<Map<K, V>>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue<Map<K, V>> {
@Suppress("UNCHECKED_CAST") // magic
return (this as SerializerAwareValue<MutableMap<K, V>>).withDefault(defaultValueComputer) as SerializerAwareValue<Map<K, V>>
}
@JvmName("withDefaultImmutableMap")
public fun <M : Map<K, V>, V : Map<*, *>, K> SerializerAwareValue<M>.withEmptyDefault(): SerializerAwareValue<M> {
return this.withDefault { LinkedHashMap<Any?, Any?>() as V }
}
@JvmName("withDefaultImmutableSet")
public fun <M : Map<K, V>, V : Set<*>, K> SerializerAwareValue<M>.withEmptyDefault(): SerializerAwareValue<M> {
return this.withDefault { LinkedHashSet<Any?>() as V }
}
@JvmName("withDefaultImmutableList")
public fun <M : Map<K, V>, V : List<*>, K> SerializerAwareValue<M>.withEmptyDefault(): SerializerAwareValue<M> {
return this.withDefault { ArrayList<Any?>() as V }
}
public fun <M : Map<K, V>, V, K> SerializerAwareValue<M>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue<M> {
val pluginData = this@PluginDataExtensions.castOrInternalError<PluginData>()
val origin = (this as SerializableValue<M>).delegate.castOrInternalError<CompositeMapValueImpl<K, V>>()
/**
* 创建一个代理对象, [Map.get] 返回 `null` 时先调用 [defaultValueComputer] 并放入 [Map], 再返回调用的返回值
*/
@JvmStatic
@JvmName("withDefaultMap")
public fun <K, V> SerializerAwareValue<MutableMap<K, V>>.withDefault(defaultValueComputer: (K) -> V): SerializerAwareValue<MutableMap<K, V>> {
val origin = this
@Suppress("UNCHECKED_CAST")
return SerializableValue(
object : CompositeMapValue<K, V> {
private val instance = object : MutableMap<K, V> {
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<MutableMap.MutableEntry<K, V>> get() = origin.value.entries as MutableSet<MutableMap.MutableEntry<K, V>>
override val keys: MutableSet<K> get() = origin.value.keys as MutableSet<K>
override val values: MutableCollection<V> get() = origin.value.values as MutableCollection<V>
override fun clear() = (origin.value as MutableMap<K, V>).clear()
override fun putAll(from: Map<out K, V>) = (origin.value as MutableMap<K, V>).putAll(from)
override fun remove(key: K): V? = (origin.value as MutableMap<K, V>).remove(key)
override fun put(key: K, value: V): V? = (origin.value as MutableMap<K, V>).put(key, value)
private val instance = object : MutableMap<K, V>, AbstractMap<K, V>() {
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = origin.value.entries
override val keys: MutableSet<K> get() = origin.value.keys
override val values: MutableCollection<V> get() = origin.value.values
override fun clear() = origin.value.clear()
override fun putAll(from: Map<out K, V>) = 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<K, V>
get() = instance
set(value) {
origin.value = value
origin.value = value as MutableMap<K, V> // erased cast
}
} as Value<M>,
} as Value<MutableMap<K, V>>, // erased cast
this.serializer
)
return pluginData.createCompositeMapValueImpl(
kToValue = origin.kToValue,
vToValue = origin.vToValue,
applyToShadowedMap = { theMap ->
object : MutableMap<K, V> 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<M>
}
/**
* 替换 [MutableMap] key
*/
@JvmName("mapKeys")
@JvmStatic
public fun <OldK, NewK, V> SerializerAwareValue<MutableMap<OldK, V>>.mapKeys(
oldToNew: (OldK) -> NewK,
newToOld: (NewK) -> OldK,
): SerializerAwareValue<MutableMap<NewK, V>> {
val origin = this
@Suppress("UNCHECKED_CAST")
return SerializableValue(
object : CompositeMapValue<NewK, V> {
private val instance = ShadowMap({ origin.value }, oldToNew, newToOld, { it }, { it })
override var value: Map<NewK, V>
get() = instance
set(value) {
origin.value = value.mapKeysTo(LinkedHashMap()) { it.key.let(newToOld) } // erased cast
}
} as Value<MutableMap<NewK, V>>, // erased cast
this.serializer
)
}
/**
* 替换 [Map] key
*/
@JvmName("mapKeysImmutable")
@JvmStatic
public fun <OldK, NewK, V> SerializerAwareValue<Map<OldK, V>>.mapKeys(
oldToNew: (OldK) -> NewK,
newToOld: (NewK) -> OldK,
): SerializerAwareValue<Map<NewK, V>> {
val origin = this
@Suppress("UNCHECKED_CAST")
return SerializableValue(
object : CompositeMapValue<NewK, V> {
// casting Map to MutableMap is OK here, as we don't call mutable functions
private val instance =
ShadowMap({ origin.value as MutableMap<OldK, V> }, oldToNew, newToOld, { it }, { it })
override var value: Map<NewK, V>
get() = instance
set(value) {
origin.value = value.mapKeysTo(LinkedHashMap()) { it.key.let(newToOld) } // erased cast
}
} as Value<Map<NewK, V>>, // erased cast
this.serializer
)
}
}

View File

@ -240,10 +240,13 @@ public interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
* @see [CompositeMapValue]
* @see [PrimitiveMapValue]
*/
@ConsoleExperimentalAPI
public interface MapValue<K, V> : CompositeValue<Map<K, V>>
@ConsoleExperimentalAPI
public interface CompositeMapValue<K, V> : MapValue<K, V>
@ConsoleExperimentalAPI
public interface PrimitiveMapValue<K, V> : MapValue<K, V>

View File

@ -20,20 +20,20 @@ import kotlin.reflect.KClass
internal open class ShadowMap<K, V, KR, VR>(
private val originMap: MutableMap<K, V>,
private val originMapComputer: () -> MutableMap<K, V>,
private val kTransform: (K) -> KR,
private val kTransformBack: (KR) -> K,
private val vTransform: (V) -> VR,
private val vTransformBack: (VR) -> V
) : MutableMap<KR, VR> {
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<MutableMap.MutableEntry<KR, VR>>
get() = originMap.entries.shadowMap(
get() = originMapComputer().entries.shadowMap(
transform = { entry: MutableMap.MutableEntry<K, V> ->
object : MutableMap.MutableEntry<KR, VR> {
override val key: KR get() = entry.key.let(kTransform)
@ -66,30 +66,30 @@ internal open class ShadowMap<K, V, KR, VR>(
}
)
override val keys: MutableSet<KR>
get() = originMap.keys.shadowMap(kTransform, kTransformBack)
get() = originMapComputer().keys.shadowMap(kTransform, kTransformBack)
override val values: MutableCollection<VR>
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<out KR, VR>) {
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 <K, V, KR, VR> MutableMap<K, V>.shadowMap(
kTransformBack: (KR) -> K,
vTransform: (V) -> VR,
vTransformBack: (VR) -> V
): MutableMap<KR, VR> = ShadowMap(this, kTransform, kTransformBack, vTransform, vTransformBack)
): MutableMap<KR, VR> = ShadowMap({ this }, kTransform, kTransformBack, vTransform, vTransformBack)
internal inline fun <E, R> MutableCollection<E>.shadowMap(
crossinline transform: (E) -> R,

View File

@ -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<MutableMap<Long, MutableSet<Long>>>().withEmptyDefault()
internal operator fun get(bot: Bot): MutableSet<Long> = managers[bot.id]!!
.mapKeys(Bot::getInstance, Bot::id)
internal operator fun get(bot: Bot): MutableSet<Long> = managers[bot]!!
}