This commit is contained in:
tursom 2021-04-12 11:22:54 +08:00
parent b0cd840376
commit cc32906fc9
22 changed files with 807 additions and 512 deletions

View File

@ -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")

View 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
}

View File

@ -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
} }

View File

@ -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"))
} }

View File

@ -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>()")
}
}
}

View File

@ -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)
}
}
}
} }

View File

@ -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
}

View File

@ -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
} }

View File

@ -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()
} }
} }
} }

View File

@ -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()
} }
} }
} }

View File

@ -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

View File

@ -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()
} }
} }
} }

View File

@ -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
}
}
}

View 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) {
}
}
}
}

View File

@ -1,4 +1,4 @@
package cn.tursom.core.delegation package cn.tursom.core.delegation.observer
/** /**
* 标识一个属性可以被指定的 FieldChangeListener 监听 * 标识一个属性可以被指定的 FieldChangeListener 监听

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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
}
}
}

View File

@ -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()

View File

@ -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")