mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-02 04:30:25 +08:00
fix componentName and smartToString
This commit is contained in:
parent
c35c2c97c8
commit
3806d7ce78
@ -9,14 +9,11 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.internal.network.component
|
package net.mamoe.mirai.internal.network.component
|
||||||
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.*
|
||||||
import kotlin.reflect.KClassifier
|
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.KTypeParameter
|
|
||||||
import kotlin.reflect.full.allSupertypes
|
import kotlin.reflect.full.allSupertypes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key for specific component [T]. Component are not polymorphic.
|
* A key for specific component [T]. Components are not polymorphic.
|
||||||
*
|
*
|
||||||
* @param T is a type hint.
|
* @param T is a type hint.
|
||||||
*/
|
*/
|
||||||
@ -28,14 +25,36 @@ internal interface ComponentKey<T : Any> {
|
|||||||
* - If [qualified] is `true`, example: `net.mamoe.mirai.internal.network.components.PacketCodec`.
|
* - If [qualified] is `true`, example: `net.mamoe.mirai.internal.network.components.PacketCodec`.
|
||||||
*/
|
*/
|
||||||
fun componentName(qualified: Boolean = false): String {
|
fun componentName(qualified: Boolean = false): String {
|
||||||
return getComponentTypeArgumentClassifier().renderClassifier(fullName = qualified)
|
val argument = getComponentTypeArgument()
|
||||||
|
argument?.render(qualified)?.let { return it }
|
||||||
|
return argument?.type?.classifier.renderClassifier(qualified)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun smartToString(qualified: Boolean = false): String {
|
fun smartToString(qualified: Boolean = false): String {
|
||||||
return "ComponentKey<${componentName(qualified)}>"
|
return "ComponentKey<${componentName(qualified)}>"
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
companion object {
|
||||||
|
// reflection is slow, but it is initialized once only (if memory sufficient).
|
||||||
|
|
||||||
|
private fun KTypeProjection.render(
|
||||||
|
fullName: Boolean
|
||||||
|
): String? {
|
||||||
|
val projection = this
|
||||||
|
|
||||||
|
projection.type?.classifier?.let { classifier ->
|
||||||
|
if (classifier is KClass<*>) {
|
||||||
|
return classifier.run { if (fullName) qualifiedName else simpleName } ?: "?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projection.type?.arguments?.firstOrNull()?.let { argument ->
|
||||||
|
return argument.render(fullName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
private fun KClassifier?.renderClassifier(
|
private fun KClassifier?.renderClassifier(
|
||||||
fullName: Boolean
|
fullName: Boolean
|
||||||
): String {
|
): String {
|
||||||
@ -53,16 +72,16 @@ internal interface ComponentKey<T : Any> {
|
|||||||
val upperBounds = upperBounds
|
val upperBounds = upperBounds
|
||||||
return when (upperBounds.size) {
|
return when (upperBounds.size) {
|
||||||
0 -> toString()
|
0 -> toString()
|
||||||
1 -> "ComponentKey<${upperBounds[0].renderType(fullName)}>"
|
1 -> upperBounds[0].renderType(fullName)
|
||||||
else -> "ComponentKey<${upperBounds.joinToString(" & ") { it.renderType(fullName) }}>"
|
else -> upperBounds.joinToString(" & ") { it.renderType(fullName) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ComponentKey<*>.getComponentTypeArgumentClassifier(): KClassifier? {
|
private fun ComponentKey<*>.getComponentTypeArgument(): KTypeProjection? {
|
||||||
val thisType = this::class.allSupertypes.find { it.classifier == COMPONENT_KEY_K_CLASS }
|
val thisType = this::class.allSupertypes.find { it.classifier == COMPONENT_KEY_K_CLASS }
|
||||||
return thisType?.arguments?.firstOrNull()?.type?.classifier
|
return thisType?.arguments?.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
val COMPONENT_KEY_K_CLASS = ComponentKey::class
|
private val COMPONENT_KEY_K_CLASS = ComponentKey::class
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,10 +13,19 @@ import net.mamoe.mirai.internal.test.AbstractTest
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
private class TestComponent {
|
private open class TestComponent {
|
||||||
companion object : ComponentKey<TestComponent>
|
companion object : ComponentKey<TestComponent>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private interface MyInterface
|
||||||
|
|
||||||
|
private open class TestComponentExt : TestComponent(), MyInterface
|
||||||
|
|
||||||
|
private open class Key<R> : ComponentKey<R> where R : TestComponent, R : MyInterface
|
||||||
|
private class KeyActual : Key<TestComponentExt>()
|
||||||
|
|
||||||
|
|
||||||
internal class ComponentKeyTest : AbstractTest() {
|
internal class ComponentKeyTest : AbstractTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -25,9 +34,38 @@ internal class ComponentKeyTest : AbstractTest() {
|
|||||||
assertEquals(TestComponent::class.qualifiedName!!, TestComponent.componentName(true))
|
assertEquals(TestComponent::class.qualifiedName!!, TestComponent.componentName(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `componentName with erased type argument`() {
|
||||||
|
assertEquals(
|
||||||
|
"TestComponent & MyInterface",
|
||||||
|
Key<TestComponentExt>().componentName(false)
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"${TestComponent::class.qualifiedName!!} & ${MyInterface::class.qualifiedName!!}",
|
||||||
|
Key<TestComponentExt>().componentName(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `componentName with actual type argument`() {
|
||||||
|
assertEquals(
|
||||||
|
"TestComponentExt",
|
||||||
|
KeyActual().componentName(false)
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
TestComponentExt::class.qualifiedName!!,
|
||||||
|
KeyActual().componentName(true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test smartToString`() {
|
fun `test smartToString`() {
|
||||||
assertEquals("ComponentKey<TestComponent>", TestComponent.smartToString(false))
|
assertEquals("ComponentKey<TestComponent>", TestComponent.smartToString(false))
|
||||||
assertEquals("ComponentKey<${TestComponent::class.qualifiedName!!}>", TestComponent.smartToString(true))
|
assertEquals("ComponentKey<${TestComponent::class.qualifiedName!!}>", TestComponent.smartToString(true))
|
||||||
|
assertEquals(
|
||||||
|
"ComponentKey<${TestComponent::class.qualifiedName!!} & ${MyInterface::class.qualifiedName!!}>",
|
||||||
|
Key<TestComponentExt>().smartToString(true)
|
||||||
|
)
|
||||||
|
assertEquals("ComponentKey<${TestComponentExt::class.qualifiedName!!}>", KeyActual().smartToString(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user