mirror of
https://github.com/tursom/TursomServer.git
synced 2024-12-29 14:30:55 +08:00
update
This commit is contained in:
parent
b0cd840376
commit
cc32906fc9
@ -7,6 +7,7 @@ include("ts-core:ts-pool")
|
|||||||
include("ts-core:ts-hash")
|
include("ts-core:ts-hash")
|
||||||
include("ts-core:ts-log")
|
include("ts-core:ts-log")
|
||||||
include("ts-core:ts-delegation")
|
include("ts-core:ts-delegation")
|
||||||
|
include("ts-core:ts-delegation:ts-observer")
|
||||||
include("ts-core:ts-clone")
|
include("ts-core:ts-clone")
|
||||||
include("ts-core:ts-mail")
|
include("ts-core:ts-mail")
|
||||||
include("ts-core:ts-coroutine")
|
include("ts-core:ts-coroutine")
|
||||||
|
123
ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt
Normal file
123
ts-core/src/main/kotlin/cn/tursom/core/TextColor.kt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package cn.tursom.core
|
||||||
|
|
||||||
|
object TextColor {
|
||||||
|
const val reset = "\u001b[0m"
|
||||||
|
|
||||||
|
enum class DisplayType(val code: Int) {
|
||||||
|
DEFAULT(0), HIGHLIGHT(1), INTENSITY(2), ITALIC(3), UNDERLINE(4),
|
||||||
|
SLOW_BLINK(5), RAPID_BLINK(6), REVERSE(7), INVISIBLE(8), CROSSED_OUT(9),
|
||||||
|
UNDERLINE_OFF(24), BLINK_OFF(25), REVERSE_OFF(27), INVISIBLE_OFF(28), CROSSED_OUT_OFF(29),
|
||||||
|
OVER_LINE(53), OVER_LINE_OFF(55);
|
||||||
|
|
||||||
|
val strCode = "\u001b[${code}m"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun textColor(displayType: DisplayType, textColor: Int, backgroundColor: Int) =
|
||||||
|
"\u001B[${displayType.code};$textColor;${backgroundColor}m"
|
||||||
|
|
||||||
|
fun rgbTextColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) =
|
||||||
|
"\u001B[${displayType.code};38;2;$r;$g;${b}m"
|
||||||
|
|
||||||
|
fun rgbBackgroundColor(r: Int, g: Int, b: Int, displayType: DisplayType = DisplayType.DEFAULT) =
|
||||||
|
"\u001B[${displayType.code};48;2;$r;$g;${b}m"
|
||||||
|
|
||||||
|
const val black = "\u001b[30m"
|
||||||
|
const val red = "\u001b[31m"
|
||||||
|
const val green = "\u001b[32m"
|
||||||
|
const val yellow = "\u001b[33m"
|
||||||
|
const val blue = "\u001b[34m"
|
||||||
|
const val magenta = "\u001b[35m"
|
||||||
|
const val cyan = "\u001b[36m"
|
||||||
|
const val white = "\u001b[37m"
|
||||||
|
|
||||||
|
const val brightBlack = "\u001b[30;1m"
|
||||||
|
const val brightRed = "\u001b[31;1m"
|
||||||
|
const val brightGreen = "\u001b[32;1m"
|
||||||
|
const val brightYellow = "\u001b[33;1m"
|
||||||
|
const val brightBlue = "\u001b[34;1m"
|
||||||
|
const val brightMagenta = "\u001b[35;1m"
|
||||||
|
const val brightCyan = "\u001b[36;1m"
|
||||||
|
const val brightWhite = "\u001b[37;1m"
|
||||||
|
|
||||||
|
val textColor = Array(256) {
|
||||||
|
"\u001b[38;5;${it}m"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun textColor(color: Int) = textColor[color]
|
||||||
|
fun textColor(color: Int, displayType: DisplayType = DisplayType.DEFAULT) =
|
||||||
|
"\u001B[${displayType.code};38;5;${color}m"
|
||||||
|
|
||||||
|
const val blackBackground = "\u001b[40m"
|
||||||
|
const val redBackground = "\u001b[41m"
|
||||||
|
const val greenBackground = "\u001b[42m"
|
||||||
|
const val yellowBackground = "\u001b[43m"
|
||||||
|
const val blueBackground = "\u001b[44m"
|
||||||
|
const val magentaBackground = "\u001b[45m"
|
||||||
|
const val cyanBackground = "\u001b[46m"
|
||||||
|
const val whiteBackground = "\u001b[47m"
|
||||||
|
|
||||||
|
const val brightBlackBackground = "\u001b[40;1m"
|
||||||
|
const val brightRedBackground = "\u001b[41;1m"
|
||||||
|
const val brightGreenBackground = "\u001b[42;1m"
|
||||||
|
const val brightYellowBackground = "\u001b[43;1m"
|
||||||
|
const val brightBlueBackground = "\u001b[44;1m"
|
||||||
|
const val brightMagentaBackground = "\u001b[45;1m"
|
||||||
|
const val brightCyanBackground = "\u001b[46;1m"
|
||||||
|
const val brightWhiteBackground = "\u001b[47;1m"
|
||||||
|
|
||||||
|
val backgroundColor = Array(256) {
|
||||||
|
"\u001b[48;5;${it}m"
|
||||||
|
}
|
||||||
|
|
||||||
|
const val bold = "\u001b[1m"
|
||||||
|
const val underline = "\u001b[4m"
|
||||||
|
const val reverseColor = "\u001b[7m"
|
||||||
|
|
||||||
|
const val up = "\u001b[1A"
|
||||||
|
const val down = "\u001b[1B"
|
||||||
|
const val left = "\u001b[1C"
|
||||||
|
const val right = "\u001b[1D"
|
||||||
|
|
||||||
|
const val downToNextLine = "\u001b[1E"
|
||||||
|
const val upToPrevLine = "\u001b[1F"
|
||||||
|
|
||||||
|
fun up(step: Int) = "\u001b[${step}A"
|
||||||
|
fun down(step: Int) = "\u001b[${step}B"
|
||||||
|
fun left(step: Int) = "\u001b[${step}C"
|
||||||
|
fun right(step: Int) = "\u001b[${step}D"
|
||||||
|
|
||||||
|
fun downToNextLine(step: Int) = "\u001b[${step}E"
|
||||||
|
fun upToPrevLine(step: Int) = "\u001b[${step}F"
|
||||||
|
|
||||||
|
fun jumpToLine(line: Int) = "\u001b[${line}G"
|
||||||
|
fun jump(line: Int, row: Int) = "\u001b[${line};${row}H"
|
||||||
|
|
||||||
|
const val cleanScreenToEnd = "\u001b[0J"
|
||||||
|
const val cleanScreenFromStart = "\u001b[1J"
|
||||||
|
const val cleanScreen = "\u001b[2J"
|
||||||
|
|
||||||
|
const val cleanLineToEnd = "\u001b[0K"
|
||||||
|
const val cleanLineFromStart = "\u001b[1K"
|
||||||
|
const val cleanLine = "\u001b[2K"
|
||||||
|
|
||||||
|
const val savePosition = "\u001b[s"
|
||||||
|
const val loadPosition = "\u001b[u"
|
||||||
|
|
||||||
|
fun rgbTo8Color(R: Int, G: Int, B: Int): Int {
|
||||||
|
//8色化处理,取RGB的高1位相与。
|
||||||
|
val r1 = R shr 5 and 0x4
|
||||||
|
val g1 = G shr 6 and 0x2
|
||||||
|
val b1 = B shr 7
|
||||||
|
return (r1 or g1 or b1) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rgbTo16Color(R: Int, G: Int, B: Int): Int {
|
||||||
|
//16色化处理,取R、G的高1位和B的高2位相与
|
||||||
|
val r1 = R shr 4 and 0x8
|
||||||
|
val g1 = G shr 5 and 0x4
|
||||||
|
val b1 = B shr 6 and 0x3
|
||||||
|
return (r1 or g1 or b1) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rgbTo256Color(r: Int, g: Int, b: Int): Int = ((r / 32 shl 5) + (g / 32 shl 2) + b / 64) and 0xFF
|
||||||
|
}
|
@ -53,8 +53,12 @@ object Utils {
|
|||||||
.create()
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
internal val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
|
internal val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
internal val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray()
|
internal val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray()
|
||||||
|
|
||||||
val md5 by lazy { MessageDigest.getInstance("MD5")!! }
|
val md5 by lazy { MessageDigest.getInstance("MD5")!! }
|
||||||
val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! }
|
val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! }
|
||||||
val sha by lazy { MessageDigest.getInstance("SHA")!! }
|
val sha by lazy { MessageDigest.getInstance("SHA")!! }
|
||||||
@ -62,6 +66,7 @@ object Utils {
|
|||||||
val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! }
|
val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! }
|
||||||
val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! }
|
val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! }
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
internal val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray()
|
internal val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray()
|
||||||
|
|
||||||
val receiverField: Field by lazy {
|
val receiverField: Field by lazy {
|
||||||
@ -135,7 +140,7 @@ inline fun <T> T?.checkNull(ifNull: () -> Exception): T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.emptyToNull() = if (isEmpty()) null else this
|
fun String.emptyToNull() = ifEmpty { null }
|
||||||
|
|
||||||
inline fun <reified T> getClazz() = T::class.java
|
inline fun <reified T> getClazz() = T::class.java
|
||||||
|
|
||||||
@ -251,7 +256,7 @@ fun <A : Annotation, V : Any> A.changeAnnotationValue(field: KProperty1<A, V>, v
|
|||||||
val h = Proxy.getInvocationHandler(this)
|
val h = Proxy.getInvocationHandler(this)
|
||||||
val memberValuesField = h.javaClass.getDeclaredField("memberValues")
|
val memberValuesField = h.javaClass.getDeclaredField("memberValues")
|
||||||
memberValuesField.isAccessible = true
|
memberValuesField.isAccessible = true
|
||||||
val memberValues = memberValuesField[h].cast<MutableMap<String, Any>>()
|
val memberValues = memberValuesField[h].uncheckedCast<MutableMap<String, Any>>()
|
||||||
memberValues[field.name] = value
|
memberValues[field.name] = value
|
||||||
true
|
true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -366,7 +371,7 @@ val KProperty<*>.receiver: Any?
|
|||||||
|
|
||||||
val KProperty<*>.owner: Class<*>?
|
val KProperty<*>.owner: Class<*>?
|
||||||
get() = try {
|
get() = try {
|
||||||
Utils.ownerField.get(this)?.cast<Class<*>>()
|
Utils.ownerField.get(this)?.uncheckedCast<Class<*>>()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
} ?: javaClass.getFieldForAll("owner")?.let {
|
} ?: javaClass.getFieldForAll("owner")?.let {
|
||||||
@ -406,16 +411,6 @@ fun Any.serialize(): ByteArray {
|
|||||||
return outputStream.toByteArray()
|
return outputStream.toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline infix fun String.ifEmpty(ifEmpty: () -> String) = if (isNotEmpty()) this else ifEmpty()
|
|
||||||
inline infix fun String.ifBlank(ifBlank: () -> String) = if (isNotBlank()) this else ifBlank()
|
|
||||||
|
|
||||||
@JvmName("ifEmptyNullable")
|
|
||||||
inline fun String.ifEmpty(ifEmpty: () -> String?) = if (isNotEmpty()) this else ifEmpty()
|
|
||||||
|
|
||||||
@JvmName("ifBlankNullable")
|
|
||||||
inline fun String.ifBlank(ifBlank: () -> String?) = if (isNotBlank()) this else ifBlank()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用 condition 做条件判断,如果返回 true 则使用 then 生成结果,否则范湖自身
|
* 使用 condition 做条件判断,如果返回 true 则使用 then 生成结果,否则范湖自身
|
||||||
*/
|
*/
|
||||||
@ -452,9 +447,9 @@ inline val KClass<*>.companionObjectInstanceOrNull: Any?
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
inline val <K : Any, V> Map<K?, V>.notNullKey get() = cast<Map<K, V>>()
|
inline val <K : Any, V> Map<K?, V>.notNullKey get() = uncheckedCast<Map<K, V>>()
|
||||||
inline val <K, V : Any> Map<K, V?>.notNullValue get() = cast<Map<K, V>>()
|
inline val <K, V : Any> Map<K, V?>.notNullValue get() = uncheckedCast<Map<K, V>>()
|
||||||
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = cast<Map<K, V>>()
|
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = uncheckedCast<Map<K, V>>()
|
||||||
|
|
||||||
inline val <K : Any, V> Map<K?, V>.filterNullKey get() = filter { it.key != null }.notNullKey
|
inline val <K : Any, V> Map<K?, V>.filterNullKey get() = filter { it.key != null }.notNullKey
|
||||||
inline val <K, V : Any> Map<K, V?>.filterNullValue get() = filter { it.value != null }.notNullValue
|
inline val <K, V : Any> Map<K, V?>.filterNullValue get() = filter { it.value != null }.notNullValue
|
||||||
@ -466,7 +461,7 @@ val <T : Any> KClass<T>.allMemberProperties: List<KProperty1<T, *>>
|
|||||||
!it.java.isInterface
|
!it.java.isInterface
|
||||||
}
|
}
|
||||||
while (superClass != null) {
|
while (superClass != null) {
|
||||||
propertiesList.addAll(superClass.memberProperties.cast())
|
propertiesList.addAll(superClass.memberProperties.uncheckedCast())
|
||||||
superClass = superClass.superclasses.firstOrNull {
|
superClass = superClass.superclasses.firstOrNull {
|
||||||
!it.java.isInterface
|
!it.java.isInterface
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":"))
|
implementation(project(":"))
|
||||||
implementation(project(":ts-core"))
|
implementation(project(":ts-core"))
|
||||||
|
implementation(project(":ts-core:ts-log"))
|
||||||
implementation(project(":ts-core:ts-datastruct"))
|
implementation(project(":ts-core:ts-datastruct"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package cn.tursom.core.clone
|
||||||
|
|
||||||
|
import cn.tursom.core.Unsafe
|
||||||
|
import cn.tursom.core.uncheckedCast
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
object InstantAllocator {
|
||||||
|
enum class AllocateFunction { INSTANCE, UNSAFE, KOBJECT, NONE }
|
||||||
|
|
||||||
|
private val allocateFunctionMap = ConcurrentHashMap<Class<*>, AllocateFunction>()
|
||||||
|
|
||||||
|
@Throws(NoSuchMethodException::class)
|
||||||
|
operator fun <T> invoke(clazz: Class<out T>, unsafe: Boolean = true): T = get(clazz, unsafe)
|
||||||
|
|
||||||
|
@Throws(NoSuchMethodException::class)
|
||||||
|
inline operator fun <reified T : Any> invoke(unsafe: Boolean = true): T = get(T::class.java, unsafe)
|
||||||
|
|
||||||
|
@Throws(NoSuchMethodException::class)
|
||||||
|
operator fun <T : Any> get(clazz: KClass<out T>, unsafe: Boolean = true): T = get(clazz.java, unsafe)
|
||||||
|
|
||||||
|
@Throws(NoSuchMethodException::class)
|
||||||
|
operator fun <T> get(clazz: Class<out T>, unsafe: Boolean = true): T {
|
||||||
|
return when (allocateFunctionMap[clazz]) {
|
||||||
|
null -> try {
|
||||||
|
val newInstance = clazz.newInstance()
|
||||||
|
allocateFunctionMap[clazz] = AllocateFunction.INSTANCE
|
||||||
|
newInstance
|
||||||
|
} catch (e: Exception) {
|
||||||
|
val kClass = clazz.kotlin
|
||||||
|
val objectInstance = kClass.objectInstance
|
||||||
|
if (objectInstance != null) {
|
||||||
|
allocateFunctionMap[clazz] = AllocateFunction.KOBJECT
|
||||||
|
objectInstance
|
||||||
|
} else if (unsafe) try {
|
||||||
|
allocateFunctionMap[clazz] = AllocateFunction.UNSAFE
|
||||||
|
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
allocateFunctionMap[clazz] = AllocateFunction.NONE
|
||||||
|
throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||||
|
} else {
|
||||||
|
throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllocateFunction.INSTANCE -> clazz.newInstance()
|
||||||
|
AllocateFunction.UNSAFE -> if (unsafe) {
|
||||||
|
Unsafe.unsafe.allocateInstance(clazz).uncheckedCast<T>()
|
||||||
|
} else {
|
||||||
|
throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||||
|
}
|
||||||
|
AllocateFunction.KOBJECT -> clazz.kotlin.objectInstance!!
|
||||||
|
AllocateFunction.NONE -> throw NoSuchMethodException("${clazz.name}:<init>()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,110 +1,22 @@
|
|||||||
@file:Suppress("unused")
|
|
||||||
|
|
||||||
package cn.tursom.core.clone
|
package cn.tursom.core.clone
|
||||||
|
|
||||||
import cn.tursom.core.Unsafe
|
import cn.tursom.core.*
|
||||||
import cn.tursom.core.cast
|
|
||||||
import cn.tursom.core.datastruct.ArrayMap
|
import cn.tursom.core.datastruct.ArrayMap
|
||||||
import cn.tursom.core.datastruct.KPropertyValueMap
|
import cn.tursom.log.impl.Slf4jImpl
|
||||||
import cn.tursom.core.datastruct.ReadWriteMap
|
|
||||||
import cn.tursom.core.datastruct.SoftArrayMap
|
|
||||||
import cn.tursom.core.final
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KMutableProperty1
|
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
import kotlin.reflect.full.findAnnotation
|
import kotlin.reflect.full.findAnnotation
|
||||||
import kotlin.reflect.full.memberProperties
|
|
||||||
import kotlin.reflect.jvm.isAccessible
|
|
||||||
import kotlin.reflect.jvm.javaField
|
|
||||||
import kotlin.reflect.jvm.javaType
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clone 使用的日志对象
|
||||||
|
*/
|
||||||
|
private val logger = Slf4jImpl.getLogger()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clone 使用的对象属性类型
|
||||||
|
*/
|
||||||
typealias Property<T> = KProperty1<T, Any?>
|
typealias Property<T> = KProperty1<T, Any?>
|
||||||
|
|
||||||
val Any.valueMap: Map<String, Any?>
|
|
||||||
get() = if (this is Map<*, *>) {
|
|
||||||
cast()
|
|
||||||
} else {
|
|
||||||
KPropertyValueMap(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val injectMapCache = ReadWriteMap<KClass<*>, ArrayMap<String, Property<*>?>>(SoftArrayMap(HashMap()))
|
|
||||||
|
|
||||||
val <T : Any> KClass<T>.injectMap: ArrayMap<String, Property<T>?>
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
get() = let {
|
|
||||||
var valueMap = injectMapCache[it] as ArrayMap<String, Property<T>?>?
|
|
||||||
if (valueMap == null) {
|
|
||||||
val properties = it.memberProperties
|
|
||||||
valueMap = ArrayMap(properties.size)
|
|
||||||
(properties as Collection<Property<T>>).forEach { property ->
|
|
||||||
property.isAccessible = true
|
|
||||||
valueMap[property.name] = property
|
|
||||||
}
|
|
||||||
injectMapCache[it] = valueMap as ArrayMap<String, Property<*>?>
|
|
||||||
}
|
|
||||||
valueMap.copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val <T : Any> T.injectMap: ArrayMap<String, Property<T>?>
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
get() = (this::class as KClass<T>).injectMap
|
|
||||||
|
|
||||||
private val <T> Array<out Pair<Property<*>, Property<T>?>>.injectMap get() = iterator().injectMap
|
|
||||||
private val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
|
|
||||||
get() = let {
|
|
||||||
val valueMap = ArrayMap<String, Property<T>?>()
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
forEach { (k, field) ->
|
|
||||||
field?.isAccessible = true
|
|
||||||
valueMap[k.name] = field
|
|
||||||
}
|
|
||||||
//logger.trace("Iterator.injectMap: {}", valueMap)
|
|
||||||
valueMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<T>?> = this::class
|
|
||||||
.cast<KClass<T>>()
|
|
||||||
.injectMap
|
|
||||||
.also {
|
|
||||||
if (clazz == null) return@also
|
|
||||||
val clazzThis = this::class.java
|
|
||||||
|
|
||||||
fun import(relation: Relation, property: Property<T>) {
|
|
||||||
if (relation.clazz != clazz) return
|
|
||||||
//logger.trace("relation {} to {}", relation.property, property.name)
|
|
||||||
it[relation.property] = when {
|
|
||||||
relation.skip -> null
|
|
||||||
relation.handler.isEmpty() -> property
|
|
||||||
else -> try {
|
|
||||||
val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java)
|
|
||||||
handler.isAccessible = true
|
|
||||||
object : KMutableProperty1<T, Any?>, KProperty1<T, Any?> by property {
|
|
||||||
override val setter: KMutableProperty1.Setter<T, Any?> get() = TODO()
|
|
||||||
override fun set(receiver: T, value: Any?) =
|
|
||||||
handler(this@injectMap, value).inject(receiver, property)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
//logger.warn("an exception caused on generate inject handler", e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun parseAnnotation(annotation: Annotation, property: Property<T>) {
|
|
||||||
when (annotation) {
|
|
||||||
is Relation -> import(annotation, property)
|
|
||||||
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this::class.memberProperties.cast<Collection<KProperty1<T, *>>>().forEach { property ->
|
|
||||||
property.annotations.forEach { annotation -> parseAnnotation(annotation, property) }
|
|
||||||
(property.javaField ?: return@forEach).annotations.forEach { annotation ->
|
|
||||||
parseAnnotation(annotation, property)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于形式化的将List中的数据映射到实体类上
|
* 用于形式化的将List中的数据映射到实体类上
|
||||||
@ -122,7 +34,7 @@ private fun <T : Any> T.injectMap(clazz: KClass<*>?): ArrayMap<String, Property<
|
|||||||
*/
|
*/
|
||||||
inline fun <reified T : Any, S : Any> List<S?>.clone(
|
inline fun <reified T : Any, S : Any> List<S?>.clone(
|
||||||
unsafe: Boolean = true,
|
unsafe: Boolean = true,
|
||||||
vararg relation: Pair<Property<S>, Property<T>?>
|
vararg relation: Pair<Property<S>, Property<T>?>,
|
||||||
): List<T> {
|
): List<T> {
|
||||||
val list = ArrayList<T>(size)
|
val list = ArrayList<T>(size)
|
||||||
val memberMap = T::class.injectMap
|
val memberMap = T::class.injectMap
|
||||||
@ -131,25 +43,28 @@ inline fun <reified T : Any, S : Any> List<S?>.clone(
|
|||||||
}
|
}
|
||||||
forEach {
|
forEach {
|
||||||
it ?: return@forEach
|
it ?: return@forEach
|
||||||
val target = instance<T>(unsafe) ?: return@forEach
|
try {
|
||||||
|
val target = InstantAllocator[T::class.java, unsafe]
|
||||||
list.add(it.inject(target, memberMap.iterator()))
|
list.add(it.inject(target, memberMap.iterator()))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any> List<Any?>.clone(
|
inline fun <reified T : Any> List<Any?>.clone(
|
||||||
unsafe: Boolean = true,
|
unsafe: Boolean = true,
|
||||||
vararg relation: Property<T>?
|
vararg relation: Property<T>?,
|
||||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||||
|
|
||||||
fun <T : Any> List<Any?>.clone(
|
fun <T : Any> List<Any?>.clone(
|
||||||
target: T,
|
target: T,
|
||||||
vararg relation: Property<T>?
|
vararg relation: Property<T>?,
|
||||||
): T = clone(target, relation.iterator())
|
): T = clone(target, relation.iterator())
|
||||||
|
|
||||||
fun <T : Any> List<Any?>.clone(
|
fun <T : Any> List<Any?>.clone(
|
||||||
target: T,
|
target: T,
|
||||||
relation: Iterator<Property<T>?>
|
relation: Iterator<Property<T>?>,
|
||||||
): T = relation.mapIndexed { index, kProperty1 ->
|
): T = relation.mapIndexed { index, kProperty1 ->
|
||||||
(kProperty1 ?: return@mapIndexed null).name to this[index]
|
(kProperty1 ?: return@mapIndexed null).name to this[index]
|
||||||
}.clone(target)
|
}.clone(target)
|
||||||
@ -157,29 +72,30 @@ fun <T : Any> List<Any?>.clone(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 新建并拷贝
|
* 新建并拷贝
|
||||||
|
* @author 王景阔
|
||||||
* 创建类型 T 的实例
|
* 创建类型 T 的实例
|
||||||
* 并将对象两个的所有同名字段拷贝进新建的实例中
|
* 并将对象两个的所有同名字段拷贝进新建的实例中
|
||||||
* @return 新建的实例
|
* @return 新建的实例
|
||||||
* @param unsafe 是否允许使用 Unsafe 创建对象,unsafe 不需调用构造函数,可以在没有默认构造函数的情况下生成对象
|
* @param unsafe 是否允许使用 Unsafe 创建对象,unsafe 不需调用构造函数,可以在没有默认构造函数的情况下生成对象
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(instance<T>(unsafe)!!)
|
inline fun <reified T : Any> Any.clone(unsafe: Boolean = true): T = clone(InstantAllocator[T::class.java, unsafe])
|
||||||
|
|
||||||
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(instance(unsafe, clazz)!!)
|
fun <T : Any> Any.clone(clazz: Class<T>, unsafe: Boolean = true): T = clone(InstantAllocator[clazz, unsafe])
|
||||||
|
|
||||||
@JvmName("unsafeClone")
|
@JvmName("unsafeClone")
|
||||||
inline fun <reified T : Any> Any.clone(
|
inline fun <reified T : Any> Any.clone(
|
||||||
unsafe: Boolean = true,
|
unsafe: Boolean = true,
|
||||||
vararg relation: Pair<String, Property<T>?>
|
vararg relation: Pair<String, Property<T>?>,
|
||||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||||
|
|
||||||
inline fun <reified T : Any, S : Any> S.clone(
|
inline fun <reified T : Any, S : Any> S.clone(
|
||||||
unsafe: Boolean = true,
|
unsafe: Boolean = true,
|
||||||
vararg relation: Pair<Property<S>, Property<T>?>
|
vararg relation: Pair<Property<S>, Property<T>?>,
|
||||||
): T = clone(instance<T>(unsafe)!!, relation.iterator())
|
): T = clone(InstantAllocator[T::class.java, unsafe], relation.iterator())
|
||||||
|
|
||||||
fun Any.cloneMap(): Map<in String, Any?> = when (this) {
|
fun Any.cloneMap(): Map<in String, Any?> = when (this) {
|
||||||
is Map<*, *> -> @Suppress("UNCHECKED_CAST") (this as Map<Any?, Any?>).mapKeys { it.key.toString() }
|
is Map<*, *> -> uncheckedCast<Map<Any?, Any?>>().mapKeys { it.key.toString() }
|
||||||
is Iterator<*> -> {
|
is Iterator<*> -> {
|
||||||
val valueMap = HashMap<String, Any?>()
|
val valueMap = HashMap<String, Any?>()
|
||||||
(this as Iterator<Any?>).forEach {
|
(this as Iterator<Any?>).forEach {
|
||||||
@ -201,22 +117,22 @@ fun <T : Any> Any.clone(target: T): T = apply { injectWithoutProperty(target) }.
|
|||||||
|
|
||||||
fun <T : Any, S : Any> S.clone(
|
fun <T : Any, S : Any> S.clone(
|
||||||
target: T,
|
target: T,
|
||||||
iterator: Iterator<Pair<Property<S>, Property<T>?>>
|
iterator: Iterator<Pair<Property<S>, Property<T>?>>,
|
||||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
||||||
valueMap
|
valueMap
|
||||||
//.also { logger.trace("clone {} into {}, value map:{}", this, target, it) }
|
.also { logger.trace("clone {} into {}, value map:{}", this, target, it) }
|
||||||
.clone(target, iterator.injectMap.iterator(), this::class)
|
.clone(target, iterator.injectMap.iterator(), this::class)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> Any.clone(
|
fun <T : Any> Any.clone(
|
||||||
target: T,
|
target: T,
|
||||||
vararg relation: Pair<String, Property<T>?>
|
vararg relation: Pair<String, Property<T>?>,
|
||||||
): T = clone(target, relation.iterator())
|
): T = clone(target, relation.iterator())
|
||||||
|
|
||||||
@JvmName("unsafeClone")
|
@JvmName("unsafeClone")
|
||||||
fun <T : Any> Any.clone(
|
fun <T : Any> Any.clone(
|
||||||
target: T,
|
target: T,
|
||||||
iterator: Iterator<Pair<String, Property<T>?>>
|
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) {
|
||||||
valueMap.clone(target, iterator, this::class)
|
valueMap.clone(target, iterator, this::class)
|
||||||
}
|
}
|
||||||
@ -225,9 +141,9 @@ fun <T : Any> Any.clone(
|
|||||||
fun <T : Any> Map<in String, Any?>.clone(
|
fun <T : Any> Map<in String, Any?>.clone(
|
||||||
target: T,
|
target: T,
|
||||||
iterator: Iterator<Pair<String, Property<T>?>>,
|
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||||
clazz: KClass<*>? = null
|
clazz: KClass<*>? = null,
|
||||||
): T {
|
): T {
|
||||||
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
|
val memberMap = target.injectMap(clazz)
|
||||||
iterator.forEach { (k, v) ->
|
iterator.forEach { (k, v) ->
|
||||||
memberMap[k] = v
|
memberMap[k] = v
|
||||||
}
|
}
|
||||||
@ -238,9 +154,9 @@ fun <T : Any> Map<in String, Any?>.clone(
|
|||||||
fun <T : Any> Map<in String, Any?>.clone(
|
fun <T : Any> Map<in String, Any?>.clone(
|
||||||
target: T,
|
target: T,
|
||||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
|
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
|
||||||
clazz: KClass<*>? = null
|
clazz: KClass<*>? = null,
|
||||||
): T {
|
): T {
|
||||||
val memberMap = target.injectMap(clazz) as MutableMap<String, Property<T>?>
|
val memberMap = target.injectMap(clazz)
|
||||||
iterator.forEach { (k, v) ->
|
iterator.forEach { (k, v) ->
|
||||||
memberMap[k.get(target)?.toString() ?: return@forEach] = v
|
memberMap[k.get(target)?.toString() ?: return@forEach] = v
|
||||||
}
|
}
|
||||||
@ -251,13 +167,13 @@ fun <T : Any> Map<in String, Any?>.clone(
|
|||||||
fun <T : Any> Map<in String, Any?>.clone(
|
fun <T : Any> Map<in String, Any?>.clone(
|
||||||
target: T,
|
target: T,
|
||||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
|
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
|
||||||
clazz: KClass<*>? = null
|
clazz: KClass<*>? = null,
|
||||||
): T {
|
): T {
|
||||||
val memberMap = target.injectMap(clazz)
|
val memberMap = target.injectMap(clazz)
|
||||||
iterator.forEach { (k, v) ->
|
iterator.forEach { (k, v) ->
|
||||||
memberMap[k ?: return@forEach] = v
|
memberMap[k ?: return@forEach] = v
|
||||||
}
|
}
|
||||||
//logger.trace("inject {} into {}, mapping: {}", this, target, memberMap)
|
logger.trace("inject {} into {}, mapping: {}", this, target, memberMap)
|
||||||
return inject(target, memberMap.iterator())
|
return inject(target, memberMap.iterator())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,229 +184,6 @@ fun <T : Any> Any.checkPropertyClone(target: T, ifClone: () -> T): T =
|
|||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
|
||||||
//fun <T> Any.checkPropertyClone(targetClass: KClass<out Any>, ifClone: () -> T): T {
|
|
||||||
// if (targetClass.findAnnotation<NoPropertyClone>()?.classList?.contains(this::class) != true)
|
|
||||||
// ifClone()
|
|
||||||
//}
|
|
||||||
|
|
||||||
fun <T : Any> Any.injectWithoutProperty(target: T): T {
|
|
||||||
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
|
|
||||||
if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try {
|
|
||||||
val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java)
|
|
||||||
handler.isAccessible = true
|
|
||||||
handler(target, this)?.inject(target, property)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
//logger.warn("an exception caused on global inject", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target::class.memberProperties
|
|
||||||
.cast<Collection<KProperty1<Any, *>>>()
|
|
||||||
.forEach { property ->
|
|
||||||
property.annotations.forEach { annotation ->
|
|
||||||
when (annotation) {
|
|
||||||
is Relation -> parseAnnotation(annotation, property)
|
|
||||||
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property.javaField?.annotations?.forEach { annotation ->
|
|
||||||
when (annotation) {
|
|
||||||
is Relation -> parseAnnotation(annotation, property)
|
|
||||||
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> Any.inject(
|
|
||||||
target: T,
|
|
||||||
iterator: Iterator<Pair<String?, Property<T>?>>
|
|
||||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
|
||||||
|
|
||||||
@JvmName("injectMap")
|
|
||||||
fun <T : Any> Any.inject(
|
|
||||||
target: T,
|
|
||||||
iterator: Iterator<Map.Entry<String?, Property<T>?>>
|
|
||||||
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
|
||||||
|
|
||||||
fun <T : Any> Map<in String, Any?>.inject(
|
|
||||||
target: T,
|
|
||||||
iterator: Iterator<Pair<String, Property<T>?>>
|
|
||||||
): T {
|
|
||||||
iterator.forEach { (k, t) ->
|
|
||||||
val value = this[k] ?: return@forEach
|
|
||||||
value.inject(target, t ?: return@forEach)
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> Map<in String, Any?>.p2pInject(
|
|
||||||
target: T,
|
|
||||||
iterator: Iterator<Pair<Property<T>, Property<T>?>>
|
|
||||||
): T {
|
|
||||||
iterator.forEach { (k, t) ->
|
|
||||||
val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach
|
|
||||||
value.inject(target, t ?: return@forEach)
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmName("injectMap")
|
|
||||||
fun <T : Any> Map<in String, Any?>.inject(
|
|
||||||
target: T,
|
|
||||||
iterator: Iterator<Map.Entry<String, Property<T>?>>
|
|
||||||
): T {
|
|
||||||
iterator.forEach { (k, t) ->
|
|
||||||
val value = this[k] ?: return@forEach
|
|
||||||
value.inject(target, t ?: return@forEach)
|
|
||||||
}
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> Any.inject(target: T, property: Property<T>) {
|
|
||||||
//logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
|
|
||||||
when (property) {
|
|
||||||
is KMutableProperty1<*, *> -> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
property as KMutableProperty1<T, Any?>
|
|
||||||
property.isAccessible = true
|
|
||||||
try {
|
|
||||||
property.set(target, cast(this, property.returnType.javaType.cast()) ?: return)
|
|
||||||
} catch (e: ClassCastException) {
|
|
||||||
//logger.trace("inject failed", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val field = property.javaField ?: return
|
|
||||||
field.isAccessible = true
|
|
||||||
field.final = false
|
|
||||||
try {
|
|
||||||
field.set(target, cast(this, field.type) ?: return)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
//logger.trace("inject failed", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) {
|
|
||||||
source
|
|
||||||
} else when (target) {
|
|
||||||
Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
|
|
||||||
Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar()
|
|
||||||
Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
|
|
||||||
Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
|
|
||||||
Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
|
|
||||||
Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
|
|
||||||
Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
|
|
||||||
Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
|
|
||||||
|
|
||||||
java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
|
|
||||||
java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()
|
|
||||||
?.toChar()
|
|
||||||
java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
|
|
||||||
java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
|
|
||||||
java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
|
|
||||||
java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
|
|
||||||
java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
|
|
||||||
java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
|
|
||||||
|
|
||||||
String::class.java -> source.toString()
|
|
||||||
|
|
||||||
else -> source
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> T.read(source: Any?): T = source?.clone(this) ?: this
|
|
||||||
|
|
||||||
fun <T : Any, S : Any> T.read(
|
|
||||||
source: S?,
|
|
||||||
vararg relation: Pair<Property<S>, Property<T>?>
|
|
||||||
): T = source?.clone(this, relation.iterator()) ?: this
|
|
||||||
|
|
||||||
fun <T : Any> T.read(
|
|
||||||
source: Map<in String, Any?>?,
|
|
||||||
vararg relation: Pair<String, Property<T>?>
|
|
||||||
): T = source?.clone(this, relation.iterator()) ?: this
|
|
||||||
|
|
||||||
|
|
||||||
fun <T : Any> T.p2pRead(
|
|
||||||
source: Map<in String, Any?>?,
|
|
||||||
vararg relation: Pair<Property<T>, Property<T>?>
|
|
||||||
): T {
|
|
||||||
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
|
|
||||||
return source?.p2pInject(this, relation.iterator()) ?: this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> T.p2pRead(
|
|
||||||
source: Map<in String, Any?>?
|
|
||||||
): T {
|
|
||||||
source ?: return this
|
|
||||||
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
|
|
||||||
val relation = properties.mapNotNull { property ->
|
|
||||||
val key = property.javaField?.getAnnotation(Key::class.java)?.key ?: return@mapNotNull null
|
|
||||||
val keyProperty = properties.find { it.name == key } ?: return@mapNotNull null
|
|
||||||
keyProperty to property
|
|
||||||
}
|
|
||||||
//logger.trace("p2p read, source:{}, relation: {}", source, relation)
|
|
||||||
return source.p2pInject(this, relation.iterator())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> T.p2pRead(
|
|
||||||
source: Any?
|
|
||||||
): T {
|
|
||||||
source ?: return this
|
|
||||||
val properties = this::class.memberProperties.cast<Collection<KProperty1<T, *>>>()
|
|
||||||
properties.forEach { property ->
|
|
||||||
val keyAnnotation = property.javaField?.getAnnotation(Key::class.java) ?: return@forEach
|
|
||||||
if (keyAnnotation.handler.isEmpty()) return@forEach
|
|
||||||
if (keyAnnotation.clazz.isInstance(source).not()) return@forEach
|
|
||||||
val handler = this::class.java.getDeclaredMethod(keyAnnotation.handler, keyAnnotation.clazz.java)
|
|
||||||
(handler(this, source) ?: return@forEach).inject(this, property)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any, S : Any> List<T>.read(
|
|
||||||
source: List<S>,
|
|
||||||
vararg relation: Pair<Property<S>, Property<T>?>
|
|
||||||
): List<T> {
|
|
||||||
val memberMap = this[0].injectMap as MutableMap<String, Property<T>?>
|
|
||||||
relation.forEach { (k, v) ->
|
|
||||||
memberMap[k.name] = v
|
|
||||||
}
|
|
||||||
return source.mapIndexed { index, it -> it.inject(this[index], memberMap.iterator()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> read(vararg values: Any, unsafe: Boolean = true): T {
|
|
||||||
val instance = instance<T>(unsafe)!!
|
|
||||||
values.forEach {
|
|
||||||
it.clone(instance)
|
|
||||||
}
|
|
||||||
return instance
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> read(value: Any, unsafe: Boolean = true): T = value.clone(unsafe)
|
|
||||||
|
|
||||||
fun <T : Any> T.readWithoutProperty(vararg values: Any): T {
|
|
||||||
values.forEach {
|
|
||||||
it.injectWithoutProperty(this)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
|
|
||||||
|
|
||||||
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T? = try {
|
|
||||||
clazz.newInstance()!!
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (unsafe) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
Unsafe.unsafe.allocateInstance(clazz) as T?
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) -> Pair<K, V>?): Map<K, V> {
|
inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) -> Pair<K, V>?): Map<K, V> {
|
||||||
val map = ArrayMap<K, V>()
|
val map = ArrayMap<K, V>()
|
||||||
@ -502,6 +195,113 @@ inline fun <T, K : Comparable<K>, V> Iterator<T>.mapIndexed(action: (Int, T) ->
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> T.mapRead(map: Map<in String, Any?>, key: KProperty1<T, *>): T {
|
fun <T : Any, F : Any?> T.set(field: KProperty1<T, F>, value: F): T {
|
||||||
return read(map[key.get(this)?.toString() ?: return this] ?: return this)
|
(value as Any?)?.inject(this, field as Property<T>)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> T.deepClone(): T = when (this) {
|
||||||
|
is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this
|
||||||
|
is CharArray -> copyOf().uncheckedCast()
|
||||||
|
is BooleanArray -> copyOf().uncheckedCast()
|
||||||
|
is ByteArray -> copyOf().uncheckedCast()
|
||||||
|
is ShortArray -> copyOf().uncheckedCast()
|
||||||
|
is IntArray -> copyOf().uncheckedCast()
|
||||||
|
is LongArray -> copyOf().uncheckedCast()
|
||||||
|
is FloatArray -> copyOf().uncheckedCast()
|
||||||
|
is DoubleArray -> copyOf().uncheckedCast()
|
||||||
|
else -> deepClone(HashMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : Any> T.deepClone(clonedMap: MutableMap<Any, Any>): T =
|
||||||
|
clonedMap[this]?.uncheckedCast<T>() ?: when (this) {
|
||||||
|
is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*> -> this
|
||||||
|
is CharArray -> copyOf().uncheckedCast()
|
||||||
|
is BooleanArray -> copyOf().uncheckedCast()
|
||||||
|
is ByteArray -> copyOf().uncheckedCast()
|
||||||
|
is ShortArray -> copyOf().uncheckedCast()
|
||||||
|
is IntArray -> copyOf().uncheckedCast()
|
||||||
|
is LongArray -> copyOf().uncheckedCast()
|
||||||
|
is FloatArray -> copyOf().uncheckedCast()
|
||||||
|
is DoubleArray -> copyOf().uncheckedCast()
|
||||||
|
is Array<*> -> {
|
||||||
|
val instance = java.lang.reflect.Array.newInstance(javaClass.componentType, size).uncheckedCast<Array<Any?>>()
|
||||||
|
forEachIndexed { index, it ->
|
||||||
|
instance[index] = it?.deepClone(clonedMap)
|
||||||
|
}
|
||||||
|
instance.uncheckedCast()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val clazz = javaClass
|
||||||
|
val newInstance = unsafeInstance(clazz)!!
|
||||||
|
clonedMap[this] = newInstance
|
||||||
|
clazz.forAllFields { field ->
|
||||||
|
if (field.isStatic()) return@forAllFields
|
||||||
|
field.isAccessible = true
|
||||||
|
field.set(newInstance, field.get(this)?.deepClone(clonedMap))
|
||||||
|
}
|
||||||
|
newInstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Any?.details(name: String = "", skipStatic: Boolean = true) = buildString {
|
||||||
|
this@details.details(HashMap(), this, "", name, skipStatic)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Any?.details(
|
||||||
|
map: MutableMap<Any, Int>,
|
||||||
|
builder: StringBuilder,
|
||||||
|
indentation: String,
|
||||||
|
name: String = "",
|
||||||
|
skipStatic: Boolean = true,
|
||||||
|
directValue: String = "|- ",
|
||||||
|
objectValue: String = "/- ",
|
||||||
|
hint: String = "${TextColor.red}|${TextColor.reset} ",
|
||||||
|
tmpIndentation: String = "",
|
||||||
|
type: String? = null,
|
||||||
|
) {
|
||||||
|
when (this) {
|
||||||
|
null, is Char, is Boolean, is Byte, is Short, is Int, is Long, is Float, is Double, is Class<*>, is String ->
|
||||||
|
builder.append("$indentation$tmpIndentation$directValue$name(${type ?: this?.javaClass?.name ?: "null"}): $this\n")
|
||||||
|
is CharArray -> builder.append("$indentation$tmpIndentation$directValue$name(CharArray): ${String(this)}\n")
|
||||||
|
is BooleanArray -> builder.append("$indentation$tmpIndentation$directValue$name(BooleanArray): ${asList()}\n")
|
||||||
|
is ByteArray -> builder.append("$indentation$tmpIndentation$directValue$name(ByteArray): 0x${toHexString()}\n")
|
||||||
|
is ShortArray -> builder.append("$indentation$tmpIndentation$directValue$name(ShortArray): ${asList()}\n")
|
||||||
|
is IntArray -> builder.append("$indentation$tmpIndentation$directValue$name(IntArray): ${asList()}\n")
|
||||||
|
is LongArray -> builder.append("$indentation$tmpIndentation$directValue$name(LongArray): ${asList()}\n")
|
||||||
|
is FloatArray -> builder.append("$indentation$tmpIndentation$directValue$name(FloatArray): ${asList()}\n")
|
||||||
|
is DoubleArray -> builder.append("$indentation$tmpIndentation$directValue$name(DoubleArray): ${asList()}\n")
|
||||||
|
is Array<*> -> {
|
||||||
|
builder.append("$indentation$tmpIndentation$objectValue$name: (Array<${javaClass.componentType.name}>, ${hashCode()})\n")
|
||||||
|
if (this !in map) {
|
||||||
|
map[this] = hashCode()
|
||||||
|
val newIndentation = "$indentation$hint"
|
||||||
|
forEachIndexed { index, it ->
|
||||||
|
val newTmpIndentation = "|- ${name.ifEmpty { "array" }}[$index]"
|
||||||
|
it.details(
|
||||||
|
map, builder, newIndentation,
|
||||||
|
skipStatic = skipStatic,
|
||||||
|
directValue = " = ",
|
||||||
|
objectValue = " = /- ",
|
||||||
|
hint = "${TextColor.red}|${TextColor.reset} ${" ".repeat(newTmpIndentation.length + 1)}${TextColor.red}|${TextColor.reset} ",
|
||||||
|
tmpIndentation = newTmpIndentation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in map -> builder.append("$indentation$tmpIndentation$directValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${map[this]}, generated)\n")
|
||||||
|
else -> {
|
||||||
|
map[this] = this.hashCode()
|
||||||
|
builder.append("$indentation$tmpIndentation$objectValue$name${if (name.isNotEmpty()) ": " else ""}(${javaClass.name}, ${hashCode()})\n")
|
||||||
|
val newIndentation = "$indentation$hint"
|
||||||
|
javaClass.forAllFields { field ->
|
||||||
|
if (skipStatic && field.isStatic()) {
|
||||||
|
return@forAllFields
|
||||||
|
}
|
||||||
|
field.isAccessible = true
|
||||||
|
val value = field.get(this)
|
||||||
|
value.details(map, builder, newIndentation, field.name, skipStatic, type = field.type.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,270 @@
|
|||||||
|
package cn.tursom.core.clone
|
||||||
|
|
||||||
|
import cn.tursom.core.Unsafe
|
||||||
|
import cn.tursom.core.allMemberProperties
|
||||||
|
import cn.tursom.core.datastruct.KPropertyValueMap
|
||||||
|
import cn.tursom.core.datastruct.SoftArrayMap
|
||||||
|
import cn.tursom.core.unaryPlus
|
||||||
|
import cn.tursom.core.uncheckedCast
|
||||||
|
import cn.tursom.log.impl.Slf4jImpl
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.collections.component1
|
||||||
|
import kotlin.collections.component2
|
||||||
|
import kotlin.collections.set
|
||||||
|
import kotlin.reflect.*
|
||||||
|
import kotlin.reflect.full.memberProperties
|
||||||
|
import kotlin.reflect.jvm.isAccessible
|
||||||
|
import kotlin.reflect.jvm.javaField
|
||||||
|
import kotlin.reflect.jvm.javaType
|
||||||
|
|
||||||
|
private val logger = Slf4jImpl().logger
|
||||||
|
|
||||||
|
val Any.valueMap: Map<String, Any?>
|
||||||
|
get() = if (this is Map<*, *>) {
|
||||||
|
uncheckedCast()
|
||||||
|
} else {
|
||||||
|
KPropertyValueMap(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val injectMapCache = SoftArrayMap<KClass<*>, Map<String, Property<*>?>>(ConcurrentHashMap())
|
||||||
|
|
||||||
|
val <T : Any> KClass<T>.injectMap: MutableMap<String, Property<T>?>
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
get() {
|
||||||
|
var injectMap = injectMapCache[this] as Map<String, Property<T>?>?
|
||||||
|
if (injectMap == null) {
|
||||||
|
injectMap = allMemberProperties.associateByTo(HashMap()) { property ->
|
||||||
|
property.isAccessible = true
|
||||||
|
property.name
|
||||||
|
}
|
||||||
|
injectMapCache[this] = injectMap as Map<String, Property<*>?>
|
||||||
|
}
|
||||||
|
return HashMap(injectMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val <T : Any> T.injectMap: MutableMap<String, Property<T>?>
|
||||||
|
get() = this::class.uncheckedCast<KClass<T>>().injectMap
|
||||||
|
|
||||||
|
internal val <T> Iterator<Pair<Property<*>, Property<T>?>>.injectMap
|
||||||
|
get() = let {
|
||||||
|
val valueMap = HashMap<String, Property<T>?>()
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
forEach { (k, field) ->
|
||||||
|
field?.isAccessible = true
|
||||||
|
valueMap[k.name] = field
|
||||||
|
}
|
||||||
|
logger.trace("Iterator.injectMap: {}", valueMap)
|
||||||
|
valueMap
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <T : Any> T.injectMap(targetClazz: KClass<*>?): MutableMap<String, Property<T>?> = this::class
|
||||||
|
.uncheckedCast<KClass<T>>()
|
||||||
|
.injectMap
|
||||||
|
.also { injectMap ->
|
||||||
|
if (targetClazz == null) return@also
|
||||||
|
val clazzThis = this::class.java
|
||||||
|
|
||||||
|
fun import(relation: Relation, property: Property<T>) {
|
||||||
|
if (relation.clazz != targetClazz) return
|
||||||
|
var propertyName = relation.property
|
||||||
|
if (propertyName.isBlank()) {
|
||||||
|
propertyName = property.name
|
||||||
|
}
|
||||||
|
logger.trace("relation {} to {}", propertyName, property.name)
|
||||||
|
injectMap[propertyName] = when {
|
||||||
|
relation.skip -> null
|
||||||
|
relation.handler.isEmpty() -> property
|
||||||
|
else -> try {
|
||||||
|
val handler = clazzThis.getDeclaredMethod(relation.handler, relation.handleClass.java)
|
||||||
|
handler.isAccessible = true
|
||||||
|
object : KMutableProperty1<T, Any?>, KProperty1<T, Any?> by property {
|
||||||
|
override val setter: KMutableProperty1.Setter<T, Any?>
|
||||||
|
get() = object : KMutableProperty1.Setter<T, Any?>, KCallable<Unit> by property.uncheckedCast() {
|
||||||
|
override val isExternal: Boolean get() = false
|
||||||
|
override val isInfix: Boolean get() = false
|
||||||
|
override val isInline: Boolean get() = false
|
||||||
|
override val isOperator: Boolean get() = false
|
||||||
|
override val isSuspend: Boolean get() = false
|
||||||
|
override val property: KProperty<Any?> get() = property
|
||||||
|
override fun invoke(receiver: T, value: Any?) =
|
||||||
|
handler(this@injectMap, value).inject(receiver, property)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(receiver: T, value: Any?) = try {
|
||||||
|
handler(this@injectMap, value).inject(receiver, property)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.trace("", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn("an exception caused on generate inject handler", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseAnnotation(annotation: Annotation, property: Property<T>) {
|
||||||
|
when (annotation) {
|
||||||
|
is Relation -> import(annotation, property)
|
||||||
|
is Relations -> annotation.relations.forEach { relation -> import(relation, property) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this::class.memberProperties.uncheckedCast<Collection<KProperty1<T, *>>>().forEach { property ->
|
||||||
|
property.annotations.forEach { annotation -> parseAnnotation(annotation, property) }
|
||||||
|
(property.javaField ?: return@forEach).annotations.forEach { annotation ->
|
||||||
|
parseAnnotation(annotation, property)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> Any.injectWithoutProperty(target: T): T {
|
||||||
|
fun parseAnnotation(relation: Relation, property: KProperty1<Any, *>) {
|
||||||
|
if (relation.property.isEmpty() && relation.clazz.java.isInstance(this)) try {
|
||||||
|
val handler = target::class.java.getDeclaredMethod(relation.handler, relation.clazz.java)
|
||||||
|
handler.isAccessible = true
|
||||||
|
handler(target, this)?.inject(target, property)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.trace("an exception caused on global inject", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target::class.memberProperties
|
||||||
|
.uncheckedCast<Collection<KProperty1<Any, *>>>()
|
||||||
|
.forEach { property ->
|
||||||
|
property.annotations.forEach { annotation ->
|
||||||
|
when (annotation) {
|
||||||
|
is Relation -> parseAnnotation(annotation, property)
|
||||||
|
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property.javaField?.annotations?.forEach { annotation ->
|
||||||
|
when (annotation) {
|
||||||
|
is Relation -> parseAnnotation(annotation, property)
|
||||||
|
is Relations -> annotation.relations.forEach { parseAnnotation(it, property) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> Any.inject(
|
||||||
|
target: T,
|
||||||
|
iterator: Iterator<Pair<String?, Property<T>?>>,
|
||||||
|
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||||
|
|
||||||
|
@JvmName("injectMap")
|
||||||
|
fun <T : Any> Any.inject(
|
||||||
|
target: T,
|
||||||
|
iterator: Iterator<Map.Entry<String?, Property<T>?>>,
|
||||||
|
): T = apply { injectWithoutProperty(target) }.checkPropertyClone(target) { valueMap.inject(target, iterator) }
|
||||||
|
|
||||||
|
fun <T : Any> Map<in String, Any?>.inject(
|
||||||
|
target: T,
|
||||||
|
iterator: Iterator<Pair<String, Property<T>?>>,
|
||||||
|
): T {
|
||||||
|
iterator.forEach { (k, t) ->
|
||||||
|
val value = this[k] ?: return@forEach
|
||||||
|
value.inject(target, t ?: return@forEach)
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* point to point inject
|
||||||
|
* 通过指定映射关系,从本map中取出数据并注入到目标对象中
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun <T : Any> Map<in String, Any?>.p2pInject(
|
||||||
|
target: T,
|
||||||
|
iterator: Iterator<Pair<Property<T>, Property<T>?>>,
|
||||||
|
): T {
|
||||||
|
iterator.forEach { (k, t) ->
|
||||||
|
val value = this[k(target)?.toString() ?: return@forEach] ?: return@forEach
|
||||||
|
value.inject(target, t ?: return@forEach)
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("injectMap")
|
||||||
|
fun <T : Any> Map<in String, Any?>.inject(
|
||||||
|
target: T,
|
||||||
|
iterator: Iterator<Map.Entry<String, Property<T>?>>,
|
||||||
|
): T {
|
||||||
|
iterator.forEach { (k, t) ->
|
||||||
|
val value = this[k] ?: return@forEach
|
||||||
|
value.inject(target, t ?: return@forEach)
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> Any.inject(target: T, property: Property<T>) {
|
||||||
|
logger.trace("inject {} into {}.{}", this, +{ target::class.simpleName }, property.name)
|
||||||
|
when (property) {
|
||||||
|
is KMutableProperty1<*, *> -> {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
property as KMutableProperty1<T, Any?>
|
||||||
|
property.isAccessible = true
|
||||||
|
try {
|
||||||
|
property.set(target, cast(this, property.returnType.javaType.uncheckedCast()) ?: return)
|
||||||
|
} catch (e: ClassCastException) {
|
||||||
|
if (logger.isTraceEnabled) {
|
||||||
|
logger.trace("inject {} failed", property.name, e)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("inject {} failed", property.name, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val field = property.javaField ?: return
|
||||||
|
field.isAccessible = true
|
||||||
|
try {
|
||||||
|
field.set(target, cast(this, field.type) ?: return)
|
||||||
|
} catch (e: ClassCastException) {
|
||||||
|
if (logger.isTraceEnabled) {
|
||||||
|
logger.trace("inject {} failed", property.name, e)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("inject {} failed", property.name, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cast(source: Any, target: Class<*>): Any? = if (target.isInstance(source)) {
|
||||||
|
source
|
||||||
|
} else when (target) {
|
||||||
|
Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
|
||||||
|
Char::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()?.toChar()
|
||||||
|
Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
|
||||||
|
Int::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
|
||||||
|
Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
|
||||||
|
Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
|
||||||
|
Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
|
||||||
|
Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
|
||||||
|
|
||||||
|
java.lang.Byte::class.java -> if (source is Number) source.toByte() else source.toString().toByteOrNull()
|
||||||
|
java.lang.Character::class.java -> if (source is Number) source.toChar() else source.toString().toIntOrNull()
|
||||||
|
?.toChar()
|
||||||
|
java.lang.Short::class.java -> if (source is Number) source.toShort() else source.toString().toShortOrNull()
|
||||||
|
java.lang.Integer::class.java -> if (source is Number) source.toInt() else source.toString().toIntOrNull()
|
||||||
|
java.lang.Long::class.java -> if (source is Number) source.toLong() else source.toString().toLongOrNull()
|
||||||
|
java.lang.Float::class.java -> if (source is Number) source.toFloat() else source.toString().toFloatOrNull()
|
||||||
|
java.lang.Double::class.java -> if (source is Number) source.toDouble() else source.toString().toDoubleOrNull()
|
||||||
|
java.lang.Boolean::class.java -> if (source is Number) source != 0 else source.toString().toBoolean()
|
||||||
|
|
||||||
|
String::class.java -> source.toString()
|
||||||
|
|
||||||
|
else -> source
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> instance(unsafe: Boolean = true) = instance(unsafe, T::class.java)
|
||||||
|
|
||||||
|
fun <T> instance(unsafe: Boolean = true, clazz: Class<T>): T = InstantAllocator[clazz, unsafe]
|
||||||
|
|
||||||
|
fun <T> unsafeInstance(clazz: Class<T>, unsafe: Boolean = true): T? = if (unsafe) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
Unsafe.unsafe.allocateInstance(clazz) as T?
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package cn.tursom.core.datastruct
|
package cn.tursom.core.datastruct
|
||||||
|
|
||||||
import cn.tursom.core.cast
|
import cn.tursom.core.uncheckedCast
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||||
@ -149,7 +149,7 @@ open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
override fun setValue(newValue: V): V = value.also { value = newValue }
|
override fun setValue(newValue: V): V = value.also { value = newValue }
|
||||||
override fun compareTo(other: K): Int {
|
override fun compareTo(other: K): Int {
|
||||||
return if (key is Comparable<*>) {
|
return if (key is Comparable<*>) {
|
||||||
key.cast<Comparable<K>>().compareTo(other)
|
key.uncheckedCast<Comparable<K>>().compareTo(other)
|
||||||
} else {
|
} else {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package cn.tursom.core.datastruct
|
package cn.tursom.core.datastruct
|
||||||
|
|
||||||
import cn.tursom.core.cast
|
import cn.tursom.core.uncheckedCast
|
||||||
|
|
||||||
class DefaultValueMap<K, V>(
|
class DefaultValueMap<K, V>(
|
||||||
private val map: Map<K, V?>,
|
private val map: Map<K, V?>,
|
||||||
private val defaultValue: (K) -> V
|
private val defaultValue: (K) -> V,
|
||||||
) : Map<K, V> by map.cast() {
|
) : Map<K, V> by map.uncheckedCast() {
|
||||||
override val entries: Set<Map.Entry<K, V>> get() = Entry()
|
override val entries: Set<Map.Entry<K, V>> get() = Entry()
|
||||||
override val values: Collection<V> get() = Values()
|
override val values: Collection<V> get() = Values()
|
||||||
|
|
||||||
@ -21,8 +21,8 @@ class DefaultValueMap<K, V>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class Entry(
|
inner class Entry(
|
||||||
private val entries: Set<Map.Entry<K, V?>> = map.entries
|
private val entries: Set<Map.Entry<K, V?>> = map.entries,
|
||||||
) : Set<Map.Entry<K, V>> by entries.cast() {
|
) : Set<Map.Entry<K, V>> by entries.uncheckedCast() {
|
||||||
override val size: Int get() = entries.count { it.value != null }
|
override val size: Int get() = entries.count { it.value != null }
|
||||||
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
|
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
|
||||||
override fun iterator(): Iterator<Map.Entry<K, V>> = EntryIterator()
|
override fun iterator(): Iterator<Map.Entry<K, V>> = EntryIterator()
|
||||||
@ -32,7 +32,7 @@ class DefaultValueMap<K, V>(
|
|||||||
private var next: Map.Entry<K, V>? = null
|
private var next: Map.Entry<K, V>? = null
|
||||||
override fun hasNext(): Boolean {
|
override fun hasNext(): Boolean {
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
next = iterator.next().cast()
|
next = iterator.next().uncheckedCast()
|
||||||
if (next?.value != null) {
|
if (next?.value != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -44,13 +44,13 @@ class DefaultValueMap<K, V>(
|
|||||||
next != null -> next
|
next != null -> next
|
||||||
hasNext() -> next
|
hasNext() -> next
|
||||||
else -> throw NoSuchElementException()
|
else -> throw NoSuchElementException()
|
||||||
}.cast()
|
}.uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class Values(
|
inner class Values(
|
||||||
private val values: Collection<V?> = map.values
|
private val values: Collection<V?> = map.values,
|
||||||
) : Collection<V> by values.cast() {
|
) : Collection<V> by values.uncheckedCast() {
|
||||||
override val size: Int get() = values.count { it != null }
|
override val size: Int get() = values.count { it != null }
|
||||||
override fun isEmpty(): Boolean = values.first { it != null } == null
|
override fun isEmpty(): Boolean = values.first { it != null } == null
|
||||||
override fun iterator(): Iterator<V> = ValuesIterator()
|
override fun iterator(): Iterator<V> = ValuesIterator()
|
||||||
@ -61,7 +61,7 @@ class DefaultValueMap<K, V>(
|
|||||||
|
|
||||||
override fun hasNext(): Boolean {
|
override fun hasNext(): Boolean {
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
next = iterator.next().cast()
|
next = iterator.next().uncheckedCast()
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class DefaultValueMap<K, V>(
|
|||||||
next != null -> next
|
next != null -> next
|
||||||
hasNext() -> next
|
hasNext() -> next
|
||||||
else -> throw NoSuchElementException()
|
else -> throw NoSuchElementException()
|
||||||
}.cast()
|
}.uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package cn.tursom.core.datastruct
|
package cn.tursom.core.datastruct
|
||||||
|
|
||||||
import cn.tursom.core.cast
|
import cn.tursom.core.uncheckedCast
|
||||||
|
|
||||||
class DefaultValueMutableMap<K, V>(
|
class DefaultValueMutableMap<K, V>(
|
||||||
private val map: MutableMap<K, V?>,
|
private val map: MutableMap<K, V?>,
|
||||||
private val defaultValue: (K) -> V
|
private val defaultValue: (K) -> V,
|
||||||
) : MutableMap<K, V> by map.cast() {
|
) : MutableMap<K, V> by map.uncheckedCast() {
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = Entry()
|
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = Entry()
|
||||||
override val values: MutableCollection<V> get() = Values()
|
override val values: MutableCollection<V> get() = Values()
|
||||||
|
|
||||||
@ -19,19 +19,19 @@ class DefaultValueMutableMap<K, V>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class Entry(
|
inner class Entry(
|
||||||
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries
|
private val entries: MutableSet<MutableMap.MutableEntry<K, V?>> = map.entries,
|
||||||
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.cast() {
|
) : MutableSet<MutableMap.MutableEntry<K, V>> by entries.uncheckedCast() {
|
||||||
override val size: Int get() = entries.count { it.value != null }
|
override val size: Int get() = entries.count { it.value != null }
|
||||||
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
|
override fun isEmpty(): Boolean = entries.firstOrNull { it.value != null } == null
|
||||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = EntryIterator()
|
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = EntryIterator()
|
||||||
|
|
||||||
inner class EntryIterator(
|
inner class EntryIterator(
|
||||||
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator()
|
private val iterator: MutableIterator<MutableMap.MutableEntry<K, V?>> = entries.iterator(),
|
||||||
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.cast() {
|
) : MutableIterator<MutableMap.MutableEntry<K, V>> by iterator.uncheckedCast() {
|
||||||
private var next: Map.Entry<K, V>? = null
|
private var next: Map.Entry<K, V>? = null
|
||||||
override fun hasNext(): Boolean {
|
override fun hasNext(): Boolean {
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
next = iterator.next().cast()
|
next = iterator.next().uncheckedCast()
|
||||||
if (next?.value != null) {
|
if (next?.value != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -43,25 +43,25 @@ class DefaultValueMutableMap<K, V>(
|
|||||||
next != null -> next
|
next != null -> next
|
||||||
hasNext() -> next
|
hasNext() -> next
|
||||||
else -> throw NoSuchElementException()
|
else -> throw NoSuchElementException()
|
||||||
}.cast()
|
}.uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class Values(
|
inner class Values(
|
||||||
private val values: MutableCollection<V?> = map.values
|
private val values: MutableCollection<V?> = map.values,
|
||||||
) : MutableCollection<V> by values.cast() {
|
) : MutableCollection<V> by values.uncheckedCast() {
|
||||||
override val size: Int get() = values.count { it != null }
|
override val size: Int get() = values.count { it != null }
|
||||||
override fun isEmpty(): Boolean = values.first { it != null } == null
|
override fun isEmpty(): Boolean = values.first { it != null } == null
|
||||||
override fun iterator(): MutableIterator<V> = ValuesIterator()
|
override fun iterator(): MutableIterator<V> = ValuesIterator()
|
||||||
|
|
||||||
inner class ValuesIterator(
|
inner class ValuesIterator(
|
||||||
private val iterator: MutableIterator<V?> = values.iterator()
|
private val iterator: MutableIterator<V?> = values.iterator(),
|
||||||
) : MutableIterator<V> by iterator.cast() {
|
) : MutableIterator<V> by iterator.uncheckedCast() {
|
||||||
private var next: V? = null
|
private var next: V? = null
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
override fun hasNext(): Boolean {
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
next = iterator.next().cast()
|
next = iterator.next().uncheckedCast()
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class DefaultValueMutableMap<K, V>(
|
|||||||
next != null -> next
|
next != null -> next
|
||||||
hasNext() -> next
|
hasNext() -> next
|
||||||
else -> throw NoSuchElementException()
|
else -> throw NoSuchElementException()
|
||||||
}.cast()
|
}.uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package cn.tursom.core.datastruct
|
package cn.tursom.core.datastruct
|
||||||
|
|
||||||
import cn.tursom.core.cast
|
import cn.tursom.core.uncheckedCast
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
import kotlin.reflect.full.memberProperties
|
import kotlin.reflect.full.memberProperties
|
||||||
@ -23,7 +23,7 @@ class KPropertyValueMap(val target: Any) : Map<String, Any?> {
|
|||||||
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
|
operator fun get(clazz: KClass<*>): SoftArrayMap<String, KProperty1<Any, *>> {
|
||||||
var map = propertiesMapCache[clazz]
|
var map = propertiesMapCache[clazz]
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = clazz.memberProperties.cast<Collection<KProperty1<Any, *>>>().let { properties ->
|
map = clazz.memberProperties.uncheckedCast<Collection<KProperty1<Any, *>>>().let { properties ->
|
||||||
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
|
val valueMap = SoftArrayMap<String, KProperty1<Any, *>>(properties.size)
|
||||||
properties.forEach {
|
properties.forEach {
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.tursom.core.datastruct
|
package cn.tursom.core.datastruct
|
||||||
|
|
||||||
import cn.tursom.core.cast
|
import cn.tursom.core.uncheckedCast
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||||
@ -17,8 +17,8 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
|
|
||||||
@Suppress("LeakingThis")
|
@Suppress("LeakingThis")
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
||||||
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().cast()
|
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().uncheckedCast()
|
||||||
override val values: MutableCollection<V> get() = arrValue.asList().cast<MutableList<V>>().subList(0, end)
|
override val values: MutableCollection<V> get() = arrValue.asList().uncheckedCast<MutableList<V>>().subList(0, end)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param key 查找的键
|
* @param key 查找的键
|
||||||
@ -59,7 +59,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
fun setByIndex(index: Int, value: V): V? {
|
fun setByIndex(index: Int, value: V): V? {
|
||||||
val oldValue = arrValue[end]
|
val oldValue = arrValue[end]
|
||||||
arrValue[index] = value
|
arrValue[index] = value
|
||||||
return oldValue.cast()
|
return oldValue.uncheckedCast()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun delete(key: K): V? {
|
override fun delete(key: K): V? {
|
||||||
@ -72,7 +72,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
|
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
|
||||||
System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1)
|
System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1)
|
||||||
end--
|
end--
|
||||||
return oldValue.cast()
|
return oldValue.uncheckedCast()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
@ -83,7 +83,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
return if (end <= 0) {
|
return if (end <= 0) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
arrValue[0].cast()
|
arrValue[0].uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
return if (index < 0 || index >= end) {
|
return if (index < 0 || index >= end) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
arr[index].cast()
|
arr[index].uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
return if (index < 0 || index >= end) {
|
return if (index < 0 || index >= end) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
arrValue[index].cast()
|
arrValue[index].uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,10 +194,10 @@ open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
|||||||
val map: ParallelArrayMap<K, V>,
|
val map: ParallelArrayMap<K, V>,
|
||||||
val index: Int
|
val index: Int
|
||||||
) : MutableMap.MutableEntry<K, V> {
|
) : MutableMap.MutableEntry<K, V> {
|
||||||
override val key: K get() = map.getKeyByIndex(index).cast()
|
override val key: K get() = map.getKeyByIndex(index).uncheckedCast()
|
||||||
override val value: V get() = map.getByIndex(index).cast()
|
override val value: V get() = map.getByIndex(index).uncheckedCast()
|
||||||
override fun setValue(newValue: V): V {
|
override fun setValue(newValue: V): V {
|
||||||
return map.setByIndex(index, newValue).cast()
|
return map.setByIndex(index, newValue).uncheckedCast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
package cn.tursom.core.delegation
|
package cn.tursom.core.delegation
|
||||||
|
|
||||||
import cn.tursom.core.*
|
import cn.tursom.core.SimpThreadLocal
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import cn.tursom.core.castOrNull
|
||||||
|
import cn.tursom.core.receiver
|
||||||
|
import cn.tursom.core.uncheckedCast
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
import java.util.concurrent.locks.Lock
|
import java.util.concurrent.locks.Lock
|
||||||
import java.util.concurrent.locks.ReadWriteLock
|
import java.util.concurrent.locks.ReadWriteLock
|
||||||
@ -126,99 +128,3 @@ fun <T, V> MutableDelegatedField<T, V>.getter(getter: MutableDelegatedField<T, V
|
|||||||
|
|
||||||
fun <T, V> MutableDelegatedField<T, V>.withExecutor(executor: Executor): MutableDelegatedField<T, V> =
|
fun <T, V> MutableDelegatedField<T, V>.withExecutor(executor: Executor): MutableDelegatedField<T, V> =
|
||||||
ExecutorMutableDelegatedField(this, executor)
|
ExecutorMutableDelegatedField(this, executor)
|
||||||
|
|
||||||
@Listenable
|
|
||||||
fun <V> KMutableProperty0<V>.listenable(): MutableDelegatedField<Any, V> {
|
|
||||||
isAccessible = true
|
|
||||||
val delegate = getDelegate()
|
|
||||||
return if (delegate is MutableDelegatedField<*, *> && delegate[ListenableMutableDelegatedField] == true) {
|
|
||||||
@OptIn(UncheckedCast::class)
|
|
||||||
delegate.cast()
|
|
||||||
} else {
|
|
||||||
@OptIn(UncheckedCast::class)
|
|
||||||
(ListenableMutableDelegatedField(KPropertyMutableDelegatedField(cast())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listenable
|
|
||||||
fun <V> listenable(initValue: V): MutableDelegatedField<Any, V> = ListenableMutableDelegatedField(
|
|
||||||
MutableDelegatedFieldValue(initValue)
|
|
||||||
)
|
|
||||||
|
|
||||||
@Listenable
|
|
||||||
fun <T, V> MutableDelegatedField<T, V>.listenable(): MutableDelegatedField<T, V> =
|
|
||||||
ListenableMutableDelegatedField(this)
|
|
||||||
|
|
||||||
@JvmName("listenable1")
|
|
||||||
@Listenable
|
|
||||||
fun <T, V> listenable(delegatedField: MutableDelegatedField<T, V>): MutableDelegatedField<T, V> =
|
|
||||||
ListenableMutableDelegatedField(delegatedField)
|
|
||||||
|
|
||||||
|
|
||||||
infix operator fun <T, V> ListenableListener<T, V>.plus(listener: T.(old: V, new: V) -> Unit): Listener<T, V> =
|
|
||||||
addListener(listener)
|
|
||||||
|
|
||||||
@OptIn(Listenable::class)
|
|
||||||
fun <V> KProperty0<V>.getListenableMutableDelegatedField(): ListenableMutableDelegatedField<Any, V>? {
|
|
||||||
isAccessible = true
|
|
||||||
var delegate = getDelegate() ?: getDelegate(receiver, name)
|
|
||||||
if (delegate is DelegatedField<*, *>) {
|
|
||||||
while (true) {
|
|
||||||
if (delegate is ListenableMutableDelegatedField<*, *>) {
|
|
||||||
@OptIn(UncheckedCast::class)
|
|
||||||
return delegate.cast()
|
|
||||||
}
|
|
||||||
if (delegate is DecoratorDelegatedField<*, *>) {
|
|
||||||
delegate = delegate.delegatedField
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (delegate is KProperty0<*> && delegate != this) {
|
|
||||||
@OptIn(UncheckedCast::class)
|
|
||||||
return delegate.cast<KProperty0<V>>().getListenableMutableDelegatedField()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <T, V> T.addChangeListener(
|
|
||||||
property: T.() -> KProperty0<V>,
|
|
||||||
): ListenableListener<T, V> {
|
|
||||||
val kProperty0 = property()
|
|
||||||
|
|
||||||
@OptIn(Listenable::class, UncheckedCast::class)
|
|
||||||
val delegatedField = kProperty0
|
|
||||||
.getListenableMutableDelegatedField()
|
|
||||||
.cast<ListenableMutableDelegatedField<T, V>?>()
|
|
||||||
?: throw UnmonitoredFieldException(kProperty0.toString())
|
|
||||||
return object : ListenableListener<T, V> {
|
|
||||||
private val selfList = ConcurrentLinkedQueue<Listener<T, V>>()
|
|
||||||
override fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V> {
|
|
||||||
@OptIn(Listenable::class)
|
|
||||||
val listener1 = delegatedField.addListener(listener)
|
|
||||||
selfList.add(listener1)
|
|
||||||
return listener1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V> {
|
|
||||||
selfList.forEach {
|
|
||||||
it.catch(handler)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun cancel(): Boolean {
|
|
||||||
selfList.forEach {
|
|
||||||
it.cancel()
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun finally(handler: T.(old: V, new: V) -> Unit): Listener<T, V> {
|
|
||||||
selfList.forEach {
|
|
||||||
it.finally(handler)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
32
ts-core/ts-delegation/ts-observer/build.gradle.kts
Normal file
32
ts-core/ts-delegation/ts-observer/build.gradle.kts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":ts-core"))
|
||||||
|
implementation(project(":ts-core:ts-delegation"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Suppress("UNCHECKED_CAST")
|
||||||
|
(rootProject.ext["excludeTest"] as (Project, TaskContainer) -> Unit)(project, tasks)
|
||||||
|
|
||||||
|
tasks.register("install") {
|
||||||
|
finalizedBy(tasks["publishToMavenLocal"])
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("maven") {
|
||||||
|
groupId = project.group.toString()
|
||||||
|
artifactId = project.name
|
||||||
|
version = project.version.toString()
|
||||||
|
|
||||||
|
from(components["java"])
|
||||||
|
try {
|
||||||
|
artifact(tasks["sourcesJar"])
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package cn.tursom.core.delegation
|
package cn.tursom.core.delegation.observer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标识一个属性可以被指定的 FieldChangeListener 监听
|
* 标识一个属性可以被指定的 FieldChangeListener 监听
|
@ -1,4 +1,4 @@
|
|||||||
package cn.tursom.core.delegation
|
package cn.tursom.core.delegation.observer
|
||||||
|
|
||||||
interface ListenableListener<out T, V> : Listener<T, V> {
|
interface ListenableListener<out T, V> : Listener<T, V> {
|
||||||
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V>
|
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V>
|
@ -1,5 +1,8 @@
|
|||||||
package cn.tursom.core.delegation
|
package cn.tursom.core.delegation.observer
|
||||||
|
|
||||||
|
import cn.tursom.core.delegation.DecoratorMutableDelegatedField
|
||||||
|
import cn.tursom.core.delegation.DelegatedFieldAttachmentKey
|
||||||
|
import cn.tursom.core.delegation.MutableDelegatedField
|
||||||
import cn.tursom.core.uncheckedCast
|
import cn.tursom.core.uncheckedCast
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque
|
import java.util.concurrent.ConcurrentLinkedDeque
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
@ -1,4 +1,4 @@
|
|||||||
package cn.tursom.core.delegation
|
package cn.tursom.core.delegation.observer
|
||||||
|
|
||||||
interface Listener<out T, V> {
|
interface Listener<out T, V> {
|
||||||
fun cancel(): Boolean
|
fun cancel(): Boolean
|
@ -1,4 +1,4 @@
|
|||||||
package cn.tursom.core.delegation
|
package cn.tursom.core.delegation.observer
|
||||||
|
|
||||||
class UnmonitoredFieldException : Exception {
|
class UnmonitoredFieldException : Exception {
|
||||||
constructor() : super()
|
constructor() : super()
|
@ -0,0 +1,109 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package cn.tursom.core.delegation.observer
|
||||||
|
|
||||||
|
import cn.tursom.core.UncheckedCast
|
||||||
|
import cn.tursom.core.cast
|
||||||
|
import cn.tursom.core.delegation.*
|
||||||
|
import cn.tursom.core.receiver
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
import kotlin.reflect.KMutableProperty0
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
|
import kotlin.reflect.jvm.isAccessible
|
||||||
|
|
||||||
|
|
||||||
|
@Listenable
|
||||||
|
fun <V> KMutableProperty0<V>.listenable(): MutableDelegatedField<Any, V> {
|
||||||
|
isAccessible = true
|
||||||
|
val delegate = getDelegate()
|
||||||
|
return if (delegate is MutableDelegatedField<*, *> && delegate[ListenableMutableDelegatedField] == true) {
|
||||||
|
@OptIn(UncheckedCast::class)
|
||||||
|
delegate.cast()
|
||||||
|
} else {
|
||||||
|
@OptIn(UncheckedCast::class)
|
||||||
|
(ListenableMutableDelegatedField(KPropertyMutableDelegatedField(cast())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listenable
|
||||||
|
fun <V> listenable(initValue: V): MutableDelegatedField<Any, V> = ListenableMutableDelegatedField(
|
||||||
|
MutableDelegatedFieldValue(initValue)
|
||||||
|
)
|
||||||
|
|
||||||
|
@Listenable
|
||||||
|
fun <T, V> MutableDelegatedField<T, V>.listenable(): MutableDelegatedField<T, V> =
|
||||||
|
ListenableMutableDelegatedField(this)
|
||||||
|
|
||||||
|
@JvmName("listenable1")
|
||||||
|
@Listenable
|
||||||
|
fun <T, V> listenable(delegatedField: MutableDelegatedField<T, V>): MutableDelegatedField<T, V> =
|
||||||
|
ListenableMutableDelegatedField(delegatedField)
|
||||||
|
|
||||||
|
|
||||||
|
infix operator fun <T, V> ListenableListener<T, V>.plus(listener: T.(old: V, new: V) -> Unit): Listener<T, V> =
|
||||||
|
addListener(listener)
|
||||||
|
|
||||||
|
@OptIn(Listenable::class)
|
||||||
|
fun <V> KProperty0<V>.getListenableMutableDelegatedField(): ListenableMutableDelegatedField<Any, V>? {
|
||||||
|
isAccessible = true
|
||||||
|
var delegate = getDelegate() ?: getDelegate(receiver, name)
|
||||||
|
if (delegate is DelegatedField<*, *>) {
|
||||||
|
while (true) {
|
||||||
|
if (delegate is ListenableMutableDelegatedField<*, *>) {
|
||||||
|
@OptIn(UncheckedCast::class)
|
||||||
|
return delegate.cast()
|
||||||
|
}
|
||||||
|
if (delegate is DecoratorDelegatedField<*, *>) {
|
||||||
|
delegate = delegate.delegatedField
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (delegate is KProperty0<*> && delegate != this) {
|
||||||
|
@OptIn(UncheckedCast::class)
|
||||||
|
return delegate.cast<KProperty0<V>>().getListenableMutableDelegatedField()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, V> T.addChangeListener(
|
||||||
|
property: T.() -> KProperty0<V>,
|
||||||
|
): ListenableListener<T, V> {
|
||||||
|
val kProperty0 = property()
|
||||||
|
|
||||||
|
@OptIn(Listenable::class, UncheckedCast::class)
|
||||||
|
val delegatedField = kProperty0
|
||||||
|
.getListenableMutableDelegatedField()
|
||||||
|
.cast<ListenableMutableDelegatedField<T, V>?>()
|
||||||
|
?: throw UnmonitoredFieldException(kProperty0.toString())
|
||||||
|
return object : ListenableListener<T, V> {
|
||||||
|
private val selfList = ConcurrentLinkedQueue<Listener<T, V>>()
|
||||||
|
override fun addListener(listener: T.(old: V, new: V) -> Unit): Listener<T, V> {
|
||||||
|
@OptIn(Listenable::class)
|
||||||
|
val listener1 = delegatedField.addListener(listener)
|
||||||
|
selfList.add(listener1)
|
||||||
|
return listener1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ListenableListener<T, V> {
|
||||||
|
selfList.forEach {
|
||||||
|
it.catch(handler)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cancel(): Boolean {
|
||||||
|
selfList.forEach {
|
||||||
|
it.cancel()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finally(handler: T.(old: V, new: V) -> Unit): Listener<T, V> {
|
||||||
|
selfList.forEach {
|
||||||
|
it.finally(handler)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package cn.tursom.core.encrypt
|
package cn.tursom.core.encrypt
|
||||||
|
|
||||||
import cn.tursom.core.Unsafe
|
import cn.tursom.core.Unsafe
|
||||||
import cn.tursom.core.cast
|
import cn.tursom.core.uncheckedCast
|
||||||
import java.security.KeyFactory
|
import java.security.KeyFactory
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
@ -72,7 +72,7 @@ class ECC(
|
|||||||
val standardCurveLineSet by lazy {
|
val standardCurveLineSet by lazy {
|
||||||
try {
|
try {
|
||||||
Unsafe {
|
Unsafe {
|
||||||
Class.forName("sun.security.ec.CurveDB")["nameMap"].cast<Map<String, Any>>().keys
|
Class.forName("sun.security.ec.CurveDB")["nameMap"].uncheckedCast<Map<String, Any>>().keys
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
emptySet()
|
emptySet()
|
||||||
|
@ -5,9 +5,9 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":"))
|
implementation(project(":"))
|
||||||
implementation(group = "org.slf4j", name = "slf4j-api", version = "1.7.29")
|
api(group = "org.slf4j", name = "slf4j-api", version = "1.7.29")
|
||||||
implementation(group = "ch.qos.logback", name = "logback-core", version = "1.2.3")
|
api(group = "ch.qos.logback", name = "logback-core", version = "1.2.3")
|
||||||
implementation(group = "ch.qos.logback", name = "logback-classic", version = "1.2.3")
|
api(group = "ch.qos.logback", name = "logback-classic", version = "1.2.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.Suppress("UNCHECKED_CAST")
|
@kotlin.Suppress("UNCHECKED_CAST")
|
||||||
|
Loading…
Reference in New Issue
Block a user