Him188 5 vuotta sitten
vanhempi
sitoutus
e53363482d
16 muutettua tiedostoa jossa 201 lisäystä ja 476 poistoa
  1. 3 0
      backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java
  2. 3 0
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt
  3. 3 12
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/internal/CompositeCommandInternal.kt
  4. 10 12
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/center/CuiPluginCenter.kt
  5. 4 4
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt
  6. 2 65
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt
  7. 9 4
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/SettingImpl.kt
  8. 4 3
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclarations.kt
  9. 2 2
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/collectionUtil.kt
  10. 138 0
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerHelper.kt
  11. 5 1
      backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt
  12. 16 19
      backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt
  13. 1 0
      build.gradle.kts
  14. 0 211
      mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
  15. 0 132
      mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParserContext.kt
  16. 1 11
      settings.gradle.kts

+ 3 - 0
backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java

@@ -8,6 +8,7 @@ import kotlinx.coroutines.CoroutineScope;
 import kotlinx.coroutines.CoroutineStart;
 import kotlinx.coroutines.future.FutureKt;
 import net.mamoe.mirai.console.plugin.jvm.JavaPlugin;
+import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI;
 import net.mamoe.mirai.message.data.Message;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -152,6 +153,7 @@ public final class JCommandManager {
      * @return 执行结果
      * @see #executeCommandDetailedAsync(CoroutineScope, CommandSender, Object...)
      */
+    @ConsoleExperimentalAPI
     @NotNull
     public static CommandExecuteResult executeCommandDetailed(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException {
         Objects.requireNonNull(sender, "sender");
@@ -171,6 +173,7 @@ public final class JCommandManager {
      * @return 执行结果
      * @see #executeCommandDetailed(CommandSender, Object...)
      */
+    @ConsoleExperimentalAPI
     @NotNull
     public static CompletableFuture<@NotNull CommandExecuteResult>
     executeCommandDetailedAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) {

+ 3 - 0
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt

@@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import net.mamoe.mirai.console.command.internal.*
 import net.mamoe.mirai.console.plugin.Plugin
+import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
 import net.mamoe.mirai.message.data.Message
 import net.mamoe.mirai.message.data.MessageChain
 
@@ -229,6 +230,7 @@ public suspend fun Command.execute(sender: CommandSender, vararg args: Any, chec
  *
  * @see JCommandManager.executeCommandDetailed Java 方法
  */
+@ConsoleExperimentalAPI
 public suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): CommandExecuteResult {
     if (messages.isEmpty()) return CommandExecuteResult.CommandNotFound("")
     return executeCommandDetailedInternal(messages, messages[0].toString().substringBefore(' '))
@@ -243,6 +245,7 @@ public suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): C
  *
  * @see JCommandManager.executeCommandDetailed Java 方法
  */
+@ConsoleExperimentalAPI
 public suspend fun CommandSender.executeCommandDetailed(messages: MessageChain): CommandExecuteResult {
     if (messages.isEmpty()) return CommandExecuteResult.CommandNotFound("")
     return executeCommandDetailedInternal(messages, messages[0].toString())

+ 3 - 12
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/internal/CompositeCommandInternal.kt

@@ -63,7 +63,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
         DefaultSubCommandDescriptor(
             "",
             permission,
-            onCommand = block2 { sender: CommandSender, args: Array<out Any> ->
+            onCommand = { sender: CommandSender, args: Array<out Any> ->
                 sender.onDefault(args)
             }
         )
@@ -292,7 +292,7 @@ internal fun AbstractReflectionCommand.createSubCommand(
         params,
         subDescription,
         overridePermission?.value?.getInstance() ?: permission,
-        onCommand = block { sender: CommandSender, args: Array<out Any> ->
+        onCommand = { sender: CommandSender, args: Array<out Any> ->
             val result = if (notStatic) {
                 if (hasSenderParam) {
                     function.isSuspend
@@ -311,13 +311,4 @@ internal fun AbstractReflectionCommand.createSubCommand(
         context = context,
         usage = buildUsage.toString()
     )
-}
-
-
-private fun block(block: suspend (CommandSender, Array<out Any>) -> Boolean): suspend (CommandSender, Array<out Any>) -> Boolean {
-    return block
-}
-
-private fun block2(block: suspend (CommandSender, Array<out Any>) -> Unit): suspend (CommandSender, Array<out Any>) -> Unit {
-    return block
-}
+}

+ 10 - 12
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/center/CuiPluginCenter.kt

@@ -11,22 +11,20 @@
 
 package net.mamoe.mirai.console.plugin.center
 
-import io.ktor.client.HttpClient
-import io.ktor.client.engine.cio.CIO
-import io.ktor.client.request.get
-import io.ktor.util.KtorExperimentalAPI
+import io.ktor.client.*
+import io.ktor.client.engine.cio.*
+import io.ktor.client.request.*
+import io.ktor.util.*
 import kotlinx.serialization.Serializable
-import kotlinx.serialization.UnstableDefault
 import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
 import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
 import net.mamoe.mirai.console.utils.retryCatching
 import java.io.File
 
-@OptIn(UnstableDefault::class)
-internal val json = runCatching {
-    Json(JsonConfiguration(isLenient = true, ignoreUnknownKeys = true))
-}.getOrElse { Json(JsonConfiguration.Stable) }
+internal val json = Json {
+    isLenient = true
+    ignoreUnknownKeys = true
+}
 
 @OptIn(KtorExperimentalAPI::class)
 internal val Http = HttpClient(CIO)
@@ -64,7 +62,7 @@ internal object CuiPluginCenter : PluginCenter {
         }.getOrElse { return null }
         if (result == "err:not found") return null
 
-        return json.parse(PluginCenter.PluginInfo.serializer(), result)
+        return json.decodeFromString(PluginCenter.PluginInfo.serializer(), result)
     }
 
     override suspend fun refresh() {
@@ -75,7 +73,7 @@ internal object CuiPluginCenter : PluginCenter {
             val result: List<PluginCenter.PluginInsight>
         )
 
-        val result = json.parse(Result.serializer(), Http.get("https://miraiapi.jasonczc.cn/getPluginList"))
+        val result = json.decodeFromString(Result.serializer(), Http.get("https://miraiapi.jasonczc.cn/getPluginList"))
 
         check(result.success) { "Failed to fetch plugin list from Cui Cloud" }
         plugins = result.result

+ 4 - 4
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt

@@ -69,25 +69,25 @@ public interface SerializerAwareValue<T> : Value<T> {
         @JvmStatic
         @ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
         public fun <T> SerializerAwareValue<T>.serialize(format: StringFormat): String {
-            return format.stringify(this.serializer, Unit)
+            return format.encodeToString(this.serializer, Unit)
         }
 
         @JvmStatic
         @ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
         public fun <T> SerializerAwareValue<T>.serialize(format: BinaryFormat): ByteArray {
-            return format.dump(this.serializer, Unit)
+            return format.encodeToByteArray(this.serializer, Unit)
         }
 
         @JvmStatic
         @ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
         public fun <T> SerializerAwareValue<T>.deserialize(format: StringFormat, value: String) {
-            format.parse(this.serializer, value)
+            format.decodeFromString(this.serializer, value)
         }
 
         @JvmStatic
         @ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
         public fun <T> SerializerAwareValue<T>.deserialize(format: BinaryFormat, value: ByteArray) {
-            format.load(this.serializer, value)
+            format.decodeFromByteArray(this.serializer, value)
         }
     }
 }

+ 2 - 65
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt

@@ -7,18 +7,15 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-@file:Suppress("NOTHING_TO_INLINE")
+@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
 
 package net.mamoe.mirai.console.setting.internal
 
-import kotlinx.serialization.*
-import kotlinx.serialization.builtins.*
+import kotlinx.serialization.KSerializer
 import net.mamoe.mirai.console.setting.SerializableValue.Companion.serializableValueWith
 import net.mamoe.mirai.console.setting.SerializerAwareValue
 import net.mamoe.mirai.console.setting.Setting
 import net.mamoe.mirai.console.setting.valueFromKType
-import net.mamoe.yamlkt.YamlDynamicSerializer
-import net.mamoe.yamlkt.YamlNullableDynamicSerializer
 import kotlin.reflect.KClass
 import kotlin.reflect.KType
 import kotlin.reflect.full.createInstance as createInstanceKotlin
@@ -142,63 +139,3 @@ internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
 @PublishedApi
 @Suppress("UNCHECKED_CAST")
 internal inline fun <R> Any.cast(): R = this as R
-
-/**
- * Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
- * Copyright 2017-2020 JetBrains s.r.o.
- */
-@Suppress(
-    "UNCHECKED_CAST",
-    "NO_REFLECTION_IN_CLASS_PATH",
-    "UNSUPPORTED",
-    "INVISIBLE_MEMBER",
-    "INVISIBLE_REFERENCE",
-    "IMPLICIT_CAST_TO_ANY"
-)
-@OptIn(ImplicitReflectionSerializer::class)
-internal fun serializerMirai(type: KType): KSerializer<Any?> {
-    fun serializerByKTypeImpl(type: KType): KSerializer<Any> {
-        val rootClass = when (val t = type.classifier) {
-            is KClass<*> -> t
-            else -> error("Only KClass supported as classifier, got $t")
-        } as KClass<Any>
-
-        val typeArguments = type.arguments
-            .map { requireNotNull(it.type) { "Star projections are not allowed, had $it instead" } }
-        return when {
-            typeArguments.isEmpty() -> rootClass.serializer()
-            else -> {
-                val serializers = typeArguments
-                    .map(::serializer)
-                // Array is not supported, see KT-32839
-                when (rootClass) {
-                    List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
-                    HashSet::class -> SetSerializer(serializers[0])
-                    Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
-                    HashMap::class -> MapSerializer(serializers[0], serializers[1])
-                    Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
-                    Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
-                    Pair::class -> PairSerializer(serializers[0], serializers[1])
-                    Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
-                    /* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
-                    else -> {
-                        if (isReferenceArray(type, rootClass)) {
-                            @Suppress("RemoveExplicitTypeArguments")
-                            return ArraySerializer<Any, Any?>(
-                                typeArguments[0].classifier as KClass<Any>,
-                                serializers[0]
-                            ).cast()
-                        }
-                        requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
-                            "Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +
-                                    "Make sure this class is marked as @Serializable or provide serializer explicitly."
-                        }
-                    }
-                }
-            }
-        }.cast()
-    }
-
-    val result = serializerByKTypeImpl(type)
-    return if (type.isMarkedNullable) result.nullable else result.cast()
-}

+ 9 - 4
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/SettingImpl.kt

@@ -11,9 +11,14 @@
 
 package net.mamoe.mirai.console.setting.internal
 
-import kotlinx.serialization.*
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
 import kotlinx.serialization.builtins.MapSerializer
 import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.CompositeDecoder
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
 import net.mamoe.mirai.console.setting.SerializerAwareValue
 import net.mamoe.mirai.console.setting.Setting
 import net.mamoe.mirai.console.setting.Value
@@ -53,7 +58,7 @@ internal abstract class SettingImpl {
         @Suppress("UNCHECKED_CAST")
         override fun deserialize(decoder: Decoder) {
             val descriptor = descriptor
-            with(decoder.beginStructure(descriptor, *settingUpdaterSerializerTypeArguments)) {
+            with(decoder.beginStructure(descriptor)) {
                 if (decodeSequentially()) {
                     var index = 0
                     repeat(decodeCollectionSize(descriptor)) {
@@ -70,7 +75,7 @@ internal abstract class SettingImpl {
                         var serialName: String? = null
                         innerLoop@ while (true) {
                             val index = decodeElementIndex(descriptor)
-                            if (index == CompositeDecoder.READ_DONE) {
+                            if (index == CompositeDecoder.DECODE_DONE) {
                                 check(serialName == null) { "name must be null at this moment." }
                                 break@outerLoop
                             }
@@ -102,7 +107,7 @@ internal abstract class SettingImpl {
         @Suppress("UNCHECKED_CAST")
         override fun serialize(encoder: Encoder, value: Unit) {
             val descriptor = descriptor
-            with(encoder.beginCollection(descriptor, valueNodes.size, *settingUpdaterSerializerTypeArguments)) {
+            with(encoder.beginCollection(descriptor, valueNodes.size)) {
                 var index = 0
 
                 // val vSerializer = settingUpdaterSerializerTypeArguments[1] as KSerializer<Any?>

+ 4 - 3
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclarations.kt

@@ -9,11 +9,11 @@
 
 package net.mamoe.mirai.console.setting.internal
 
-import kotlinx.serialization.Decoder
-import kotlinx.serialization.Encoder
 import kotlinx.serialization.KSerializer
-import kotlinx.serialization.SerialDescriptor
 import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
 import net.mamoe.mirai.console.setting.*
 
 /**
@@ -98,6 +98,7 @@ internal abstract class ShortValueImpl : ShortValue, SerializerAwareValue<Short>
         else value.hashCode() * 31
     }
 }
+
 internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit>, AbstractValueImpl<Int> {
     constructor()
     constructor(default: Int) {

+ 2 - 2
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/collectionUtil.kt

@@ -11,7 +11,7 @@
 
 package net.mamoe.mirai.console.setting.internal
 
-import kotlinx.serialization.ImplicitReflectionSerializer
+import kotlinx.serialization.UnsafeSerializationApi
 import kotlinx.serialization.serializer
 import net.mamoe.yamlkt.Yaml
 import kotlin.reflect.KClass
@@ -452,7 +452,7 @@ internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Un
 }
 
 
-@OptIn(ImplicitReflectionSerializer::class)
+@OptIn(UnsafeSerializationApi::class)
 internal fun <R : Any> Any.smartCastPrimitive(clazz: KClass<R>): R {
     kotlin.runCatching {
         return Yaml.default.parse(clazz.serializer(), this.toString())

+ 138 - 0
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerHelper.kt

@@ -0,0 +1,138 @@
+/*
+ * 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.setting.internal
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.UnsafeSerializationApi
+import kotlinx.serialization.builtins.*
+import kotlinx.serialization.serializer
+import net.mamoe.yamlkt.YamlDynamicSerializer
+import net.mamoe.yamlkt.YamlNullableDynamicSerializer
+import java.lang.reflect.Modifier
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+
+
+/**
+ * Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
+ * Copyright 2017-2020 JetBrains s.r.o.
+ */
+@OptIn(UnsafeSerializationApi::class)
+@Suppress(
+    "UNCHECKED_CAST",
+    "NO_REFLECTION_IN_CLASS_PATH",
+    "UNSUPPORTED",
+    "INVISIBLE_MEMBER",
+    "INVISIBLE_REFERENCE",
+    "IMPLICIT_CAST_TO_ANY"
+)
+internal fun serializerMirai(type: KType): KSerializer<Any?> {
+    fun serializerByKTypeImpl(type: KType): KSerializer<Any> {
+        val rootClass = type.kclass()
+
+        val typeArguments = type.arguments
+            .map { requireNotNull(it.type) { "Star projections in type arguments are not allowed, but had $type" } }
+        return when {
+            typeArguments.isEmpty() -> rootClass.serializer()
+            else -> {
+                val serializers = typeArguments
+                    .map(::serializer)
+                // Array is not supported, see KT-32839
+                when (rootClass) {
+                    List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
+                    HashSet::class -> SetSerializer(serializers[0])
+                    Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
+                    HashMap::class -> MapSerializer(serializers[0], serializers[1])
+                    Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
+                    Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
+                    Pair::class -> PairSerializer(serializers[0], serializers[1])
+                    Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
+                    /* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
+                    else -> {
+                        if (isReferenceArray(rootClass)) {
+                            return ArraySerializer(
+                                typeArguments[0].classifier as KClass<Any>,
+                                serializers[0]
+                            ).cast()
+                        }
+                        requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
+                            "Can't find a method to construct serializer for type ${rootClass.simpleName}. " +
+                                    "Make sure this class is marked as @Serializable or provide serializer explicitly."
+                        }
+                    }
+                }
+            }
+        }.cast()
+    }
+
+    val result = serializerByKTypeImpl(type)
+    return if (type.isMarkedNullable) result.nullable else result.cast()
+}
+
+
+/**
+ * Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
+ * Copyright 2017-2020 JetBrains s.r.o.
+ */
+@OptIn(UnsafeSerializationApi::class)
+@Suppress(
+    "UNCHECKED_CAST",
+    "NO_REFLECTION_IN_CLASS_PATH",
+    "UNSUPPORTED",
+    "INVISIBLE_MEMBER",
+    "INVISIBLE_REFERENCE",
+    "IMPLICIT_CAST_TO_ANY"
+)
+private fun <T : Any> KClass<T>.constructSerializerForGivenTypeArgs(vararg args: KSerializer<Any?>): KSerializer<T>? {
+    val jClass = this.java
+    // Search for serializer defined on companion object.
+    val companion =
+        jClass.declaredFields.singleOrNull { it.name == "Companion" }?.apply { isAccessible = true }?.get(null)
+    if (companion != null) {
+        val serializer = companion.javaClass.methods
+            .find { method ->
+                method.name == "serializer" && method.parameterTypes.size == args.size && method.parameterTypes.all { it == KSerializer::class.java }
+            }
+            ?.invoke(companion, *args) as? KSerializer<T>
+        if (serializer != null) return serializer
+    }
+    // Check whether it's serializable object
+    findObjectSerializer(jClass)?.let { return it }
+    // Search for default serializer if no serializer is defined in companion object.
+    return try {
+        jClass.declaredClasses.singleOrNull { it.simpleName == ("\$serializer") }
+            ?.getField("INSTANCE")?.get(null) as? KSerializer<T>
+    } catch (e: NoSuchFieldException) {
+        null
+    }
+}
+
+private fun <T : Any> findObjectSerializer(jClass: Class<T>): KSerializer<T>? {
+    // Check it is an object without using kotlin-reflect
+    val field =
+        jClass.declaredFields.singleOrNull { it.name == "INSTANCE" && it.type == jClass && Modifier.isStatic(it.modifiers) }
+            ?: return null
+    // Retrieve its instance and call serializer()
+    val instance = field.get(null)
+    val method =
+        jClass.methods.singleOrNull { it.name == "serializer" && it.parameters.isEmpty() && it.returnType == KSerializer::class.java }
+            ?: return null
+    val result = method.invoke(instance)
+    @Suppress("UNCHECKED_CAST")
+    return result as? KSerializer<T>
+}
+
+private fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass.java.isArray
+
+@Suppress("UNCHECKED_CAST")
+private fun KType.kclass() = when (val t = classifier) {
+    is KClass<*> -> t
+    else -> error("Only KClass supported as classifier, got $t")
+} as KClass<Any>

+ 5 - 1
backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt

@@ -9,7 +9,11 @@
 
 package net.mamoe.mirai.console.setting.internal
 
-import kotlinx.serialization.*
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
 import kotlin.reflect.KProperty
 import kotlin.reflect.full.findAnnotation
 

+ 16 - 19
backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt

@@ -9,9 +9,7 @@
 
 package net.mamoe.mirai.console.setting
 
-import kotlinx.serialization.UnstableDefault
 import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonConfiguration
 import net.mamoe.mirai.console.utils.ConsoleInternalAPI
 import org.junit.jupiter.api.Test
 import kotlin.test.assertEquals
@@ -34,20 +32,19 @@ internal class SettingTest {
         }
     }
 
-    @OptIn(UnstableDefault::class)
-    private val jsonPrettyPrint = Json(JsonConfiguration(prettyPrint = true))
-    private val json = Json(JsonConfiguration.Stable)
+    private val jsonPrettyPrint = Json { prettyPrint = true }
+    private val json = Json {}
 
     @Test
     fun testStringify() {
         val setting = MySetting()
 
-        var string = json.stringify(setting.updaterSerializer, Unit)
+        var string = json.encodeToString(setting.updaterSerializer, Unit)
         assertEquals("""{"int":1,"map":{},"map2":{}}""", string)
 
         setting.int = 2
 
-        string = json.stringify(setting.updaterSerializer, Unit)
+        string = json.encodeToString(setting.updaterSerializer, Unit)
         assertEquals("""{"int":2,"map":{},"map2":{}}""", string)
     }
 
@@ -57,10 +54,10 @@ internal class SettingTest {
 
         assertEquals(1, setting.int)
 
-        json.parse(
+        json.decodeFromString(
             setting.updaterSerializer, """
-            {"int":3,"map":{},"map2":{}}
-        """.trimIndent()
+                {"int":3,"map":{},"map2":{}}
+            """.trimIndent()
         )
 
         assertEquals(3, setting.int)
@@ -77,10 +74,10 @@ internal class SettingTest {
 
         assertEquals(mutableMapOf(), delegation()) // delegation
 
-        json.parse(
+        json.decodeFromString(
             setting.updaterSerializer, """
-            {"int":1,"map":{"t":"test"},"map2":{}}
-        """.trimIndent()
+                {"int":1,"map":{"t":"test"},"map2":{}}
+            """.trimIndent()
         )
 
         assertEquals(mapOf("t" to "test").toString(), delegation().toString())
@@ -100,10 +97,10 @@ internal class SettingTest {
 
         assertEquals(mutableMapOf(), delegation()) // delegation
 
-        json.parse(
+        json.decodeFromString(
             setting.updaterSerializer, """
-            {"int":1,"map":{},"map2":{"t":{"f":"test"}}}
-        """.trimIndent()
+                {"int":1,"map":{},"map2":{"t":{"f":"test"}}}
+            """.trimIndent()
         )
 
         assertEquals(mapOf("t" to mapOf("f" to "test")).toString(), delegation().toString())
@@ -125,10 +122,10 @@ internal class SettingTest {
 
         assertEquals(mutableMapOf(), delegation()) // delegation
 
-        json.parse(
+        json.decodeFromString(
             setting.updaterSerializer, """
-            {"int":1,"map":{},"map2":{"t":{"f":"test"}}}
-        """.trimIndent()
+                {"int":1,"map":{},"map2":{"t":{"f":"test"}}}
+            """.trimIndent()
         )
 
         assertEquals(mapOf("f" to "test").toString(), delegation().toString())

+ 1 - 0
build.gradle.kts

@@ -2,6 +2,7 @@
 plugins {
     id("com.jfrog.bintray") version Versions.bintray apply false
 }
+
 tasks.withType(JavaCompile::class.java) {
     options.encoding = "UTF8"
 }

+ 0 - 211
mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt

@@ -1,211 +0,0 @@
-/*
- * 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
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.io.charsets.Charset
-import net.mamoe.mirai.Bot
-import net.mamoe.mirai.console.command.CommandManager
-import net.mamoe.mirai.console.command.DefaultCommands
-import net.mamoe.mirai.console.plugins.PluginManager
-import net.mamoe.mirai.console.utils.MiraiConsoleUI
-import net.mamoe.mirai.utils.SimpleLogger.LogPriority
-import net.mamoe.mirai.utils.WeakRef
-import java.io.ByteArrayOutputStream
-import java.io.PrintStream
-import kotlin.coroutines.EmptyCoroutineContext
-
-
-object MiraiConsole : CoroutineScope by CoroutineScope(EmptyCoroutineContext) {
-    /**
-     * 发布的版本名
-     */
-    const val build = "Pkmon"
-
-    lateinit var version: String
-        internal set
-
-    /**
-     * 获取从Console登陆上的Bot, Bots
-     * */
-    @Suppress("DEPRECATION")
-    @Deprecated(
-        "use Bot.botInstances from mirai-core",
-        replaceWith = ReplaceWith("Bot.instances", "net.mamoe.mirai.Bot"),
-        level = DeprecationLevel.ERROR
-    )
-    val bots: List<WeakRef<Bot>>
-        @Suppress("DEPRECATION_ERROR")
-        get() = Bot.instances
-
-    fun getBotOrNull(uin: Long): Bot? {
-        return Bot.botInstances.firstOrNull { it.id == uin }
-    }
-
-    class BotNotFoundException(uin: Long) : Exception("Bot $uin Not Found")
-
-    fun getBotOrThrow(uin: Long): Bot {
-        return Bot.botInstances.firstOrNull { it.id == uin } ?: throw BotNotFoundException(uin)
-    }
-
-    /**
-     * 与前端交互所使用的Logger
-     */
-    internal var logger = MiraiConsoleLogger
-
-    /**
-     * Console运行路径
-     */
-    lateinit var path: String
-        internal set
-
-    /**
-     * Console前端接口
-     */
-    lateinit var frontEnd: MiraiConsoleUI
-        internal set
-
-
-    private var started = false
-
-
-    @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
-    @Suppress("FunctionName")
-    @JvmSynthetic
-    @JvmStatic
-    fun /* synthetic */`start$default`(
-        miraiConsole: MiraiConsole,
-        miraiConsoleUI: MiraiConsoleUI?,
-        string: String?,
-        string2: String?,
-        n: Int,
-        @Suppress("UNUSED_PARAMETER") `object`: Any?
-    ) {
-        @Suppress("NAME_SHADOWING")
-        var string = string
-
-        @Suppress("NAME_SHADOWING")
-        var string2 = string2
-        if (n and 2 != 0) {
-            string = "0.0.0"
-        }
-        if (n and 4 != 0) {
-            string2 = "0.0.0"
-        }
-        miraiConsole.start(miraiConsoleUI!!, string!!, string2!!)
-    }
-
-    /**
-     * 启动Console
-     */
-    @JvmOverloads
-    fun start(
-        frontEnd: MiraiConsoleUI,
-        coreVersion: String = "0.0.0",
-        consoleVersion: String = "0.0.0",
-        path: String = System.getProperty("user.dir")
-    ) {
-        if (started) {
-            return
-        }
-        started = true
-        this.path = path
-        /* 初始化前端 */
-        this.version = consoleVersion
-        this.frontEnd = frontEnd
-        this.frontEnd.pushVersion(consoleVersion, build, coreVersion)
-        logger("Mirai-console now running under $path")
-        logger("Get news in github: https://github.com/mamoe/mirai")
-        logger("Mirai为开源项目,请自觉遵守开源项目协议")
-        logger("Powered by Mamoe Technologies and contributors")
-
-        /* 依次启用功能 */
-        DefaultCommands()
-        PluginManager.loadPlugins()
-        CommandManager.start()
-
-        /* 通知启动完成 */
-        logger("Mirai-console 启动完成")
-        logger("\"login qqnumber qqpassword \" to login a bot")
-        logger("\"login qq号 qq密码 \" 来登录一个BOT")
-
-        /* 尝试从系统配置自动登录 */
-        DefaultCommands.tryLoginAuto()
-    }
-
-    /**
-     * 关闭 Console
-     */
-    fun stop() {
-        PluginManager.disablePlugins()
-        CommandManager.cancel()
-        try {
-            Bot.botInstances.forEach {
-                it.close()
-            }
-        } catch (ignored: Exception) {
-        }
-    }
-}
-
-
-internal object MiraiConsoleLogger {
-    operator fun invoke(any: Any?) {
-        invoke(
-            "[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
-            0L,
-            any
-        )
-    }
-
-    operator fun invoke(e: Throwable?) {
-        invoke(
-            "[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
-            0L,
-            e
-        )
-    }
-
-    operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, any: Any? = null) {
-        if (any != null) {
-            MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, "$any")
-        }
-    }
-
-    operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, e: Throwable? = null) {
-        if (e != null) {
-            MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, e.stacktraceString)
-        }
-    }
-
-    // 设置默认的pushLog输出为 INFO 类型
-    operator fun invoke(identityStr: String, identity: Long, any: Any? = null) {
-        if (any != null) {
-            MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "$any")
-        }
-    }
-
-    operator fun invoke(identityStr: String, identity: Long, e: Throwable? = null) {
-        if (e != null) {
-            MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, e.stacktraceString)
-        }
-    }
-}
-
-internal val Throwable.stacktraceString: String
-    get() =
-        ByteArrayOutputStream().apply {
-            printStackTrace(PrintStream(this))
-        }.use { it.toByteArray().encodeToString() }
-
-
-@Suppress("NOTHING_TO_INLINE")
-internal inline fun ByteArray.encodeToString(charset: Charset = Charsets.UTF_8): String =
-    kotlinx.io.core.String(this, charset = charset)

+ 0 - 132
mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParserContext.kt

@@ -1,132 +0,0 @@
-/*
- * 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
- */
-
-@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "unused", "MemberVisibilityCanBePrivate")
-
-package net.mamoe.mirai.console.command
-
-import net.mamoe.mirai.Bot
-import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node
-import net.mamoe.mirai.contact.Friend
-import net.mamoe.mirai.contact.Group
-import net.mamoe.mirai.contact.Member
-import kotlin.internal.LowPriorityInOverloadResolution
-import kotlin.reflect.KClass
-
-
-/**
- * [KClass] 到 [CommandArgParser] 的匹配
- */
-interface CommandParserContext {
-    operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
-
-    /**
-     * 内建的默认 [CommandArgParser]
-     */
-    object Builtins : CommandParserContext by (CommandParserContext {
-        Int::class with IntArgParser
-        Byte::class with ByteArgParser
-        Short::class with ShortArgParser
-        Boolean::class with BooleanArgParser
-        String::class with StringArgParser
-        Long::class with LongArgParser
-        Double::class with DoubleArgParser
-        Float::class with FloatArgParser
-
-        Member::class with ExistMemberArgParser
-        Group::class with ExistGroupArgParser
-        Friend::class with ExistFriendArgParser
-        Bot::class with ExistBotArgParser
-    })
-}
-
-fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? = this[param.type]
-
-/**
- * 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
- */
-operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
-    return object : CommandParserContext {
-        override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
-    }
-}
-
-@Suppress("UNCHECKED_CAST")
-open class AbstractCommandParserContext(val list: List<Node<*>>) : CommandParserContext {
-    class Node<T : Any>(
-        val klass: KClass<T>,
-        val parser: CommandArgParser<T>
-    )
-
-    override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? =
-        this.list.firstOrNull { it.klass == klass }?.parser as CommandArgParser<T>?
-}
-
-/**
- * 构建一个 [CommandParserContext].
- *
- * ```
- * CommandParserContext {
- *     Int::class with IntArgParser
- *     Member::class with ExistMemberArgParser
- *     Group::class with { s: String, sender: CommandSender ->
- *          Bot.getInstance(s.toLong()).getGroup(s.toLong())
- *     }
- *     Bot::class with { s: String ->
- *          Bot.getInstance(s.toLong())
- *     }
- * }
- * ```
- */
-@Suppress("FunctionName")
-@JvmSynthetic
-inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
-    return AbstractCommandParserContext(
-        CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
-}
-
-/**
- * @see CommandParserContext
- */
-class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
-    @JvmName("add")
-    inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): Node<*> =
-        Node(this, parser)
-
-    /**
-     * 添加一个指令解析器
-     */
-    @JvmSynthetic
-    @LowPriorityInOverloadResolution
-    inline infix fun <T : Any> KClass<T>.with(
-        crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
-    ): Node<*> = Node(this, CommandArgParser(parser))
-
-    /**
-     * 添加一个指令解析器
-     */
-    @JvmSynthetic
-    inline infix fun <T : Any> KClass<T>.with(
-        crossinline parser: CommandArgParser<T>.(s: String) -> T
-    ): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
-}
-
-
-@PublishedApi
-internal inline fun <T, K> Iterable<T>.distinctByReversed(selector: (T) -> K): List<T> {
-    val set = HashSet<K>()
-    val list = ArrayList<T>()
-    for (i in list.indices.reversed()) {
-        val element = list[i]
-        if (set.add(element.let(selector))) {
-            list.add(element)
-        }
-    }
-    return list
-}

+ 1 - 11
settings.gradle.kts

@@ -1,21 +1,11 @@
 pluginManagement {
     repositories {
         mavenLocal()
+        gradlePluginPortal()
         jcenter()
         maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
         mavenCentral()
     }
-
-    resolutionStrategy {
-        eachPlugin {
-            val version = requested.version
-            when (requested.id.id) {
-                "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${version}")
-                "org.jetbrains.kotlin.plugin.serialization" -> useModule("org.jetbrains.kotlin:kotlin-serialization:${version}")
-                "com.jfrog.bintray" -> useModule("com.jfrog.bintray.gradle:gradle-bintray-plugin:$version")
-            }
-        }
-    }
 }
 
 rootProject.name = "mirai-console"