mirror of
https://github.com/tursom/TursomServer.git
synced 2025-01-30 14:20:07 +08:00
添加delegate和observe
This commit is contained in:
parent
c44e9fca3e
commit
530b0b8602
@ -1,7 +1,9 @@
|
||||
dependencies {
|
||||
compile project(":")
|
||||
compile project(":log")
|
||||
|
||||
// kotlin 协程
|
||||
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
|
||||
compile project(":log")
|
||||
testRuntime group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-debug', version: '1.3.9'
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
package cn.tursom.niothread.loophandler
|
||||
|
||||
import cn.tursom.core.randomInt
|
||||
import cn.tursom.niothread.NioThread
|
||||
import cn.tursom.core.Utils
|
||||
import cn.tursom.niothread.NioProtocol
|
||||
import cn.tursom.niothread.NioThread
|
||||
import java.nio.channels.SelectionKey
|
||||
import java.nio.channels.ServerSocketChannel
|
||||
|
||||
class MultithreadingBossLoopHandler(
|
||||
protocol: NioProtocol,
|
||||
@ -14,7 +13,7 @@ class MultithreadingBossLoopHandler(
|
||||
val workerThread: NioThread = if (workerThread.isEmpty()) {
|
||||
nioThread
|
||||
} else {
|
||||
workerThread[randomInt(0, workerThread.size - 1)]
|
||||
workerThread[Utils.random.nextInt(0, workerThread.size - 1)]
|
||||
}
|
||||
handle(nioThread, key, workerThread)
|
||||
}
|
||||
|
@ -1,17 +1,19 @@
|
||||
package cn.tursom.datagram.server
|
||||
|
||||
import cn.tursom.channel.BufferedAsyncChannel
|
||||
import cn.tursom.core.log
|
||||
import cn.tursom.core.pool.DirectMemoryPool
|
||||
import cn.tursom.datagram.AsyncDatagramClient
|
||||
import cn.tursom.log.impl.Slf4jImpl
|
||||
import cn.tursom.socket.NioClient
|
||||
import cn.tursom.socket.server.BuffedNioServer
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
val logger = Slf4jImpl.getLogger()
|
||||
|
||||
val echoHandler: suspend BufferedAsyncChannel.() -> Unit = {
|
||||
while (true) {
|
||||
val buffer = read()
|
||||
log("$this recv from client $remoteAddress: ${buffer.toString(buffer.readable)}")
|
||||
logger.debug("$this recv from client $remoteAddress: ${buffer.toString(buffer.readable)}")
|
||||
Throwable().printStackTrace()
|
||||
write(buffer)
|
||||
}
|
||||
@ -52,7 +54,7 @@ fun main() {
|
||||
client.write(line)
|
||||
client.read(3000)
|
||||
}
|
||||
log("recv from server: ${read.getString()}")
|
||||
logger.debug("recv from server: ${read.getString()}")
|
||||
read.close()
|
||||
} catch (e: Exception) {
|
||||
Exception(e).printStackTrace()
|
||||
|
13
build.gradle
13
build.gradle
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlinVersion = '1.4.0'
|
||||
ext.kotlinVersion = '1.4.31'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@ -28,14 +28,18 @@ allprojects {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
||||
api "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||
api "com.google.code.gson:gson:2.8.2"
|
||||
testImplementation group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
kotlinOptions.useIR = true
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
kotlinOptions.useIR = true
|
||||
}
|
||||
|
||||
//打包源代码
|
||||
@ -66,4 +70,11 @@ allprojects {
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings {
|
||||
useExperimentalAnnotation('-Xopt-in=kotlin.RequiresOptIn')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package cn.tursom.log
|
||||
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.event.Level
|
||||
|
||||
inline fun lazyLog(crossinline toString: () -> String) = object {
|
||||
override fun toString(): String = toString()
|
||||
}
|
||||
@ -26,4 +29,46 @@ inline fun lazyPrettyMap(map: Map<out CharSequence, Any>) = if (map.isNotEmpty()
|
||||
lazyPrettyMap(map.iterator())
|
||||
} else {
|
||||
"{}"
|
||||
}
|
||||
|
||||
fun Logger.isEnabled(level: Level) = when (level) {
|
||||
Level.ERROR -> isErrorEnabled
|
||||
Level.WARN -> isWarnEnabled
|
||||
Level.INFO -> isInfoEnabled
|
||||
Level.DEBUG -> isDebugEnabled
|
||||
Level.TRACE -> isTraceEnabled
|
||||
}
|
||||
|
||||
fun Logger.log(level: Level, msg: String, args: Array<*>) = when (level) {
|
||||
Level.ERROR -> error(msg, *args)
|
||||
Level.WARN -> warn(msg, *args)
|
||||
Level.INFO -> info(msg, *args)
|
||||
Level.DEBUG -> debug(msg, *args)
|
||||
Level.TRACE -> trace(msg, *args)
|
||||
}
|
||||
|
||||
@JvmName("friendlyLog")
|
||||
fun Logger.log(level: Level, msg: String, vararg args: Any?) = when (level) {
|
||||
Level.ERROR -> error(msg, *args)
|
||||
Level.WARN -> warn(msg, *args)
|
||||
Level.INFO -> info(msg, *args)
|
||||
Level.DEBUG -> debug(msg, *args)
|
||||
Level.TRACE -> trace(msg, *args)
|
||||
}
|
||||
|
||||
fun Logger.logCaller() = logCaller(Level.DEBUG)
|
||||
|
||||
fun Logger.logCaller(level: Level) {
|
||||
if (isEnabled(level)) {
|
||||
val e = Throwable()
|
||||
val stackTraceElement = e.stackTrace[1]
|
||||
log(
|
||||
level,
|
||||
"calling {}.{}({}:{})",
|
||||
stackTraceElement.className,
|
||||
stackTraceElement.methodName,
|
||||
stackTraceElement.fileName,
|
||||
stackTraceElement.lineNumber
|
||||
)
|
||||
}
|
||||
}
|
@ -3,21 +3,60 @@ package cn.tursom.log.impl
|
||||
import cn.tursom.log.Slf4j
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import sun.reflect.Reflection
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.jvm.jvmName
|
||||
|
||||
open class Slf4jImpl(name: String? = null) : Slf4j {
|
||||
constructor(clazz: Class<*>?) : this(clazz?.name)
|
||||
constructor(clazz: KClass<*>?) : this(clazz?.jvmName?.let {
|
||||
if (clazz.isCompanion) it.dropLast(10) else it
|
||||
open class Slf4jImpl(
|
||||
override val log: Logger,
|
||||
) : Slf4j, Logger by log {
|
||||
constructor(name: String? = null) : this(LoggerFactory.getLogger(name ?: loggerName))
|
||||
constructor(target: Class<*>?) : this(target?.canonicalName)
|
||||
constructor(target: Any?) : this(target?.let { it::class })
|
||||
constructor(target: KClass<*>?) : this(target?.let { clazz ->
|
||||
clazz.jvmName.let {
|
||||
if (clazz.isCompanion) {
|
||||
it.dropLast(10)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
override val log: Logger = LoggerFactory.getLogger(name ?: if (this.javaClass != Slf4jImpl::class.java) {
|
||||
val clazz = this.javaClass.kotlin
|
||||
clazz.jvmName.let {
|
||||
if (clazz.isCompanion) it.dropLast(10) else it
|
||||
@Suppress("MemberVisibilityCanBePrivate", "NOTHING_TO_INLINE")
|
||||
companion object {
|
||||
private val thisClassName = listOf(this::class.java.name.dropLast(10), this::class.java.name)
|
||||
private val loggerName: String
|
||||
get() = getCallerClassName() ?: throw UnsupportedOperationException()
|
||||
|
||||
private fun getCallerClassName(): String? {
|
||||
var clazz: Class<*>?
|
||||
var callStackDepth = 1
|
||||
do {
|
||||
@Suppress("DEPRECATION")
|
||||
clazz = Reflection.getCallerClass(callStackDepth++)
|
||||
if (clazz?.name !in thisClassName) {
|
||||
break
|
||||
}
|
||||
} while (clazz != null)
|
||||
return clazz?.name
|
||||
}
|
||||
} else {
|
||||
throw NotImplementedError("")
|
||||
})
|
||||
|
||||
inline fun getLogger(name: String): Logger = LoggerFactory.getLogger(name)
|
||||
|
||||
fun getLogger(): Logger = LoggerFactory.getLogger(loggerName)
|
||||
|
||||
inline fun getLogger(target: Any): Logger = getLogger(if (target::class != Slf4jImpl::class) {
|
||||
val kClass = target::class
|
||||
kClass.jvmName.let {
|
||||
if (kClass.isCompanion) {
|
||||
it.dropLast(10)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw NotImplementedError("there is no default logger name")
|
||||
})
|
||||
}
|
||||
}
|
@ -14,5 +14,7 @@ include 'database:redis'
|
||||
include 'utils:ws-client'
|
||||
include 'utils:mail'
|
||||
include 'utils:csv'
|
||||
include 'utils:delegation'
|
||||
include 'utils:observer'
|
||||
include 'utils:TrafficForward'
|
||||
include 'utils:performance-test'
|
@ -1,3 +1,4 @@
|
||||
dependencies {
|
||||
compile project(":")
|
||||
compile project(":log")
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package cn.tursom.socket.server
|
||||
|
||||
import cn.tursom.core.log
|
||||
import cn.tursom.core.logE
|
||||
import cn.tursom.socket.INioProtocol
|
||||
import cn.tursom.socket.niothread.INioThread
|
||||
import cn.tursom.socket.niothread.WorkerLoopNioThread
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.socket.server
|
||||
|
||||
import cn.tursom.core.getTAG
|
||||
import cn.tursom.log.impl.Slf4jImpl
|
||||
import cn.tursom.socket.BaseSocket
|
||||
import java.io.IOException
|
||||
import java.net.ServerSocket
|
||||
@ -41,22 +41,22 @@ class ThreadPoolSocketServer
|
||||
* @param timeUnit timeout的单位,默认毫秒
|
||||
* @param handler 对套接字处理的业务逻辑
|
||||
*/(
|
||||
override val port: Int,
|
||||
threads: Int = 1,
|
||||
queueSize: Int = 1,
|
||||
keepAliveTime: Long = 60_000L,
|
||||
timeUnit: TimeUnit = TimeUnit.MILLISECONDS,
|
||||
override val handler: BaseSocket.() -> Unit
|
||||
override val port: Int,
|
||||
threads: Int = 1,
|
||||
queueSize: Int = 1,
|
||||
keepAliveTime: Long = 60_000L,
|
||||
timeUnit: TimeUnit = TimeUnit.MILLISECONDS,
|
||||
override val handler: BaseSocket.() -> Unit
|
||||
) : ISimpleSocketServer {
|
||||
|
||||
constructor(
|
||||
port: Int,
|
||||
handler: BaseSocket.() -> Unit
|
||||
port: Int,
|
||||
handler: BaseSocket.() -> Unit
|
||||
) : this(port, 1, 1, 60_000L, TimeUnit.MILLISECONDS, handler)
|
||||
|
||||
var socket = Socket()
|
||||
private val pool: ThreadPoolExecutor =
|
||||
ThreadPoolExecutor(threads, threads, keepAliveTime, timeUnit, LinkedBlockingQueue(queueSize))
|
||||
ThreadPoolExecutor(threads, threads, keepAliveTime, timeUnit, LinkedBlockingQueue(queueSize))
|
||||
private var serverSocket: ServerSocket = ServerSocket(port)
|
||||
|
||||
/**
|
||||
@ -70,7 +70,7 @@ class ThreadPoolSocketServer
|
||||
while (!serverSocket.isClosed) {
|
||||
try {
|
||||
socket = serverSocket.accept()
|
||||
println("$TAG: run(): get connect: $socket")
|
||||
debug("run(): get connect: {}", socket)
|
||||
pool.execute {
|
||||
socket.use {
|
||||
BaseSocket(it).handler()
|
||||
@ -128,8 +128,7 @@ class ThreadPoolSocketServer
|
||||
closeServer()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = getTAG(this::class.java)
|
||||
companion object : Slf4jImpl() {
|
||||
/**
|
||||
* 线程池满时返回给客户端的信息
|
||||
*/
|
||||
|
79
src/main/kotlin/cn/tursom/core/EnumTypeAdapterFactory.kt
Normal file
79
src/main/kotlin/cn/tursom/core/EnumTypeAdapterFactory.kt
Normal file
@ -0,0 +1,79 @@
|
||||
package cn.tursom.core
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
|
||||
object EnumTypeAdapterFactory : TypeAdapterFactory {
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class EnumValue
|
||||
|
||||
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||
if (!type.rawType.isEnum) {
|
||||
return null
|
||||
}
|
||||
|
||||
val valueOf = type.rawType.getDeclaredMethod("valueOf", String::class.java)
|
||||
|
||||
val enumValueMap = type.rawType.enumConstants.asList().associateWith {
|
||||
val enum: T = it.cast()
|
||||
enum.javaClass.getField(it.toString()).getAnnotation(SerializedName::class.java)?.let { serializedName ->
|
||||
return@associateWith serializedName.value
|
||||
}
|
||||
|
||||
val field = enum.javaClass.declaredFields.firstOrNull { it2 ->
|
||||
it2.getAnnotation(EnumValue::class.java) != null
|
||||
}
|
||||
if (field != null) {
|
||||
field.isAccessible = true
|
||||
val value: Any = field.get(enum)
|
||||
value
|
||||
} else {
|
||||
enum
|
||||
}
|
||||
}
|
||||
|
||||
return object : TypeAdapter<T>() {
|
||||
override fun write(out: JsonWriter, value: T?) {
|
||||
if (value == null) {
|
||||
out.nullValue()
|
||||
} else {
|
||||
when (val enumValue = enumValueMap[value]) {
|
||||
null -> out.nullValue()
|
||||
is Boolean -> out.value(enumValue)
|
||||
is Char -> out.value(enumValue.toString())
|
||||
is Byte -> out.value(enumValue)
|
||||
is Short -> out.value(enumValue)
|
||||
is Int -> out.value(enumValue)
|
||||
is Long -> out.value(enumValue)
|
||||
is Float -> out.value(enumValue)
|
||||
is Double -> out.value(enumValue)
|
||||
is Enum<*> -> out.value(enumValue.toString())
|
||||
else -> out.jsonValue(Utils.gson.toJson(enumValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(reader: JsonReader): T? {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull()
|
||||
return null
|
||||
} else {
|
||||
val source = reader.nextString()
|
||||
enumValueMap.forEach { (value, type) ->
|
||||
if (type.toString() == source) {
|
||||
return value.cast()
|
||||
}
|
||||
}
|
||||
return valueOf(null, source).cast()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
src/main/kotlin/cn/tursom/core/GsonDataTypeAdaptor.kt
Normal file
81
src/main/kotlin/cn/tursom/core/GsonDataTypeAdaptor.kt
Normal file
@ -0,0 +1,81 @@
|
||||
package cn.tursom.core
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
|
||||
class GsonDataTypeAdaptor internal constructor(private val gson: Gson) : TypeAdapter<Map<String, Any>?>() {
|
||||
override fun write(out: JsonWriter, value: Map<String, Any>?) {
|
||||
if (value == null) {
|
||||
out.nullValue()
|
||||
return
|
||||
}
|
||||
out.beginObject()
|
||||
value.forEach { (t, u) ->
|
||||
out.name(t)
|
||||
System.err.println(u)
|
||||
gson.getAdapter(Any::class.java).write(out, u)
|
||||
}
|
||||
out.endObject()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Map<String, Any> = readInternal(`in`).cast()
|
||||
|
||||
private fun readInternal(`in`: JsonReader): Any? {
|
||||
return when (`in`.peek()) {
|
||||
JsonToken.BEGIN_ARRAY -> {
|
||||
val list: MutableList<Any?> = ArrayList()
|
||||
`in`.beginArray()
|
||||
while (`in`.hasNext()) {
|
||||
list.add(readInternal(`in`))
|
||||
}
|
||||
`in`.endArray()
|
||||
list
|
||||
}
|
||||
JsonToken.BEGIN_OBJECT -> {
|
||||
val map: MutableMap<String, Any?> = LinkedTreeMap()
|
||||
`in`.beginObject()
|
||||
while (`in`.hasNext()) {
|
||||
map[`in`.nextName()] = readInternal(`in`)
|
||||
}
|
||||
`in`.endObject()
|
||||
map
|
||||
}
|
||||
JsonToken.STRING -> `in`.nextString()
|
||||
JsonToken.NUMBER -> {
|
||||
//将其作为一个字符串读取出来
|
||||
val numberStr: String = `in`.nextString()
|
||||
//返回的numberStr不会为null
|
||||
if (numberStr.contains(".") || numberStr.contains("e")
|
||||
|| numberStr.contains("E")
|
||||
) {
|
||||
numberStr.toDouble()
|
||||
} else numberStr.toLong()
|
||||
}
|
||||
JsonToken.BOOLEAN -> `in`.nextBoolean()
|
||||
JsonToken.NULL -> {
|
||||
`in`.nextNull()
|
||||
null
|
||||
}
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FACTORY: TypeAdapterFactory = object : TypeAdapterFactory {
|
||||
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||
return if (type.rawType == Map::class.java) {
|
||||
GsonDataTypeAdaptor(gson).cast()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.tursom.core
|
||||
|
||||
import cn.tursom.core.Unsafe.unsafe
|
||||
import java.lang.reflect.Array
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
|
@ -2,229 +2,229 @@
|
||||
|
||||
package cn.tursom.core
|
||||
|
||||
import sun.misc.Unsafe
|
||||
import java.io.ByteArrayInputStream
|
||||
import cn.tursom.core.datastruct.ReversedList
|
||||
import cn.tursom.core.datastruct.StepList
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import sun.reflect.Reflection
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.io.Serializable
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.lang.reflect.Proxy
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.jar.JarFile
|
||||
import java.util.zip.Deflater
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import java.util.zip.Inflater
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashSet
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.experimental.and
|
||||
import kotlin.jvm.internal.PropertyReference
|
||||
import kotlin.random.Random
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.companionObjectInstance
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.full.superclasses
|
||||
|
||||
object Utils {
|
||||
const val dollar = '$'
|
||||
val random = Random(System.currentTimeMillis())
|
||||
|
||||
inline fun <reified T> Array<out T?>.excludeNull(): List<T> {
|
||||
val list = ArrayList<T>()
|
||||
forEach { if (it != null) list.add(it) }
|
||||
return list
|
||||
}
|
||||
|
||||
fun printNonDaemonThread() {
|
||||
val currentGroup = Thread.currentThread().threadGroup
|
||||
val noThreads = currentGroup.activeCount()
|
||||
val lstThreads = arrayOfNulls<Thread>(noThreads)
|
||||
currentGroup.enumerate(lstThreads)
|
||||
lstThreads.excludeNull().forEach { t ->
|
||||
if (!t.isDaemon) {
|
||||
log(t.name)
|
||||
}
|
||||
@Suppress("unused", "SpellCheckingInspection")
|
||||
val gson: Gson by lazy {
|
||||
GsonBuilder()
|
||||
.registerTypeAdapterFactory(GsonDataTypeAdaptor.FACTORY)
|
||||
.registerTypeAdapterFactory(EnumTypeAdapterFactory)
|
||||
.create()
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
fun log(log: String) = println("${ThreadLocalSimpleDateFormat.standard.format(System.currentTimeMillis())}: $log")
|
||||
fun logE(log: String) =
|
||||
System.err.println("${ThreadLocalSimpleDateFormat.standard.format(System.currentTimeMillis())}: $log")
|
||||
|
||||
val String.urlDecode: String get() = URLDecoder.decode(this, "utf-8")
|
||||
val String.urlEncode: String get() = URLEncoder.encode(this, "utf-8")
|
||||
|
||||
inline fun <T> usingTime(action: () -> T): Long {
|
||||
val t1 = System.currentTimeMillis()
|
||||
action()
|
||||
val t2 = System.currentTimeMillis()
|
||||
return t2 - t1
|
||||
}
|
||||
|
||||
inline fun <T> usingNanoTime(action: () -> T): Long {
|
||||
val t1 = System.nanoTime()
|
||||
action()
|
||||
val t2 = System.nanoTime()
|
||||
return t2 - t1
|
||||
}
|
||||
|
||||
inline fun <T> Collection<T>.toString(action: (T) -> Any): String {
|
||||
val iterator = iterator()
|
||||
if (!iterator.hasNext()) return "[]"
|
||||
val sb = StringBuilder("[${action(iterator.next())}")
|
||||
iterator.forEach {
|
||||
sb.append(", ")
|
||||
sb.append(action(it))
|
||||
@Suppress("unused", "SpellCheckingInspection")
|
||||
val prettyGson: Gson by lazy {
|
||||
GsonBuilder()
|
||||
.registerTypeAdapterFactory(GsonDataTypeAdaptor.FACTORY)
|
||||
.registerTypeAdapterFactory(EnumTypeAdapterFactory)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
}
|
||||
|
||||
internal val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
|
||||
internal val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray()
|
||||
val md5 by lazy { MessageDigest.getInstance("MD5")!! }
|
||||
val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! }
|
||||
val sha by lazy { MessageDigest.getInstance("SHA")!! }
|
||||
val sha1 by lazy { MessageDigest.getInstance("SHA-1")!! }
|
||||
val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! }
|
||||
val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! }
|
||||
|
||||
internal val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray()
|
||||
|
||||
val receiverField: Field by lazy {
|
||||
kotlin.jvm.internal.CallableReference::class.java.getDeclaredField("receiver").apply { isAccessible = true }
|
||||
}
|
||||
val ownerField: Field by lazy {
|
||||
kotlin.jvm.internal.CallableReference::class.java.getDeclaredField("owner").apply { isAccessible = true }
|
||||
}
|
||||
sb.append("]")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
val unsafe by lazy {
|
||||
val field = Unsafe::class.java.getDeclaredField("theUnsafe")
|
||||
field.isAccessible = true
|
||||
field.get(null) as Unsafe
|
||||
fun String.hexStringToByteArray(): ByteArray {
|
||||
val len = length
|
||||
val data = ByteArray(len / 2)
|
||||
var i = 0
|
||||
while (i < len) {
|
||||
data[i / 2] = (Character.digit(this[i], 16) shl 4 or Character.digit(this[i + 1], 16)).toByte()
|
||||
i += 2
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> Class<T>.unsafeInstance() = unsafe.allocateInstance(this) as T
|
||||
|
||||
val Class<*>.actualTypeArguments: Array<out Type>
|
||||
get() = (genericSuperclass as ParameterizedType).actualTypeArguments
|
||||
fun ByteArray.toHexString(upper: Boolean = true): String = if (upper) toUpperHexString() else toLowerHexString()
|
||||
|
||||
fun ByteArray.toUpperHexString(): String {
|
||||
val hexChars = CharArray(size * 2)
|
||||
for (i in indices) {
|
||||
val b = this[i]
|
||||
hexChars[i shl 1] = Utils.UPPER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = Utils.UPPER_HEX_ARRAY[(b and 0x0F).toInt()]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun ByteArray.toLowerHexString(): String {
|
||||
val hexChars = CharArray(size * 2)
|
||||
for (i in indices) {
|
||||
val b = this[i]
|
||||
hexChars[i shl 1] = Utils.LOWER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = Utils.LOWER_HEX_ARRAY[(b and 0x0F).toInt()]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
|
||||
inline fun <T, R : Any> Iterable<T>.toSetNotNull(transform: (T) -> R?): Set<R> {
|
||||
return HashSet<R>().apply { this@toSetNotNull.forEach { add(transform(it) ?: return@forEach) } }
|
||||
}
|
||||
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
|
||||
inline fun <T> Any?.cast() = this as T
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
|
||||
inline fun <reified T> Any?.castOrNull() = if (this is T) this else null
|
||||
|
||||
inline fun <T> T?.checkNull(ifNull: () -> Exception): T {
|
||||
if (this == null) {
|
||||
throw ifNull()
|
||||
} else {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
fun String.emptyToNull() = if (isEmpty()) null else this
|
||||
|
||||
inline fun <reified T> getClazz() = T::class.java
|
||||
|
||||
fun Class<*>.isInheritanceFrom(parent: Class<*>) = parent.isAssignableFrom(this)
|
||||
|
||||
fun getClassName(jarPath: String): List<String> {
|
||||
val myClassName = ArrayList<String>()
|
||||
for (entry in JarFile(jarPath).entries()) {
|
||||
val entryName = entry.name
|
||||
if (entryName.endsWith(".class")) {
|
||||
myClassName.add(entryName.replace("/", ".").substring(0, entryName.lastIndexOf(".")))
|
||||
}
|
||||
}
|
||||
return myClassName
|
||||
operator fun <T> (() -> T).unaryPlus() = object : () -> T {
|
||||
override operator fun invoke() = this@unaryPlus()
|
||||
override fun toString(): String = this@unaryPlus().toString()
|
||||
}
|
||||
|
||||
fun <T> List<T>.binarySearch(comparison: (T) -> Int): T? {
|
||||
val index = binarySearch(0, size, comparison)
|
||||
return if (index < 0) null
|
||||
else get(index)
|
||||
fun String.toLowerCase(vararg indexes: Int): String {
|
||||
val charArray = toCharArray()
|
||||
indexes.forEach { index ->
|
||||
charArray[index] = charArray[index].toLowerCase()
|
||||
}
|
||||
return String(charArray)
|
||||
}
|
||||
|
||||
val cpuNumber = Runtime.getRuntime().availableProcessors()
|
||||
|
||||
fun String.simplifyPath(): String {
|
||||
if (isEmpty()) {
|
||||
return "."
|
||||
fun String.toUpperCase(vararg indexes: Int): String {
|
||||
val charArray = toCharArray()
|
||||
indexes.forEach { index ->
|
||||
charArray[index] = charArray[index].toUpperCase()
|
||||
}
|
||||
val pathList = split(java.io.File.separator).dropLastWhile { it.isEmpty() }
|
||||
val list = LinkedList<String>()
|
||||
for (path in pathList) {
|
||||
if (path.isEmpty() || "." == path) {
|
||||
continue
|
||||
}
|
||||
if (".." == path) {
|
||||
list.pollLast()
|
||||
continue
|
||||
}
|
||||
list.addLast(path)
|
||||
}
|
||||
var result = ""
|
||||
while (list.size > 0) {
|
||||
result += java.io.File.separator + list.pollFirst()!!
|
||||
}
|
||||
return if (result.isNotEmpty()) result else "."
|
||||
return String(charArray)
|
||||
}
|
||||
|
||||
//获取md5加密对象
|
||||
val md5 by lazy { MessageDigest.getInstance("MD5")!! }
|
||||
fun String.toLowerCase(indexes: IntRange): String {
|
||||
val charArray = toCharArray()
|
||||
indexes.forEach { index ->
|
||||
charArray[index] = charArray[index].toLowerCase()
|
||||
}
|
||||
return String(charArray)
|
||||
}
|
||||
|
||||
fun String.toUpperCase(indexes: IntRange): String {
|
||||
val charArray = toCharArray()
|
||||
indexes.forEach { index ->
|
||||
charArray[index] = charArray[index].toUpperCase()
|
||||
}
|
||||
return String(charArray)
|
||||
}
|
||||
|
||||
fun ByteArray.md5(): ByteArray {
|
||||
//加密,返回字节数组
|
||||
return md5.digest(this)
|
||||
return Utils.md5.digest(this)
|
||||
}
|
||||
|
||||
fun String.md5(): String = toByteArray().md5().toHexString()
|
||||
|
||||
|
||||
//获取md5加密对象
|
||||
val sha256 by lazy { MessageDigest.getInstance("SHA-256")!! }
|
||||
|
||||
fun ByteArray.sha256(): ByteArray {
|
||||
//加密,返回字节数组
|
||||
return sha256.digest(this)
|
||||
return Utils.sha256.digest(this)
|
||||
}
|
||||
|
||||
fun String.sha256(): String = toByteArray().sha256().toHexString()
|
||||
|
||||
//获取sha加密对象
|
||||
val sha by lazy { MessageDigest.getInstance("SHA")!! }
|
||||
|
||||
fun ByteArray.sha(): ByteArray = sha.digest(this)
|
||||
fun ByteArray.sha(): ByteArray = Utils.sha.digest(this)
|
||||
|
||||
fun String.sha(): String = toByteArray().sha().toHexString()
|
||||
|
||||
//获取sha1加密对象
|
||||
val sha1 by lazy { MessageDigest.getInstance("SHA-1")!! }
|
||||
|
||||
fun ByteArray.sha1(): ByteArray = sha1.digest(this)
|
||||
fun ByteArray.sha1(): ByteArray = Utils.sha1.digest(this)
|
||||
|
||||
fun String.sha1(): String = toByteArray().sha1().toHexString()
|
||||
|
||||
//获取sha384加密对象
|
||||
val sha384 by lazy { MessageDigest.getInstance("SHA-384")!! }
|
||||
|
||||
fun ByteArray.sha384(): ByteArray = sha384.digest(this)
|
||||
fun ByteArray.sha384(): ByteArray = Utils.sha384.digest(this)
|
||||
|
||||
fun String.sha384(): String = toByteArray().sha384().toHexString()
|
||||
|
||||
//获取 sha-512 加密对象
|
||||
val sha512 by lazy { MessageDigest.getInstance("SHA-512")!! }
|
||||
|
||||
fun ByteArray.sha512(): ByteArray = sha512.digest(this)
|
||||
fun ByteArray.sha512(): ByteArray = Utils.sha512.digest(this)
|
||||
|
||||
fun String.sha512(): String = toByteArray().sha512().toHexString()
|
||||
|
||||
|
||||
fun ByteArray.toHexString(upper: Boolean = true): String = if (upper) toUpperHexString() else toLowerHexString()
|
||||
|
||||
private val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
|
||||
fun ByteArray.toUpperHexString(): String {
|
||||
val hexChars = CharArray(size * 2)
|
||||
for (i in indices) {
|
||||
val b = this[i]
|
||||
hexChars[i shl 1] = UPPER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = UPPER_HEX_ARRAY[(b and 0x0F).toInt()]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
private val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray()
|
||||
fun ByteArray.toLowerHexString(): String {
|
||||
val hexChars = CharArray(size * 2)
|
||||
for (i in indices) {
|
||||
val b = this[i]
|
||||
hexChars[i shl 1] = LOWER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = LOWER_HEX_ARRAY[(b and 0x0F).toInt()]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun String.fromHexString(): ByteArray {
|
||||
val source = toLowerCase()
|
||||
val data = ByteArray(length / 2)
|
||||
for (i in 0 until length / 2) {
|
||||
data[i] = ((LOWER_HEX_ARRAY.indexOf(source[i * 2]) shl 4) + LOWER_HEX_ARRAY.indexOf(source[i * 2 + 1])).toByte()
|
||||
data[i] =
|
||||
((Utils.UPPER_HEX_ARRAY.indexOf(source[i * 2]) shl 4) + Utils.UPPER_HEX_ARRAY.indexOf(source[i * 2 + 1])).toByte()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun ByteArray.toUTF8String() = String(this, Charsets.UTF_8)
|
||||
|
||||
fun String.base64(): String = this.toByteArray().base64().toUTF8String()
|
||||
fun String.base64() = this.toByteArray().base64().toUTF8String()
|
||||
fun ByteArray.base64(): ByteArray = Base64.getEncoder().encode(this)
|
||||
fun String.base64Url(): String = this.toByteArray().base64Url().toUTF8String()
|
||||
fun ByteArray.base64Url(): ByteArray = Base64.getUrlEncoder().encode(this)
|
||||
fun String.base64Mime(): String = this.toByteArray().base64Mime().toUTF8String()
|
||||
fun ByteArray.base64Mime(): ByteArray = Base64.getMimeEncoder().encode(this)
|
||||
|
||||
fun String.base64decode(): String = Base64.getDecoder().decode(this).toUTF8String()
|
||||
fun String.base64decode() = Base64.getDecoder().decode(this).toUTF8String()
|
||||
fun ByteArray.base64decode(): ByteArray = Base64.getDecoder().decode(this)
|
||||
fun String.base64UrlDecode(): String = Base64.getUrlDecoder().decode(this).toUTF8String()
|
||||
fun ByteArray.base64UrlDecode(): ByteArray = Base64.getUrlDecoder().decode(this)
|
||||
@ -234,163 +234,56 @@ fun ByteArray.base64MimeDecode(): ByteArray = Base64.getMimeDecoder().decode(thi
|
||||
fun String.digest(type: String) = toByteArray().digest(type)?.toHexString()
|
||||
|
||||
fun ByteArray.digest(type: String) = try {
|
||||
//获取加密对象
|
||||
val instance = MessageDigest.getInstance(type)
|
||||
//加密,返回字节数组
|
||||
instance.digest(this)
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
|
||||
val random = Random()
|
||||
fun randomInt() = random.nextInt()
|
||||
fun randomInt(min: Int, max: Int): Int =
|
||||
if (min > max) randomInt(max, min) else (random.nextInt() and Int.MAX_VALUE) % (max - min + 1) + min
|
||||
|
||||
fun randomLong() = random.nextLong()
|
||||
fun randomLong(min: Long, max: Long) = (random.nextLong() and Long.MAX_VALUE) % (max - min + 1) + min
|
||||
fun randomBoolean() = random.nextBoolean()
|
||||
fun randomFloat() = random.nextFloat()
|
||||
fun randomDouble() = random.nextDouble()
|
||||
fun randomGaussian() = random.nextGaussian()
|
||||
fun randomBytes(bytes: ByteArray) = random.nextBytes(bytes)
|
||||
|
||||
fun getTAG(cls: Class<*>): String {
|
||||
return cls.name.split(".").last().dropLast(10)
|
||||
}
|
||||
|
||||
operator fun <T> (() -> T).unaryPlus() = object : () -> T {
|
||||
override fun invoke(): T = this@unaryPlus()
|
||||
override fun toString() = this@unaryPlus().toString()
|
||||
}
|
||||
|
||||
operator fun Executor.invoke(action: () -> Unit) {
|
||||
execute(action)
|
||||
}
|
||||
|
||||
operator fun Executor.invoke(action: Runnable) = this(action::run)
|
||||
|
||||
inline fun <reified T : Annotation> Field.getAnnotation(): T? = getAnnotation(T::class.java)
|
||||
|
||||
inline fun <reified T : Annotation> Class<*>.getAnnotation(): T? = getAnnotation(T::class.java)
|
||||
|
||||
fun process(size: Int, vararg actions: () -> Unit) {
|
||||
actions.forEachIndexed { index, function ->
|
||||
if (actions.size - index <= size) function()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> process(value: T, vararg actions: Pair<T, () -> Unit>) {
|
||||
var checked = false
|
||||
actions.forEach { (v, function) ->
|
||||
if (checked || value == v) {
|
||||
checked = true
|
||||
function()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> T.println(): T {
|
||||
println(this)
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
|
||||
inline fun <T> Any?.cast(): T = this as T
|
||||
|
||||
inline fun loop(`continue`: () -> Boolean = { true }, action: () -> Unit) {
|
||||
while (`continue`()) action()
|
||||
}
|
||||
|
||||
inline fun <reified T> getClazz() = T::class.java
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <R, T : Function<R>> lambda(lambda: T) = lambda
|
||||
|
||||
fun ByteArray.gz(): ByteArray {
|
||||
val os = ByteArrayOutputStream()
|
||||
GZIPOutputStream(os).use {
|
||||
it.write(this)
|
||||
}
|
||||
return os.toByteArray()
|
||||
}
|
||||
|
||||
fun ByteArray.ungz(): ByteArray {
|
||||
return GZIPInputStream(ByteArrayInputStream(this)).readBytes()
|
||||
}
|
||||
|
||||
fun ByteArray.undeflate(): ByteArray {
|
||||
val infl = Inflater()
|
||||
infl.setInput(this)
|
||||
val bos = ByteArrayOutputStream()
|
||||
val outByte = ByteArray(1024)
|
||||
bos.use {
|
||||
while (!infl.finished()) {
|
||||
// 解压缩并将解压缩后的内容输出到字节输出流bos中
|
||||
val len = infl.inflate(outByte)
|
||||
if (len == 0) {
|
||||
break
|
||||
}
|
||||
bos.write(outByte, 0, len)
|
||||
}
|
||||
infl.end()
|
||||
}
|
||||
return bos.toByteArray()
|
||||
}
|
||||
|
||||
|
||||
fun ByteArray.deflate(): ByteArray {
|
||||
val defl = Deflater()
|
||||
defl.setInput(this)
|
||||
defl.finish()
|
||||
val bos = ByteArrayOutputStream()
|
||||
val outputByte = ByteArray(1024)
|
||||
bos.use {
|
||||
while (!defl.finished()) {
|
||||
// 压缩并将压缩后的内容输出到字节输出流bos中
|
||||
val len = defl.deflate(outputByte)
|
||||
bos.write(outputByte, 0, len)
|
||||
}
|
||||
defl.end()
|
||||
}
|
||||
return bos.toByteArray()
|
||||
}
|
||||
|
||||
//fun ByteArray.deflate(): ByteArray {
|
||||
// val os = ByteArrayOutputStream()
|
||||
// DeflaterOutputStream(os).use {
|
||||
// it.write(this)
|
||||
// }
|
||||
// return os.toByteArray()
|
||||
//}
|
||||
//
|
||||
//fun ByteArray.undeflate(): ByteArray {
|
||||
// return DeflaterInputStream(ByteArrayInputStream(this)).readBytes()
|
||||
//}
|
||||
|
||||
inline fun <reified T : Any?> Any.assert(action: T.() -> Unit): Boolean {
|
||||
return if (this is T) {
|
||||
action()
|
||||
fun <A : Annotation, V : Any> A.changeAnnotationValue(field: KProperty1<A, V>, value: V): Boolean {
|
||||
return try {
|
||||
val h = Proxy.getInvocationHandler(this)
|
||||
val memberValuesField = h.javaClass.getDeclaredField("memberValues")
|
||||
memberValuesField.isAccessible = true
|
||||
val memberValues = memberValuesField[h].cast<MutableMap<String, Any>>()
|
||||
memberValues[field.name] = value
|
||||
true
|
||||
} else {
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
val Class<*>.allFields: List<Field>
|
||||
get() {
|
||||
var clazz = this
|
||||
val list = ArrayList<Field>()
|
||||
while (clazz != Any::class.java) {
|
||||
list.addAll(clazz.declaredFields)
|
||||
clazz = clazz.superclass
|
||||
/**
|
||||
* 向数据库提交一项任务并获取返回值
|
||||
*/
|
||||
suspend fun <T> Executor.runWith(action: () -> T): T = suspendCoroutine { cont ->
|
||||
execute {
|
||||
try {
|
||||
cont.resume(action())
|
||||
} catch (e: Exception) {
|
||||
cont.resumeWithException(e)
|
||||
}
|
||||
list.addAll(clazz.declaredFields)
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
fun Class<*>.forAllFields(action: (Field) -> Unit) {
|
||||
inline fun <reified T : Any> Gson.fromJson(json: String): T = fromJson(json, T::class.java)
|
||||
|
||||
inline fun usingTime(action: () -> Unit): Long {
|
||||
val t1 = System.currentTimeMillis()
|
||||
action()
|
||||
val t2 = System.currentTimeMillis()
|
||||
return t2 - t1
|
||||
}
|
||||
|
||||
inline fun usingNanoTime(action: () -> Unit): Long {
|
||||
val t1 = System.nanoTime()
|
||||
action()
|
||||
val t2 = System.nanoTime()
|
||||
return t2 - t1
|
||||
}
|
||||
|
||||
inline fun Class<*>.forAllFields(action: (Field) -> Unit) {
|
||||
var clazz = this
|
||||
while (clazz != Any::class.java) {
|
||||
clazz.declaredFields.forEach(action)
|
||||
@ -399,14 +292,21 @@ fun Class<*>.forAllFields(action: (Field) -> Unit) {
|
||||
clazz.declaredFields.forEach(action)
|
||||
}
|
||||
|
||||
fun <T, R> Iterable<T>.firstNotNull(selector: (T) -> R): R? {
|
||||
forEach {
|
||||
return selector(it) ?: return@forEach
|
||||
val Class<*>.allFields: List<Field>
|
||||
get() {
|
||||
val fieldList = ArrayList<Field>()
|
||||
forAllFields(fieldList::add)
|
||||
return fieldList
|
||||
}
|
||||
|
||||
fun Class<*>.getFieldForAll(name: String): Field? {
|
||||
forAllFields {
|
||||
if (it.name == name) return it
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun Class<*>.forAllMethods(action: (Method) -> Unit) {
|
||||
inline fun Class<*>.forAllMethods(action: (Method) -> Unit) {
|
||||
var clazz = this
|
||||
while (clazz != Any::class.java) {
|
||||
clazz.declaredMethods.forEach(action)
|
||||
@ -415,14 +315,51 @@ fun Class<*>.forAllMethods(action: (Method) -> Unit) {
|
||||
clazz.declaredMethods.forEach(action)
|
||||
}
|
||||
|
||||
private val BASE62_DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()
|
||||
fun Class<*>.getMethodForAll(name: String, vararg parameterTypes: Class<*>?): Method? {
|
||||
forAllMethods {
|
||||
if (it.name == name && parameterTypes.contentEquals(it.parameterTypes)) return it
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val Class<*>.allMethods: List<Method>
|
||||
get() {
|
||||
val fieldList = ArrayList<Method>()
|
||||
forAllMethods(fieldList::add)
|
||||
return fieldList
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个 KProperty<*> 对应的对象
|
||||
*/
|
||||
val KProperty<*>.receiver: Any?
|
||||
get() = if (this is PropertyReference) {
|
||||
boundReceiver
|
||||
} else try {
|
||||
Utils.receiverField.get(this)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
} ?: javaClass.getFieldForAll("receiver")?.let {
|
||||
it.isAccessible = true
|
||||
it.get(this)
|
||||
}
|
||||
|
||||
val KProperty<*>.owner: Class<*>?
|
||||
get() = try {
|
||||
Utils.ownerField.get(this)?.cast<Class<*>>()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
} ?: javaClass.getFieldForAll("owner")?.let {
|
||||
it.isAccessible = true
|
||||
it.get(this)?.castOrNull()
|
||||
}
|
||||
|
||||
tailrec fun Long.base62(sBuilder: StringBuilder = StringBuilder()): String {
|
||||
return if (this == 0L) {
|
||||
sBuilder.reverse().toString()
|
||||
} else {
|
||||
val remainder = (this % 62).toInt()
|
||||
sBuilder.append(BASE62_DIGITS[remainder])
|
||||
sBuilder.append(Utils.DIGITS[remainder])
|
||||
(this / 62).base62(sBuilder)
|
||||
}
|
||||
}
|
||||
@ -430,10 +367,208 @@ tailrec fun Long.base62(sBuilder: StringBuilder = StringBuilder()): String {
|
||||
fun String.base62Decode(): Long {
|
||||
var sum: Long = 0
|
||||
val len = length
|
||||
var base = 62L
|
||||
var base = 1L
|
||||
for (i in 0 until len) {
|
||||
sum += BASE62_DIGITS.indexOf(this[len - i - 1]) * base
|
||||
sum += Utils.DIGITS.indexOf(this[len - i - 1]) * base
|
||||
base *= 62
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
fun Any.toJson(): String = Utils.gson.toJson(this)
|
||||
fun Any.toPrettyJson(): String = Utils.prettyGson.toJson(this)
|
||||
|
||||
inline fun <reified T : Any> String.fromJson(): T = Utils.gson.fromJson(this, T::class.java)
|
||||
|
||||
fun Any.serialize(): ByteArray {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
ObjectOutputStream(outputStream).writeObject(this)
|
||||
return outputStream.toByteArray()
|
||||
}
|
||||
|
||||
operator fun <E> List<E>.get(startIndex: Int = 0, endIndex: Int = size, step: Int = 1): List<E> {
|
||||
if (step <= 0) throw IllegalArgumentException("step($step) is negative or zero")
|
||||
val fromIndex = when {
|
||||
startIndex < 0 -> size + startIndex
|
||||
startIndex >= size -> size
|
||||
else -> startIndex
|
||||
}
|
||||
val toIndex = when {
|
||||
endIndex < 0 -> size + endIndex + 1
|
||||
endIndex >= size -> size
|
||||
else -> endIndex
|
||||
}
|
||||
var targetList = if (fromIndex > toIndex) ReversedList(subList(toIndex, fromIndex)) else subList(fromIndex, toIndex)
|
||||
if (step != 1) targetList = targetList step step
|
||||
return targetList
|
||||
}
|
||||
|
||||
operator fun <E> List<E>.get(intProgression: IntProgression): List<E> {
|
||||
val first = intProgression.first
|
||||
val last = intProgression.last
|
||||
val step = intProgression.step
|
||||
return when {
|
||||
step == 0 -> get(first, last + if (last < 0) 0 else 1, 1)
|
||||
step < 0 -> get(first + if (last > 0 && first >= 0) 1 else 0, last, -step)
|
||||
else -> get(first, last + if (last < 0) 0 else 1, step)
|
||||
}
|
||||
}
|
||||
|
||||
infix fun <E> List<E>.step(step: Int): List<E> = StepList(this, step)
|
||||
|
||||
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 生成结果,否则范湖自身
|
||||
*/
|
||||
inline fun <T> T.ifThen(condition: T.() -> Boolean, then: () -> T) = if (condition()) then() else this
|
||||
|
||||
@JvmName("ifThenNullable")
|
||||
inline fun <T> T.ifThen(condition: T.() -> Boolean, then: () -> T?) = if (condition()) then() else this
|
||||
|
||||
inline fun <T> Any.wait(action: () -> T) = synchronized(this) {
|
||||
val t = action()
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
(this as Object).wait()
|
||||
t
|
||||
}
|
||||
|
||||
inline fun <T> Any.notify(action: () -> T) = synchronized(this) {
|
||||
val t = action()
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
(this as Object).notify()
|
||||
t
|
||||
}
|
||||
|
||||
inline fun <T> Any.notifyAll(action: () -> T) = synchronized(this) {
|
||||
val t = action()
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
(this as Object).notifyAll()
|
||||
t
|
||||
}
|
||||
|
||||
inline val KClass<*>.companionObjectInstanceOrNull: Any?
|
||||
get() = try {
|
||||
companionObjectInstance
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
inline val <K : Any, V> Map<K?, V>.notNullKey get() = cast<Map<K, V>>()
|
||||
inline val <K, V : Any> Map<K, V?>.notNullValue get() = cast<Map<K, V>>()
|
||||
inline val <K : Any, V : Any> Map<K?, V?>.notNullEntry get() = cast<Map<K, V>>()
|
||||
|
||||
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
|
||||
|
||||
val <T : Any> KClass<T>.allMemberProperties: List<KProperty1<T, *>>
|
||||
get() {
|
||||
val propertiesList = memberProperties.toMutableList()
|
||||
var superClass = superclasses.firstOrNull {
|
||||
!it.java.isInterface
|
||||
}
|
||||
while (superClass != null) {
|
||||
propertiesList.addAll(superClass.memberProperties.cast())
|
||||
superClass = superClass.superclasses.firstOrNull {
|
||||
!it.java.isInterface
|
||||
}
|
||||
}
|
||||
return propertiesList
|
||||
}
|
||||
|
||||
fun String.toStartWith(prefix: String) = if (startsWith(prefix)) this else prefix + this
|
||||
fun String.toStartWith(prefix: Char) = if (startsWith(prefix)) this else prefix + this
|
||||
|
||||
|
||||
fun mongoLegal(value: Any?) = when {
|
||||
value == null -> true
|
||||
value is Number -> true
|
||||
value is Boolean -> true
|
||||
value is Char -> true
|
||||
value is String -> true
|
||||
value is Serializable -> true
|
||||
value.javaClass.kotlin.isData -> true
|
||||
value.javaClass.name.endsWith("DTO") -> true
|
||||
value.javaClass.name.endsWith("VO") -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun getCallerClass(thisClassName: List<String>): Class<*>? {
|
||||
var clazz: Class<*>?
|
||||
var callStackDepth = 1
|
||||
do {
|
||||
clazz = getCallerClass(callStackDepth++)
|
||||
if (clazz?.name !in thisClassName) {
|
||||
break
|
||||
}
|
||||
} while (clazz != null)
|
||||
return clazz
|
||||
}
|
||||
|
||||
fun getCallerClassName(thisClassName: List<String>): String? {
|
||||
return getCallerClass(thisClassName)?.name
|
||||
}
|
||||
|
||||
fun getCallerClass(callStackDepth: Int): Class<*>? {
|
||||
@Suppress("DEPRECATION")
|
||||
return Reflection.getCallerClass(callStackDepth)
|
||||
}
|
||||
|
||||
fun getCallerClassName(callStackDepth: Int): String? {
|
||||
return getCallerClass(callStackDepth)?.name
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun CharSequence?.isNotNullOrEmpty(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isNotNullOrEmpty != null)
|
||||
}
|
||||
|
||||
return this != null && this.isNotEmpty()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun Collection<*>?.isNotNullOrEmpty(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isNotNullOrEmpty != null)
|
||||
}
|
||||
|
||||
return this != null && this.isNotEmpty()
|
||||
}
|
||||
|
||||
//@OptIn(ExperimentalContracts::class)
|
||||
//fun main() {
|
||||
// val s: String? = ""
|
||||
// if (s.isNotNullAndEmpty()) {
|
||||
// println(s.length)
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
inline fun <reified T> Any?.assert(ifMatch: T.() -> Unit) = if (this is T) {
|
||||
ifMatch()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
val cpuNumber get() = Runtime.getRuntime().availableProcessors()
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <R, T : Function<R>> lambda(lambda: T) = lambda
|
||||
|
||||
val String.urlDecode: String get() = URLDecoder.decode(this, "utf-8")
|
||||
val String.urlEncode: String get() = URLEncoder.encode(this, "utf-8")
|
||||
|
||||
fun <T> List<T>.binarySearch(comparison: (T) -> Int): T? {
|
||||
val index = binarySearch(0, size, comparison)
|
||||
return if (index < 0) null
|
||||
else get(index)
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
open class AbstractListIterator<E>(
|
||||
val list: List<E>,
|
||||
private var index: Int = 0
|
||||
) : ListIterator<E> {
|
||||
override fun hasNext(): Boolean = list.size > index
|
||||
override fun next(): E = list[index++]
|
||||
override fun nextIndex(): Int = index
|
||||
override fun hasPrevious(): Boolean = index > 0
|
||||
override fun previous(): E = list[--index]
|
||||
|
||||
override fun previousIndex(): Int = index - 1
|
||||
}
|
48
src/main/kotlin/cn/tursom/core/datastruct/ReversedList.kt
Normal file
48
src/main/kotlin/cn/tursom/core/datastruct/ReversedList.kt
Normal file
@ -0,0 +1,48 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
class ReversedList<E>(
|
||||
val list: List<E>
|
||||
) : List<E> by list {
|
||||
override fun get(index: Int): E = list[size - index - 1]
|
||||
|
||||
override fun indexOf(element: E): Int {
|
||||
val lastIndexOf = list.lastIndexOf(element)
|
||||
return if (lastIndexOf >= 0) size - lastIndexOf else -1
|
||||
}
|
||||
|
||||
override fun lastIndexOf(element: E): Int {
|
||||
val indexOf = list.indexOf(element)
|
||||
return if (indexOf >= 0) size - indexOf else -1
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<E> = listIterator()
|
||||
override fun listIterator(): ListIterator<E> = listIterator(0)
|
||||
|
||||
override fun listIterator(index: Int): ListIterator<E> = ReverseListIterator(list.listIterator(size - index))
|
||||
|
||||
override fun subList(fromIndex: Int, toIndex: Int): List<E> {
|
||||
return ReversedList(list.subList(size - toIndex, size - fromIndex))
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val iterator = iterator()
|
||||
return buildString {
|
||||
append('[')
|
||||
iterator.forEach {
|
||||
append(it)
|
||||
if (iterator.hasNext()) append(", ")
|
||||
}
|
||||
append(']')
|
||||
}
|
||||
}
|
||||
|
||||
private class ReverseListIterator<E>(val listIterator: ListIterator<E>) : ListIterator<E> {
|
||||
override fun hasNext(): Boolean = listIterator.hasPrevious()
|
||||
override fun next(): E = listIterator.previous()
|
||||
override fun nextIndex(): Int = listIterator.previousIndex()
|
||||
override fun hasPrevious(): Boolean = listIterator.hasNext()
|
||||
override fun previous(): E = listIterator.next()
|
||||
override fun previousIndex(): Int = listIterator.nextIndex()
|
||||
}
|
||||
}
|
||||
|
49
src/main/kotlin/cn/tursom/core/datastruct/StepList.kt
Normal file
49
src/main/kotlin/cn/tursom/core/datastruct/StepList.kt
Normal file
@ -0,0 +1,49 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
class StepList<E>(
|
||||
val list: List<E>,
|
||||
val step: Int = 1,
|
||||
) : List<E> by list {
|
||||
init {
|
||||
if (step <= 0) throw IllegalArgumentException("step is negative or zero")
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = when {
|
||||
step == 1 -> list.size
|
||||
list.isEmpty() -> 0
|
||||
else -> list.size / step + if (list.size % step == 0) 0 else 1
|
||||
}
|
||||
|
||||
override fun get(index: Int): E = list[index * step]
|
||||
|
||||
override fun indexOf(element: E): Int {
|
||||
val indexOf = list.indexOf(element)
|
||||
return if (indexOf >= 0) indexOf * step else -1
|
||||
}
|
||||
|
||||
override fun lastIndexOf(element: E): Int {
|
||||
val indexOf = list.lastIndexOf(element)
|
||||
return if (indexOf >= 0) indexOf * step else -1
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<E> = listIterator()
|
||||
override fun listIterator(): ListIterator<E> = listIterator(0)
|
||||
override fun listIterator(index: Int): ListIterator<E> =
|
||||
if (step == 1) list.listIterator(index) else AbstractListIterator(this, index)
|
||||
|
||||
override fun subList(fromIndex: Int, toIndex: Int): List<E> =
|
||||
StepList(list.subList(fromIndex * step, toIndex * step), step)
|
||||
|
||||
override fun toString(): String {
|
||||
val iterator = iterator()
|
||||
return buildString {
|
||||
append('[')
|
||||
iterator.forEach {
|
||||
append(it)
|
||||
if (iterator.hasNext()) append(", ")
|
||||
}
|
||||
append(']')
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package cn.tursom.core.encrypt
|
||||
|
||||
import cn.tursom.core.Utils
|
||||
import cn.tursom.core.datastruct.concurrent.BlockingArrayList
|
||||
import cn.tursom.core.pool.Pool
|
||||
import cn.tursom.core.randomInt
|
||||
|
||||
open class EncryptPool<T : Encrypt>(
|
||||
initSize: Int = 0,
|
||||
@ -20,5 +20,5 @@ open class EncryptPool<T : Encrypt>(
|
||||
return aesPool.add(cache)
|
||||
}
|
||||
|
||||
override fun get(): T = aesPool[randomInt(0, aesPool.size - 1)]
|
||||
override fun get(): T = aesPool[Utils.random.nextInt(0, aesPool.size - 1)]
|
||||
}
|
4
utils/delegation/build.gradle
Normal file
4
utils/delegation/build.gradle
Normal file
@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compile project(":")
|
||||
api "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface DecoratorDelegateProvider<in T, out V> :
|
||||
DelegateProvider<T, DelegatedField<T, V>>,
|
||||
DecoratorDelegatedField<T, V> {
|
||||
override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): DelegatedField<T, V> = delegatedField
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
interface DecoratorDelegatedField<in T, out V> {
|
||||
val delegatedField: DelegatedField<T, V>
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface DecoratorMutableDelegateProvider<in T, V> :
|
||||
DelegateProvider<T, MutableDelegatedField<T, V>>,
|
||||
//DecoratorProvideDelegate<T, V>,
|
||||
DecoratorMutableDelegatedField<T, V> {
|
||||
override operator fun provideDelegate(thisRef: T, prop: KProperty<*>): MutableDelegatedField<T, V> =
|
||||
mutableDelegatedField
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
interface DecoratorMutableDelegatedField<in T, V> : DecoratorDelegatedField<T, V> {
|
||||
val mutableDelegatedField: MutableDelegatedField<T, V>
|
||||
override val delegatedField: DelegatedField<T, V> get() = mutableDelegatedField
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface DelegateProvider<in T, out R> {
|
||||
operator fun provideDelegate(thisRef: T, prop: KProperty<*>): R
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* 这是用来规范kotlin委托属性的一个接口,你可以用这个接口来针对属性进行硬编码级别的动态代理
|
||||
* 比如如果你需要监控属性的变化,可以使用 FieldChangeListener.listened 来定义属性
|
||||
* 如果你还需要对这个属性进行加锁,你就可以在后方加一个 .locked 即可
|
||||
* 如果还需要用指定的锁,在后面再加一个 (lock) 就玩成了
|
||||
* 使用例:
|
||||
* class XXXImpl: XXX, FieldChangeListener by FieldChangeListenerImpl() {
|
||||
* val lock = ReentrantLock()
|
||||
* val field by listened(0).locker(lock)
|
||||
* }
|
||||
*/
|
||||
interface DelegatedField<in T, out V> {
|
||||
/**
|
||||
* 用来获取值,不会发生附加调用
|
||||
*/
|
||||
fun getValue(): V
|
||||
operator fun getValue(thisRef: T, property: KProperty<*>): V = getValue()
|
||||
|
||||
operator fun <K> get(key: DelegatedFieldAttachmentKey<K>): K? =
|
||||
if (this is DecoratorDelegatedField<*, *>) {
|
||||
delegatedField[key]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
operator fun <V> set(key: DelegatedFieldAttachmentKey<V>, value: V): Boolean =
|
||||
if (this is DecoratorDelegatedField<*, *>) {
|
||||
delegatedField.set(key, value)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
fun <V> removeAttachment(key: DelegatedFieldAttachmentKey<V>): Boolean =
|
||||
if (this is DecoratorDelegatedField<*, *>) {
|
||||
delegatedField.removeAttachment(key)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
interface DelegatedFieldAttachmentKey<V>
|
@ -0,0 +1,20 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class ExecutorMutableDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
private val executor: Executor,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) {
|
||||
executor.execute {
|
||||
mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
valueOnSet(thisRef, property, value, getValue())
|
||||
mutableDelegatedField.setValue(value)
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class FilterDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
private val filter: T.(old: V, new: V) -> Boolean,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
companion object Key : DelegatedFieldAttachmentKey<Boolean>
|
||||
|
||||
private var filterResult = false
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): K? {
|
||||
return if (key == Key) filterResult.cast() else super.get(key)
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
filterResult = thisRef.filter(getValue(), value)
|
||||
if (!filterResult) {
|
||||
return
|
||||
}
|
||||
mutableDelegatedField.setValue(thisRef, property, value)
|
||||
}
|
||||
|
||||
override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) {
|
||||
filterResult = thisRef.filter(getValue(), value)
|
||||
if (!filterResult) {
|
||||
return
|
||||
}
|
||||
mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class GetterDelegatedField<in T, out V>(
|
||||
override val delegatedField: DelegatedField<T, V>,
|
||||
private val getter: DelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V,
|
||||
) : DelegatedField<T, V> by delegatedField, DecoratorDelegatedField<T, V> {
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = delegatedField.getter(thisRef, property)
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class GetterMutableDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
private val getter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = mutableDelegatedField.getter(thisRef, property)
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
class KPropertyDelegatedField<in T, out V>(
|
||||
val delegation: KProperty0<V>,
|
||||
) : DelegatedField<T, V> {
|
||||
override fun getValue(): V = delegation.get()
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
class KPropertyMutableDelegatedField<in T, V>(
|
||||
val delegation: KMutableProperty0<V>,
|
||||
) : MutableDelegatedField<T, V> {
|
||||
override fun getValue(): V = delegation.get()
|
||||
override fun setValue(value: V) = delegation.set(value)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class LockMutableDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
private val lock: Lock = ReentrantLock(),
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
constructor(
|
||||
initValue: V,
|
||||
lock: Lock = ReentrantLock(),
|
||||
) : this(MutableDelegatedFieldValue(initValue), lock)
|
||||
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = lock.withLock {
|
||||
mutableDelegatedField.getValue(thisRef, property)
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) = lock.withLock {
|
||||
mutableDelegatedField.setValue(thisRef, property, value)
|
||||
}
|
||||
|
||||
override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) = lock.withLock {
|
||||
mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface MutableDelegatedField<in T, V> : DelegatedField<T, V> {
|
||||
/**
|
||||
* 用来设置值,不会发生 valueOnSet调用
|
||||
*/
|
||||
fun setValue(value: V)
|
||||
|
||||
/**
|
||||
* setter委托定义与其默认实现
|
||||
*/
|
||||
operator fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
valueOnSet(thisRef, property, value, getValue())
|
||||
setValue(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 当值发生设置时应当被调用
|
||||
* 流水线式调用
|
||||
*/
|
||||
fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) {}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
open class MutableDelegatedFieldValue<in T, V>(
|
||||
private var initValue: V
|
||||
) : MutableDelegatedField<T, V> {
|
||||
override fun getValue(): V = initValue
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V = initValue
|
||||
override fun setValue(value: V) {
|
||||
initValue = value
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
initValue = value
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.cast
|
||||
|
||||
class NotNullDelegatedField<in T, out V : Any>(
|
||||
override val delegatedField: DelegatedField<T, V?>,
|
||||
) : DelegatedField<T, V> by delegatedField.cast(), DecoratorDelegatedField<T, V?>
|
@ -0,0 +1,8 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.cast
|
||||
|
||||
class NotNullMutableDelegatedField<in T, V : Any>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V?>,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField.cast(), DecoratorMutableDelegatedField<T, V?>
|
||||
|
@ -0,0 +1,43 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import java.util.concurrent.locks.ReadWriteLock
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class ReadWriteLockMutableDelegatedField<in T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
private val readWriteLock: ReadWriteLock = ReentrantReadWriteLock(),
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
constructor(
|
||||
initValue: V,
|
||||
readWriteLock: ReadWriteLock = ReentrantReadWriteLock(),
|
||||
) : this(MutableDelegatedFieldValue(initValue), readWriteLock)
|
||||
|
||||
override fun getValue(thisRef: T, property: KProperty<*>): V {
|
||||
val rl = readWriteLock.readLock()
|
||||
rl.lock()
|
||||
try {
|
||||
return mutableDelegatedField.getValue(thisRef, property)
|
||||
} finally {
|
||||
rl.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
if (readWriteLock is ReentrantReadWriteLock) readWriteLock.write {
|
||||
mutableDelegatedField.setValue(thisRef, property, value)
|
||||
} else readWriteLock.writeLock().withLock {
|
||||
mutableDelegatedField.setValue(thisRef, property, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) {
|
||||
if (readWriteLock is ReentrantReadWriteLock) readWriteLock.write {
|
||||
mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
} else readWriteLock.writeLock().withLock {
|
||||
mutableDelegatedField.setValue(thisRef, property, value)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
class SetterDelegatedField<T, V>(
|
||||
override val delegatedField: DelegatedField<T, V>,
|
||||
val setter: DelegatedField<T, V>.(value: V) -> Unit,
|
||||
) : MutableDelegatedField<T, V>, DelegatedField<T, V> by delegatedField, DecoratorDelegatedField<T, V> {
|
||||
override fun setValue(value: V) = delegatedField.setter(value)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class SetterMutableDelegatedField<T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
val setter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>, value: V) -> Unit,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
mutableDelegatedField.setter(thisRef, property, value)
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.SimpThreadLocal
|
||||
|
||||
|
||||
class SimpThreadLocalMutableDelegatedField<in T, V>(
|
||||
private val threadLocal: SimpThreadLocal<V>,
|
||||
val new: () -> V
|
||||
) : MutableDelegatedField<T, V> {
|
||||
constructor(new: () -> V) : this(SimpThreadLocal(new = new), new)
|
||||
|
||||
override fun setValue(value: V) = threadLocal.set(value)
|
||||
override fun getValue(): V = threadLocal.get()
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package cn.tursom.delegation
|
||||
|
||||
class ThreadLocalMutableDelegatedField<in T, V>(
|
||||
private val threadLocal: ThreadLocal<V?> = ThreadLocal()
|
||||
) : MutableDelegatedField<T, V?> {
|
||||
override fun setValue(value: V?) = threadLocal.set(value)
|
||||
override fun getValue(): V? = threadLocal.get()
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.delegation
|
||||
|
||||
import cn.tursom.core.SimpThreadLocal
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.castOrNull
|
||||
import cn.tursom.core.receiver
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReadWriteLock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
fun getDelegate(obj: Any?, field: String): DelegatedField<*, *>? {
|
||||
obj ?: return null
|
||||
val kProperty1 = obj.javaClass.kotlin.memberProperties.firstOrNull { it.name == field }
|
||||
kProperty1?.isAccessible = true
|
||||
val delegate = kProperty1?.getDelegate(obj)
|
||||
return delegate.castOrNull()
|
||||
}
|
||||
|
||||
val <V> KProperty0<V>.getOwnerDelegated: DelegatedField<*, V>?
|
||||
get() = getDelegate(receiver, name).castOrNull()
|
||||
|
||||
val <V> KProperty0<V>.getDelegatedValue: V?
|
||||
get() {
|
||||
val delegate = getDelegate() ?: getOwnerDelegated
|
||||
return delegate?.castOrNull<DelegatedField<*, V>>()?.getValue()
|
||||
}
|
||||
|
||||
fun <V> KProperty0<V>.setDelegatedValue(value: V): Boolean {
|
||||
val delegate = getDelegate() ?: getOwnerDelegated
|
||||
delegate.castOrNull<MutableDelegatedField<*, V>>()?.setValue(value) ?: return false
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 将可空属性委托为不可空属性
|
||||
*/
|
||||
fun <T, V> T.delegated(value: V): MutableDelegatedField<T, V> = MutableDelegatedFieldValue(value)
|
||||
fun <T, V> T.delegated(@Suppress("UNUSED_PARAMETER") target: T, value: V): MutableDelegatedField<T, V> =
|
||||
MutableDelegatedFieldValue(value)
|
||||
|
||||
val <V> KProperty0<V>.delegated: DelegatedField<Any, V> get() = KPropertyDelegatedField(this)
|
||||
val <V> KMutableProperty0<V>.delegated: MutableDelegatedField<Any, V> get() = KPropertyMutableDelegatedField(this)
|
||||
val <V : Any> KProperty0<V?>.delegatedNotNull get() = delegated.notNull
|
||||
val <V : Any> KMutableProperty0<out V?>.delegatedNotNull: MutableDelegatedField<Any, V> get() = delegated.notNull
|
||||
|
||||
val <T, V : Any> DelegatedField<T, V?>.notNull: DelegatedField<T, V> get() = NotNullDelegatedField(this)
|
||||
val <T, V : Any> MutableDelegatedField<T, out V?>.notNull: MutableDelegatedField<T, V>
|
||||
get() = NotNullMutableDelegatedField(cast())
|
||||
|
||||
val <T, V> MutableDelegatedField<T, V>.locked: MutableDelegatedField<T, V> get() = LockMutableDelegatedField(this)
|
||||
fun <T, V> MutableDelegatedField<T, V>.locked(lock: Lock = ReentrantLock()): MutableDelegatedField<T, V> =
|
||||
LockMutableDelegatedField(this, lock)
|
||||
|
||||
val <T, V> MutableDelegatedField<T, V>.readWriteLocked: MutableDelegatedField<T, V>
|
||||
get() = ReadWriteLockMutableDelegatedField(this)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.readWriteLocked(readWriteLock: ReadWriteLock = ReentrantReadWriteLock()): MutableDelegatedField<T, V> =
|
||||
ReadWriteLockMutableDelegatedField(this, readWriteLock)
|
||||
|
||||
fun <T, V> T.threadLocalDelegated(): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField()
|
||||
fun <T, V> T.threadLocalDelegated(type: Class<V>): MutableDelegatedField<T, V?> = ThreadLocalMutableDelegatedField()
|
||||
fun <T, V : Any> T.threadLocalDelegated(type: KClass<V>): MutableDelegatedField<T, V?> =
|
||||
ThreadLocalMutableDelegatedField()
|
||||
|
||||
fun <T, V> T.threadLocalDelegated(new: () -> V): MutableDelegatedField<T, V> = SimpThreadLocalMutableDelegatedField(new)
|
||||
fun <T, V> T.threadLocalDelegated(simpThreadLocal: SimpThreadLocal<V>, new: () -> V): MutableDelegatedField<T, V> =
|
||||
SimpThreadLocalMutableDelegatedField(simpThreadLocal, new)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.filter(filter: T.(old: V, new: V) -> Boolean): MutableDelegatedField<T, V> =
|
||||
FilterDelegatedField(this, filter)
|
||||
|
||||
fun <T, V> DelegatedField<T, V>.setter(setter: DelegatedField<T, V>.(value: V) -> Unit): DelegatedField<T, V> =
|
||||
SetterDelegatedField(this, setter)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.setter(setter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>, value: V) -> Unit): MutableDelegatedField<T, V> =
|
||||
SetterMutableDelegatedField(this, setter)
|
||||
|
||||
fun <T, V> DelegatedField<T, V>.getter(getter: DelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V): DelegatedField<T, V> =
|
||||
GetterDelegatedField(this, getter)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.getter(getter: MutableDelegatedField<T, V>.(thisRef: T, property: KProperty<*>) -> V): MutableDelegatedField<T, V> =
|
||||
GetterMutableDelegatedField(this, getter)
|
||||
|
||||
fun <T, V> MutableDelegatedField<T, V>.withExecutor(executor: Executor): MutableDelegatedField<T, V> =
|
||||
ExecutorMutableDelegatedField(this, executor)
|
4
utils/observer/build.gradle
Normal file
4
utils/observer/build.gradle
Normal file
@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compile project(":")
|
||||
compile project(":utils:delegation")
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cn.tursom.observer
|
||||
|
||||
/**
|
||||
* 标识一个属性可以被指定的 FieldChangeListener 监听
|
||||
* 属性的实现者应该实现相应的逻辑
|
||||
*/
|
||||
@RequiresOptIn
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||
annotation class Observable
|
@ -0,0 +1,64 @@
|
||||
package cn.tursom.observer
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.delegation.DecoratorMutableDelegatedField
|
||||
import cn.tursom.delegation.DelegatedFieldAttachmentKey
|
||||
import cn.tursom.delegation.MutableDelegatedField
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@Observable
|
||||
class ObservableMutableDelegatedField<T, V>(
|
||||
override val mutableDelegatedField: MutableDelegatedField<T, V>,
|
||||
) : MutableDelegatedField<T, V> by mutableDelegatedField, DecoratorMutableDelegatedField<T, V> {
|
||||
companion object : DelegatedFieldAttachmentKey<Boolean>
|
||||
|
||||
override fun <K> get(key: DelegatedFieldAttachmentKey<K>): K? {
|
||||
return if (key == Companion) true.cast() else super.get(key)
|
||||
}
|
||||
|
||||
private val listenerList = ConcurrentLinkedDeque<T.(old: V, new: V) -> Unit>()
|
||||
|
||||
override fun setValue(thisRef: T, property: KProperty<*>, value: V) {
|
||||
val oldValue = getValue()
|
||||
listenerList.forEach {
|
||||
thisRef.it(oldValue, value)
|
||||
}
|
||||
mutableDelegatedField.setValue(thisRef, property, value)
|
||||
}
|
||||
|
||||
override fun valueOnSet(thisRef: T, property: KProperty<*>, value: V, oldValue: V) {
|
||||
listenerList.forEach {
|
||||
thisRef.it(oldValue, value)
|
||||
}
|
||||
mutableDelegatedField.valueOnSet(thisRef, property, value, oldValue)
|
||||
}
|
||||
|
||||
fun addListener(listener: T.(old: V, new: V) -> Unit): Observer<T, V> {
|
||||
var catch: (T.(old: V, new: V, e: Throwable) -> Unit)? = null
|
||||
var finally: (T.(old: V, new: V) -> Unit)? = null
|
||||
listenerList.add { old, new ->
|
||||
try {
|
||||
listener(old, new)
|
||||
} catch (e: Throwable) {
|
||||
catch?.invoke(this, old, new, e)
|
||||
} finally {
|
||||
finally?.invoke(this, old, new)
|
||||
}
|
||||
}
|
||||
return object : Observer<T, V> {
|
||||
override fun cancel() = listenerList.remove(listener)
|
||||
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Observer<T, V> {
|
||||
catch = handler
|
||||
return this
|
||||
}
|
||||
|
||||
override fun finally(handler: T.(old: V, new: V) -> Unit): Observer<T, V> {
|
||||
finally = handler
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.observer
|
||||
|
||||
interface ObservableObserver<out T, V> : Observer<T, V> {
|
||||
infix fun addListener(listener: T.(old: V, new: V) -> Unit): Observer<T, V>
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ObservableObserver<T, V>
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.observer
|
||||
|
||||
interface Observer<out T, V> {
|
||||
fun cancel(): Boolean
|
||||
infix fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): Observer<T, V>
|
||||
infix fun finally(handler: T.(old: V, new: V) -> Unit): Observer<T, V>
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.tursom.observer
|
||||
|
||||
class UnmonitoredFieldException : Exception {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||
message,
|
||||
cause,
|
||||
enableSuppression,
|
||||
writableStackTrace
|
||||
)
|
||||
}
|
120
utils/observer/src/main/kotlin/cn/tursom/observer/utils.kt
Normal file
120
utils/observer/src/main/kotlin/cn/tursom/observer/utils.kt
Normal file
@ -0,0 +1,120 @@
|
||||
package cn.tursom.observer
|
||||
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.receiver
|
||||
import cn.tursom.delegation.*
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
@Observable
|
||||
fun <V> KMutableProperty0<V>.listenable(): MutableDelegatedField<Any, V> {
|
||||
isAccessible = true
|
||||
val delegate = getDelegate()
|
||||
return if (delegate is MutableDelegatedField<*, *> && delegate[ObservableMutableDelegatedField] == true) {
|
||||
delegate.cast()
|
||||
} else {
|
||||
ObservableMutableDelegatedField(KPropertyMutableDelegatedField(cast()))
|
||||
}
|
||||
}
|
||||
|
||||
@Observable
|
||||
fun <V> listenable(initValue: V): MutableDelegatedField<Any, V> = ObservableMutableDelegatedField(
|
||||
MutableDelegatedFieldValue(initValue)
|
||||
)
|
||||
|
||||
@Observable
|
||||
fun <T, V> MutableDelegatedField<T, V>.listenable(): MutableDelegatedField<T, V> =
|
||||
ObservableMutableDelegatedField(this)
|
||||
|
||||
@OptIn(Observable::class)
|
||||
fun <V> KProperty0<V>.getListenableMutableDelegatedField(): ObservableMutableDelegatedField<Any, V>? {
|
||||
isAccessible = true
|
||||
var delegate = getDelegate() ?: getDelegate(receiver, name)
|
||||
if (delegate is DelegatedField<*, *>) {
|
||||
while (true) {
|
||||
if (delegate is ObservableMutableDelegatedField<*, *>) {
|
||||
return delegate.cast()
|
||||
}
|
||||
if (delegate is DecoratorDelegatedField<*, *>) {
|
||||
delegate = delegate.delegatedField
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (delegate is KProperty0<*>) {
|
||||
return delegate.cast<KProperty0<V>>().getListenableMutableDelegatedField()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
inline fun <T, V> T.addChangeListener(
|
||||
property: T.() -> KProperty0<V>,
|
||||
): ObservableObserver<T, V> {
|
||||
val kProperty0 = property()
|
||||
|
||||
@OptIn(Observable::class)
|
||||
val delegatedField = kProperty0
|
||||
.getListenableMutableDelegatedField()
|
||||
.cast<ObservableMutableDelegatedField<T, V>?>()
|
||||
?: throw UnmonitoredFieldException(kProperty0.toString())
|
||||
return object : ObservableObserver<T, V> {
|
||||
private val selfList = ConcurrentLinkedQueue<Observer<T, V>>()
|
||||
override fun addListener(listener: T.(old: V, new: V) -> Unit): Observer<T, V> {
|
||||
@OptIn(Observable::class)
|
||||
val listener1 = delegatedField.addListener(listener)
|
||||
selfList.add(listener1)
|
||||
return listener1
|
||||
}
|
||||
|
||||
override fun catch(handler: T.(old: V, new: V, e: Throwable) -> Unit): ObservableObserver<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): Observer<T, V> {
|
||||
selfList.forEach {
|
||||
it.finally(handler)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
infix operator fun <T, V> ObservableObserver<T, V>.invoke(listener: T.(old: V, new: V) -> Unit): Observer<T, V> =
|
||||
addListener(listener)
|
||||
|
||||
infix fun <T, V> ObservableObserver<T, V>.with(listener: T.(old: V, new: V) -> Unit): Observer<T, V> =
|
||||
addListener(listener)
|
||||
|
||||
infix fun <T, V> ObservableObserver<T, V>.and(listener: T.(old: V, new: V) -> Unit): Observer<T, V> =
|
||||
addListener(listener)
|
||||
|
||||
infix operator fun <T, V> ObservableObserver<T, V>.plus(listener: T.(old: V, new: V) -> Unit): Observer<T, V> =
|
||||
addListener(listener)
|
||||
|
||||
infix fun <V> KProperty0<V>.listen(listener: Any.(old: V, new: V) -> Unit): Observer<Any, V> {
|
||||
@OptIn(Observable::class)
|
||||
return getListenableMutableDelegatedField()
|
||||
?.addListener(listener)
|
||||
?: throw UnmonitoredFieldException(toString())
|
||||
}
|
||||
|
||||
fun <T, V> T.listen(property: KProperty0<V>, listener: T.(old: V, new: V) -> Unit): Observer<Any, V> {
|
||||
@OptIn(Observable::class)
|
||||
return property.getListenableMutableDelegatedField()
|
||||
?.addListener(listener.cast())
|
||||
?: throw UnmonitoredFieldException(toString())
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package cn.tursom.utils.asynclock
|
||||
|
||||
import cn.tursom.core.unsafe
|
||||
import cn.tursom.core.Unsafe.unsafe
|
||||
import java.io.Closeable
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
|
@ -9,9 +9,9 @@ package cn.tursom.utils.bytebuffer
|
||||
* will support
|
||||
*/
|
||||
|
||||
import cn.tursom.core.Unsafe.unsafe
|
||||
import cn.tursom.core.buffer.ByteBuffer
|
||||
import cn.tursom.core.isStatic
|
||||
import cn.tursom.core.unsafe
|
||||
|
||||
class UnsupportedException : Exception()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.web.router.impl
|
||||
|
||||
import cn.tursom.core.binarySearch
|
||||
import cn.tursom.web.router.*
|
||||
import cn.tursom.web.router.Router
|
||||
import cn.tursom.web.router.impl.colonnode.AnyColonNode
|
||||
import cn.tursom.web.router.impl.colonnode.ColonNode
|
||||
import cn.tursom.web.router.impl.colonnode.IColonNode
|
||||
@ -29,31 +29,31 @@ class ColonRouter<T> : Router<T> {
|
||||
routeNode = when {
|
||||
r.isEmpty() -> routeNode
|
||||
|
||||
r == "*" -> routeNode.wildSubRouter ?: {
|
||||
r == "*" -> routeNode.wildSubRouter ?: run {
|
||||
val node = AnyColonNode<T>(routeList, index)
|
||||
routeNode.wildSubRouter = node
|
||||
index = routeList.size - 1
|
||||
node
|
||||
}()
|
||||
}
|
||||
|
||||
r[0] == ':' -> run {
|
||||
val node = synchronized(routeNode.placeholderRouterList!!) {
|
||||
val matchLength = PlaceholderColonNode.matchLength(routeList, index)
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength } ?: {
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength } ?: run {
|
||||
routeNode.addNode(routeList, index, null)
|
||||
routeNode.placeholderRouterList!!.binarySearch { it.size - matchLength }!!
|
||||
}()
|
||||
}
|
||||
}
|
||||
index += node.size - 1
|
||||
node
|
||||
}
|
||||
|
||||
else -> synchronized(routeNode.subRouterMap) {
|
||||
routeNode.subRouterMap[r] ?: {
|
||||
routeNode.subRouterMap[r] ?: run {
|
||||
val node = ColonNode<T>(routeList, index)
|
||||
routeNode.subRouterMap[r] = node
|
||||
node
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
index++
|
||||
|
Loading…
Reference in New Issue
Block a user