Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
internal.extension.ComponentStorageInternal.kt Maven / Gradle / Ivy
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.console.internal.extension
import net.mamoe.mirai.console.extension.*
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector.ExtensionPoint.selectSingleton
import net.mamoe.mirai.console.internal.data.kClassQualifiedNameOrTip
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.name
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet
import kotlin.contracts.contract
import kotlin.reflect.KClass
/**
* The [ComponentStorage] containing all components provided by Mirai Console internals and installed plugins.
*/
internal object GlobalComponentStorage : AbstractConcurrentComponentStorage()
internal interface ExtensionRegistry {
val plugin: Plugin?
val extension: E
operator fun component1(): Plugin? {
return this.plugin
}
operator fun component2(): E {
return this.extension
}
}
internal class LazyExtensionRegistry(
override val plugin: Plugin?,
initializer: () -> E,
) : ExtensionRegistry {
override val extension: E by lazy { initializer() }
}
internal data class DataExtensionRegistry(
override val plugin: Plugin?,
override val extension: E,
) : ExtensionRegistry
internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
private val instances: MutableMap, MutableSet>> = ConcurrentHashMap()
@Suppress("UNCHECKED_CAST")
internal fun ExtensionPoint.getExtensions(): Set> {
val userDefined = instances.getOrPut(this, ::CopyOnWriteArraySet) as Set>
val builtins = if (this is AbstractInstanceExtensionPoint<*, *>) {
this.builtinImplementations.mapTo(HashSet()) { DataExtensionRegistry(null, it) } as Set>
} else null
return builtins?.plus(userDefined) ?: userDefined
}
// unused for now
internal fun removeExtensionsRegisteredByPlugin(plugin: Plugin) {
instances.forEach { (_, u) ->
u.removeAll { it.plugin == plugin }
}
}
internal fun mergeWith(another: AbstractConcurrentComponentStorage) {
for ((ep, list) in another.instances) {
for (extensionRegistry in list) {
@Suppress("UNCHECKED_CAST")
ep as ExtensionPoint
this.contribute(ep, extensionRegistry.plugin, lazyInstance = { extensionRegistry.extension })
}
}
}
internal inline fun ExtensionPoint.withExtensions(block: T.() -> Unit) {
return withExtensions { _ -> block() }
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun ExtensionPoint.withExtensions(block: T.(plugin: Plugin?) -> Unit) {
contract {
callsInPlace(block)
}
for ((plugin, extension) in this.getExtensions()) {
kotlin.runCatching {
block.invoke(extension, plugin)
}.getOrElse { throwable ->
throwExtensionException(extension, plugin, throwable)
}
}
}
internal inline fun > ExtensionPoint.findSingleton(builtin: E): E =
findSingleton(E::class, builtin)
internal fun > ExtensionPoint.findSingleton(type: KClass, builtin: E): E {
val candidates = this.getExtensions()
return when (candidates.size) {
0 -> builtin
1 -> candidates.single().extension
else -> SingletonExtensionSelector.instance.selectSingleton(type, candidates) ?: builtin
}
}
internal inline fun , T> ExtensionPoint.findSingletonInstance(builtin: T): T =
findSingletonInstance(E::class, builtin)
internal fun , T> ExtensionPoint.findSingletonInstance(
type: KClass,
builtin: T,
): T {
val candidates = this.getExtensions()
return when (candidates.size) {
0 -> builtin
1 -> candidates.single().extension.instance
else -> SingletonExtensionSelector.instance.selectSingleton(type, candidates)?.instance ?: builtin
}
}
internal inline fun ExtensionPoint.foldExtensions(
initial: E,
block: (acc: E, extension: T) -> E,
): E {
contract {
callsInPlace(block)
}
var e: E = initial
for ((plugin, extension) in this.getExtensions()) {
kotlin.runCatching {
e = block.invoke(e, extension)
}.getOrElse { throwable ->
throwExtensionException(extension, plugin, throwable)
}
}
return e
}
internal fun ExtensionPoint.throwExtensionException(
extension: T,
plugin: Plugin?,
throwable: Throwable,
) {
throw ExtensionException(
"Exception while executing extension '${extension.kClassQualifiedNameOrTip}' provided by plugin '${plugin?.name ?: ""}', registered for '${this.extensionType.qualifiedName}'",
throwable
)
}
internal inline fun ExtensionPoint.useExtensions(block: (extension: T) -> Unit): Unit =
withExtensions(block)
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun ExtensionPoint.useExtensions(block: (extension: T, plugin: Plugin?) -> Unit): Unit =
withExtensions(block)
override fun contribute(
extensionPoint: ExtensionPoint,
plugin: Plugin,
extensionInstance: T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
}
@JvmName("contribute1")
fun contribute(
extensionPoint: ExtensionPoint,
plugin: Plugin?,
extensionInstance: T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
}
override fun contribute(
extensionPoint: ExtensionPoint,
plugin: Plugin,
lazyInstance: () -> T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
}
@JvmName("contribute1")
fun contribute(
extensionPoint: ExtensionPoint,
plugin: Plugin?,
lazyInstance: () -> T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
}
}