Move internal implementations of extensions into internal.extension

This commit is contained in:
Him188 2020-09-12 21:20:53 +08:00
parent 65cba4fd0b
commit 165f4d73b8
8 changed files with 177 additions and 158 deletions

View File

@ -18,9 +18,9 @@ import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.MiraiConsole.INSTANCE
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
import net.mamoe.mirai.console.extension.GlobalComponentStorage
import net.mamoe.mirai.console.extensions.BotConfigurationAlterer
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.center.PluginCenter
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader

View File

@ -9,17 +9,9 @@
package 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.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
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
/**
* 组件容器, 容纳 [Plugin] 注册的 [Extension].
@ -41,146 +33,3 @@ public interface ComponentStorage {
)
}
internal object GlobalComponentStorage : AbstractConcurrentComponentStorage()
internal interface ExtensionRegistry<out E : Extension> {
val plugin: Plugin
val extension: E
operator fun component1(): Plugin {
return this.plugin
}
operator fun component2(): E {
return this.extension
}
}
internal class LazyExtensionRegistry<out E : Extension>(
override val plugin: Plugin,
initializer: () -> E,
) : ExtensionRegistry<E> {
override val extension: E by lazy { initializer() }
}
internal data class DataExtensionRegistry<out E : Extension>(
override val plugin: Plugin,
override val extension: E,
) : ExtensionRegistry<E>
internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
@Suppress("UNCHECKED_CAST")
internal fun <T : Extension> ExtensionPoint<out T>.getExtensions(): Set<ExtensionRegistry<T>> {
return instances.getOrPut(this, ::CopyOnWriteArraySet) as Set<ExtensionRegistry<T>>
}
internal fun mergeWith(another: AbstractConcurrentComponentStorage) {
for ((ep, list) in another.instances) {
for (extensionRegistry in list) {
@Suppress("UNCHECKED_CAST")
ep as ExtensionPoint<Extension>
this.contribute(ep, extensionRegistry.plugin, lazyInstance = { extensionRegistry.extension })
}
}
}
internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.() -> Unit) {
return withExtensions { _ -> block() }
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<out T>.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 <reified E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(builtin: E): E =
findSingleton(E::class, builtin)
internal fun <E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(type: KClass<E>, 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 <reified E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(builtin: T): T =
findSingletonInstance(E::class, builtin)
internal fun <E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(
type: KClass<E>,
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 <T : Extension, E> ExtensionPoint<out T>.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 <T : Extension> ExtensionPoint<out T>.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 <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T) -> Unit): Unit =
withExtensions(block)
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T, plugin: Plugin) -> Unit): Unit =
withExtensions(block)
val instances: MutableMap<ExtensionPoint<*>, MutableSet<ExtensionRegistry<*>>> = ConcurrentHashMap()
override fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin,
extensionInstance: T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
}
override fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin,
lazyInstance: () -> T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
}
}

View File

@ -10,6 +10,7 @@
package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.extensions.*
import net.mamoe.mirai.console.internal.extension.AbstractConcurrentComponentStorage
import net.mamoe.mirai.console.permission.PermissionService
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.loader.PluginLoader

View File

@ -10,8 +10,13 @@
package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.extension.*
import net.mamoe.mirai.console.internal.extensions.BuiltInSingletonExtensionSelector
import net.mamoe.mirai.console.extension.AbstractExtensionPoint
import net.mamoe.mirai.console.extension.Extension
import net.mamoe.mirai.console.extension.FunctionExtension
import net.mamoe.mirai.console.extension.SingletonExtension
import net.mamoe.mirai.console.internal.extension.BuiltInSingletonExtensionSelector
import net.mamoe.mirai.console.internal.extension.ExtensionRegistry
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.utils.info

View File

@ -27,7 +27,6 @@ import net.mamoe.mirai.console.command.Command.Companion.primaryName
import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.ConsoleCommandSender
import net.mamoe.mirai.console.data.PluginDataStorage
import net.mamoe.mirai.console.extension.GlobalComponentStorage
import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.extensions.PostStartupExtension
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
@ -35,7 +34,8 @@ import net.mamoe.mirai.console.internal.command.CommandManagerImpl
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScope
import net.mamoe.mirai.console.internal.data.castOrNull
import net.mamoe.mirai.console.internal.extensions.BuiltInSingletonExtensionSelector
import net.mamoe.mirai.console.internal.extension.BuiltInSingletonExtensionSelector
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
import net.mamoe.mirai.console.internal.util.autoHexToBytes

View File

@ -1,4 +1,4 @@
package net.mamoe.mirai.console.internal.extensions
package net.mamoe.mirai.console.internal.extension
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.console.MiraiConsole

View File

@ -0,0 +1,164 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 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
internal object GlobalComponentStorage : AbstractConcurrentComponentStorage()
internal interface ExtensionRegistry<out E : Extension> {
val plugin: Plugin
val extension: E
operator fun component1(): Plugin {
return this.plugin
}
operator fun component2(): E {
return this.extension
}
}
internal class LazyExtensionRegistry<out E : Extension>(
override val plugin: Plugin,
initializer: () -> E,
) : ExtensionRegistry<E> {
override val extension: E by lazy { initializer() }
}
internal data class DataExtensionRegistry<out E : Extension>(
override val plugin: Plugin,
override val extension: E,
) : ExtensionRegistry<E>
internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
@Suppress("UNCHECKED_CAST")
internal fun <T : Extension> ExtensionPoint<out T>.getExtensions(): Set<ExtensionRegistry<T>> {
return instances.getOrPut(this, ::CopyOnWriteArraySet) as Set<ExtensionRegistry<T>>
}
internal fun mergeWith(another: AbstractConcurrentComponentStorage) {
for ((ep, list) in another.instances) {
for (extensionRegistry in list) {
@Suppress("UNCHECKED_CAST")
ep as ExtensionPoint<Extension>
this.contribute(ep, extensionRegistry.plugin, lazyInstance = { extensionRegistry.extension })
}
}
}
internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.() -> Unit) {
return withExtensions { _ -> block() }
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<out T>.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 <reified E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(builtin: E): E =
findSingleton(E::class, builtin)
internal fun <E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(type: KClass<E>, 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 <reified E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(builtin: T): T =
findSingletonInstance(E::class, builtin)
internal fun <E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(
type: KClass<E>,
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 <T : Extension, E> ExtensionPoint<out T>.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 <T : Extension> ExtensionPoint<out T>.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 <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T) -> Unit): Unit =
withExtensions(block)
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T, plugin: Plugin) -> Unit): Unit =
withExtensions(block)
val instances: MutableMap<ExtensionPoint<*>, MutableSet<ExtensionRegistry<*>>> = ConcurrentHashMap()
override fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin,
extensionInstance: T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
}
override fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin,
lazyInstance: () -> T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
}
}

View File

@ -14,10 +14,10 @@ package net.mamoe.mirai.console.internal.plugin
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.extension.GlobalComponentStorage
import net.mamoe.mirai.console.extensions.PluginLoaderProvider
import net.mamoe.mirai.console.internal.data.cast
import net.mamoe.mirai.console.internal.data.mkdir
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.description.PluginDependency