Introduce InstanceExtensionPoint

This commit is contained in:
Him188 2020-10-20 13:47:43 +08:00
parent 2084f8154f
commit 58af1b3354
9 changed files with 60 additions and 20 deletions

View File

@ -2,6 +2,7 @@ package net.mamoe.mirai.console.command.parse
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.extensions.CommandCallParserProvider
import net.mamoe.mirai.console.internal.command.flattenCommandComponents
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.message.data.MessageChain
@ -20,4 +21,6 @@ public object SpaceSeparatedCommandCallParser : CommandCallParser {
valueArguments = flatten.drop(1).map(::InvariantCommandValueArgument)
)
}
public object Provider : CommandCallParserProvider(SpaceSeparatedCommandCallParser)
}

View File

@ -6,6 +6,7 @@ import net.mamoe.mirai.console.command.descriptor.*
import net.mamoe.mirai.console.command.descriptor.ArgumentAcceptance.Companion.isNotAcceptable
import net.mamoe.mirai.console.command.parse.CommandCall
import net.mamoe.mirai.console.command.parse.CommandValueArgument
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.cast
import net.mamoe.mirai.console.util.safeCast
@ -14,6 +15,8 @@ import java.util.*
@ConsoleExperimentalApi
@ExperimentalCommandDescriptors
public object BuiltInCommandCallResolver : CommandCallResolver {
public object Provider : CommandCallResolverProvider(BuiltInCommandCallResolver)
override fun resolve(call: CommandCall): ResolvedCommandCall? {
val callee = CommandManager.matchCommand(call.calleeName) ?: return null

View File

@ -24,6 +24,12 @@ public open class AbstractExtensionPoint<T : Extension>(
public override val extensionType: KClass<T>,
) : ExtensionPoint<T>
public open class InstanceExtensionPoint<E : InstanceExtension<T>, T>(
extensionType: KClass<E>,
public vararg val builtinImplementations: E,
) : AbstractExtensionPoint<E>(extensionType)
/**
* 表示一个 [SingletonExtension] [ExtensionPoint]
*/

View File

@ -11,13 +11,15 @@ package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.CommandCallParser
import net.mamoe.mirai.console.extension.AbstractExtensionPoint
import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.console.extension.InstanceExtensionPoint
/**
* The provider of [CommandCallParser]
*/
@ExperimentalCommandDescriptors
public interface CommandCallParserProvider : InstanceExtension<CommandCallParser> {
public companion object ExtensionPoint : AbstractExtensionPoint<CommandCallParserProvider>(CommandCallParserProvider::class)
public open class CommandCallParserProvider(override val instance: CommandCallParser) : InstanceExtension<CommandCallParser> {
public companion object ExtensionPoint :
InstanceExtensionPoint<CommandCallParserProvider, CommandCallParser>(CommandCallParserProvider::class, SpaceSeparatedCommandCallParser.Provider)
}

View File

@ -10,11 +10,13 @@
package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.resolve.BuiltInCommandCallResolver
import net.mamoe.mirai.console.command.resolve.CommandCallResolver
import net.mamoe.mirai.console.extension.AbstractExtensionPoint
import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.console.extension.InstanceExtensionPoint
@ExperimentalCommandDescriptors
public interface CommandCallResolverProvider : InstanceExtension<CommandCallResolver> {
public companion object ExtensionPoint : AbstractExtensionPoint<CommandCallResolverProvider>(CommandCallResolverProvider::class)
public open class CommandCallResolverProvider(override val instance: CommandCallResolver) : InstanceExtension<CommandCallResolver> {
public companion object ExtensionPoint :
InstanceExtensionPoint<CommandCallResolverProvider, CommandCallResolver>(CommandCallResolverProvider::class, BuiltInCommandCallResolver.Provider)
}

View File

@ -29,7 +29,7 @@ import kotlin.reflect.KClass
*/
public interface SingletonExtensionSelector : FunctionExtension {
public data class Registry<T : Extension>(
val plugin: Plugin,
val plugin: Plugin?,
val extension: T,
)
@ -55,11 +55,11 @@ public interface SingletonExtensionSelector : FunctionExtension {
instances.isEmpty() -> BuiltInSingletonExtensionSelector
instances.size == 1 -> {
instances.single().also { (plugin, ext) ->
MiraiConsole.mainLogger.info { "Loaded SingletonExtensionSelector: $ext from ${plugin.name}" }
MiraiConsole.mainLogger.info { "Loaded SingletonExtensionSelector: $ext from ${plugin?.name ?: "<builtin>"}" }
}.extension
}
else -> {
error("Found too many SingletonExtensionSelectors: ${instances.joinToString { (p, i) -> "'$i' from '${p.name}'" }}. Check your plugins and ensure there is only one external SingletonExtensionSelectors")
error("Found too many SingletonExtensionSelectors: ${instances.joinToString { (p, i) -> "'$i' from '${p?.name ?: "<builtin>"}'" }}. Check your plugins and ensure there is only one external SingletonExtensionSelectors")
}
}
}

View File

@ -52,7 +52,7 @@ internal object BuiltInSingletonExtensionSelector : SingletonExtensionSelector {
val candidatesList = candidates.toList()
for ((index, candidate) in candidatesList.withIndex()) {
MiraiConsole.mainLogger.info { "${index + 1}. '${candidate.extension}' from '${candidate.plugin.name}'" }
MiraiConsole.mainLogger.info { "${index + 1}. '${candidate.extension}' from '${candidate.plugin?.name ?: "<builtin>"}'" }
}
MiraiConsole.mainLogger.info { "Please choose a number from 1 to ${candidatesList.count()}" }

View File

@ -25,10 +25,10 @@ import kotlin.reflect.KClass
*/
internal object GlobalComponentStorage : AbstractConcurrentComponentStorage()
internal interface ExtensionRegistry<out E : Extension> {
val plugin: Plugin
val plugin: Plugin?
val extension: E
operator fun component1(): Plugin {
operator fun component1(): Plugin? {
return this.plugin
}
@ -38,21 +38,27 @@ internal interface ExtensionRegistry<out E : Extension> {
}
internal class LazyExtensionRegistry<out E : Extension>(
override val plugin: Plugin,
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 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>>
val userDefined = instances.getOrPut(this, ::CopyOnWriteArraySet) as Set<ExtensionRegistry<T>>
val builtins = if (this is InstanceExtensionPoint<*, *>) {
this.builtinImplementations.mapTo(HashSet()) { DataExtensionRegistry(null, it) } as Set<ExtensionRegistry<T>>
} else null
return builtins?.plus(userDefined) ?: userDefined
}
internal fun mergeWith(another: AbstractConcurrentComponentStorage) {
@ -71,7 +77,7 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.(plugin: Plugin) -> Unit) {
internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.(plugin: Plugin?) -> Unit) {
contract {
callsInPlace(block)
}
@ -131,11 +137,11 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
internal fun <T : Extension> ExtensionPoint<out T>.throwExtensionException(
extension: T,
plugin: Plugin,
plugin: Plugin?,
throwable: Throwable,
) {
throw ExtensionException(
"Exception while executing extension '${extension.kClassQualifiedNameOrTip}' provided by plugin '${plugin.name}', registered for '${this.extensionType.qualifiedName}'",
"Exception while executing extension '${extension.kClassQualifiedNameOrTip}' provided by plugin '${plugin?.name ?: "<builtin>"}', registered for '${this.extensionType.qualifiedName}'",
throwable
)
}
@ -145,7 +151,7 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T, plugin: Plugin) -> Unit): Unit =
internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T, plugin: Plugin?) -> Unit): Unit =
withExtensions(block)
val instances: MutableMap<ExtensionPoint<*>, MutableSet<ExtensionRegistry<*>>> = ConcurrentHashMap()
@ -157,6 +163,15 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
}
@JvmName("contribute1")
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,
@ -164,4 +179,13 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
}
@JvmName("contribute1")
fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin?,
lazyInstance: () -> T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
}
}

View File

@ -148,7 +148,7 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol
var count = 0
GlobalComponentStorage.run {
PluginLoaderProvider.useExtensions { ext, plugin ->
logger.info { "Loaded PluginLoader ${ext.instance} from ${plugin.name}" }
logger.info { "Loaded PluginLoader ${ext.instance} from ${plugin?.name ?: "<builtin>"}" }
_pluginLoaders.add(ext.instance)
count++
}