From 1246f0f644eb1fca30f92c601941937506ca2beb Mon Sep 17 00:00:00 2001 From: bush-did-711 <39170869+bush-did-711@users.noreply.github.com> Date: Tue, 29 Mar 2022 23:37:52 -1000 Subject: added some experimental stuff, not done still messy shitcode --- README.md | 2 +- .../kotlin/me/bush/illnamethislater/EventBus.kt | 23 +++++---- .../me/bush/illnamethislater/ListenerGroup.kt | 26 ++++++++++ .../me/bush/illnamethislater/ListenerList.kt | 43 ----------------- src/main/kotlin/me/bush/illnamethislater/Util.kt | 56 ++++++++++++++++------ src/test/kotlin/Main.kt | 52 +++++++++++--------- 6 files changed, 114 insertions(+), 88 deletions(-) create mode 100644 src/main/kotlin/me/bush/illnamethislater/ListenerGroup.kt delete mode 100644 src/main/kotlin/me/bush/illnamethislater/ListenerList.kt diff --git a/README.md b/README.md index 3b80c54..389cbfd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ #EVENTBUS-KOTLIN this isnt done yet i just wanted to get the gh up -still not done dfsdofdfomsdkflmsdf +still not done dfsdofdfomsdkflmsdfvdfdfsdfsdf diff --git a/src/main/kotlin/me/bush/illnamethislater/EventBus.kt b/src/main/kotlin/me/bush/illnamethislater/EventBus.kt index 4de6bc5..66424f7 100644 --- a/src/main/kotlin/me/bush/illnamethislater/EventBus.kt +++ b/src/main/kotlin/me/bush/illnamethislater/EventBus.kt @@ -11,7 +11,7 @@ import kotlin.reflect.KClass * @since 1.0.0 */ class EventBus(private val logger: Logger = LogManager.getLogger()) { - private val listeners = hashMapOf, ListenerList>() + private val listeners = hashMapOf, ListenerGroup>() private val subscribers = mutableSetOf() /** @@ -37,8 +37,8 @@ class EventBus(private val logger: Logger = LogManager.getLogger()) { * The */ fun register(listener: Listener, subscriber: Any = Any()): Any { - listeners.getOrPut(listener.type) { ListenerList() } - .add(listener.also { it.subscriber = subscriber }) + listener.subscriber = subscriber + listeners.computeIfAbsent(listener.type, ::ListenerGroup).addListener(listener) subscribers += subscriber return subscriber } @@ -58,7 +58,13 @@ class EventBus(private val logger: Logger = LogManager.getLogger()) { * Posts an event. */ // doc - infix fun post(event: Any) = listeners[event::class]?.post(event) + infix fun post(event: Any) = listeners[event::class]?.let { group -> + group.sequential.forEach { + if (!group.cancelState.isCancelled(event) || it.receiveCancelled) { + it.listener(event) + } + } + } /** * Logs the subscriber count, total listener count, and listener count @@ -71,15 +77,16 @@ class EventBus(private val logger: Logger = LogManager.getLogger()) { * OtherEvent: 3, 1 * String: 1, 1 */ + // do lol + fun debugInfo() { logger.info(StringBuilder().apply { append("\nSubscribers: ${subscribers.size}") - val sequential = listeners.values.sumOf { it.sequential.size } - val parallel = listeners.values.sumOf { it.parallel.size } - append("\nListeners: $sequential sequential, $parallel parallel") + append("\nListeners: ${listeners.values.sumOf { it.sequential.size }} sequential, ${listeners.values.sumOf { it.parallel.size }} parallel") listeners.entries.sortedByDescending { it.value.sequential.size + it.value.parallel.size }.forEach { - append("\n${it.key.simpleName}: ${it.value.sequential.size}, ${it.value.parallel.size}") + append("${it.key.simpleName}: ${it.value.sequential.size}, ${it.value.parallel.size}") } }.toString()) } } + diff --git a/src/main/kotlin/me/bush/illnamethislater/ListenerGroup.kt b/src/main/kotlin/me/bush/illnamethislater/ListenerGroup.kt new file mode 100644 index 0000000..d8003a4 --- /dev/null +++ b/src/main/kotlin/me/bush/illnamethislater/ListenerGroup.kt @@ -0,0 +1,26 @@ +package me.bush.illnamethislater + +import java.util.concurrent.CopyOnWriteArrayList +import kotlin.reflect.KClass + +/** + * @author bush + * @since 1.0.0 + */ +internal class ListenerGroup(type: KClass<*>) { + val parallel = CopyOnWriteArrayList() + val sequential = CopyOnWriteArrayList() + val cancelState = cancelStateOf(type) + + val isEmpty get() = parallel.isEmpty() && sequential.isEmpty() + + fun addListener(listener: Listener) { + if (listener.parallel) parallel += listener + else sequential += listener + } + + fun removeFrom(subscriber: Any) { + parallel.removeIf(Listener::subscriber::equals) + sequential.removeIf(Listener::subscriber::equals) + } +} diff --git a/src/main/kotlin/me/bush/illnamethislater/ListenerList.kt b/src/main/kotlin/me/bush/illnamethislater/ListenerList.kt deleted file mode 100644 index 9bebb87..0000000 --- a/src/main/kotlin/me/bush/illnamethislater/ListenerList.kt +++ /dev/null @@ -1,43 +0,0 @@ -package me.bush.illnamethislater - -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import java.util.concurrent.CopyOnWriteArrayList - -/** - * @author bush - * @since 1.0.0 - */ -internal class ListenerList { - val sequential = CopyOnWriteArrayList() - val parallel = CopyOnWriteArrayList() - - val isEmpty get() = sequential.isEmpty() && parallel.isEmpty() - - fun add(listener: Listener) { - if (listener.parallel) parallel += listener - else sequential += listener - } - - fun removeFrom(subscriber: Any) { - sequential.removeIf(subscriber::equals) - parallel.removeIf(subscriber::equals) - } - - fun post(event: Any): Boolean { - // todo thsi - parallel.run { - if (isNotEmpty()) runBlocking { - forEach { // credit kami blue for the idea - launch { it.listener(event) } - } - } - } - sequential.run { - if (isNotEmpty()) forEach { - it.listener(event) - } - } - return false - } -} diff --git a/src/main/kotlin/me/bush/illnamethislater/Util.kt b/src/main/kotlin/me/bush/illnamethislater/Util.kt index 5285718..ab486ab 100644 --- a/src/main/kotlin/me/bush/illnamethislater/Util.kt +++ b/src/main/kotlin/me/bush/illnamethislater/Util.kt @@ -1,36 +1,34 @@ package me.bush.illnamethislater +import sun.misc.Unsafe import java.lang.reflect.Modifier -import java.util.concurrent.atomic.AtomicInteger -import java.util.concurrent.atomic.AtomicLong -import kotlin.reflect.KCallable -import kotlin.reflect.KClass -import kotlin.reflect.KProperty +import kotlin.reflect.* import kotlin.reflect.full.allSuperclasses import kotlin.reflect.full.declaredMembers -import kotlin.reflect.full.starProjectedType +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaGetter // author bush // since 1.0.0 -/* +/** * Using [KClass.members] only returns public members, and * using [KClass.declaredMembers] doesn't return inherited * members. This returns all members, private and inherited. */ internal val KClass.allMembers - get() = declaredMembers + allSuperclasses.flatMap { it.declaredMembers } + get() = (declaredMembers + allSuperclasses.flatMap { it.declaredMembers }).asSequence() -/* +/** * Checks if a [KCallable] is static on the jvm, and handles invocation accordingly. * * I am not aware of a better alternative that works with `object` classes. */ internal fun KCallable.handleCall(receiver: Any) = if (static) call() else call(receiver) -/* +/** * Checks if the calling [KCallable] is a static java field. * * Because kotlin likes to be funny, properties belonging to @@ -45,11 +43,41 @@ internal val KCallable<*>.static get() = if (this !is KProperty<*> || javaGetter != null) false else javaField?.let { Modifier.isStatic(it.modifiers) } ?: false -/* +/** * Finds all listeners in a class. (properties and methods) */ @Suppress("UNCHECKED_CAST") // This cannot fail internal inline val KClass<*>.listeners - get() = allMembers.asSequence().filter { - it.returnType == Listener::class.starProjectedType - } as Sequence> + get() = allMembers.filter { it.returnType == typeOf() } as Sequence> + +internal fun interface CancelledState { + fun isCancelled(event: Any): Boolean +} + +private val unsafe = Unsafe::class.java.getDeclaredField("theUnsafe").let { + it.isAccessible = true + it.get(null) as Unsafe +} + +private val offsetMap = hashMapOf, Long>() + +private val possibleNames = arrayOf("canceled", "cancelled") + +private val NOT_CANCELLABLE = CancelledState { false } + +internal fun cancelStateOf(type: KClass<*>) = when { + type.isSubclassOf(Event::class) -> CancelledState { (it as Event).cancelled } + else -> findCancelField(type)?.let { + offsetMap[type] = unsafe.objectFieldOffset(it.javaField) + CancelledState { event -> unsafe.getBoolean(event, offsetMap[type]!!) } + } ?: NOT_CANCELLABLE +} + +private fun findCancelField(type: KClass<*>) = type.allMembers + .filter { it.name in possibleNames && it.returnType == typeOf() } + .filterIsInstance>().toList().let { + if (it.isEmpty()) null else { + if (it.size != 1) TODO() // warn + it[0] + } + } diff --git a/src/test/kotlin/Main.kt b/src/test/kotlin/Main.kt index dc6e194..7000c2d 100644 --- a/src/test/kotlin/Main.kt +++ b/src/test/kotlin/Main.kt @@ -10,12 +10,12 @@ import org.apache.logging.log4j.core.config.Configurator fun main() { Configurator.setRootLevel(Level.INFO) -// EventBus().run { -// -// subscribe(Subscriber()) -// -// post("String") -// + EventBus().run { + + subscribe(Subscriber()) + + post(External()) + // val key = register(listener { // println(it) // }) @@ -27,32 +27,40 @@ fun main() { // unsubscribe(topLevelListenerKey) // // debugInfo() -// } + } - val not = NotDuck() - not.wtf() - doDuck(not) - //doDuck(Any()) } -fun topLevelListener() = listener { println("topLevelListener(): $it") } +fun topLevelListener() = listener { + println("topLevelListener(): $it") +} class Subscriber { - val listener0 get() = listener(500, true, false) { - println(it.uppercase()) + val listener0 = listener(500) { + println("listener 0") + println(it.canceled) + it.canceled = true } -} -fun doDuck(any: Any) { -} + val listener1 = listener(250, receiveCancelled = true) { + println("listener 1") + println(it.canceled) + it.canceled = false + } + + val listener2 get() = listener { + println("listener 2") + println(it.canceled) + it.canceled = true + } -class NotDuck { - fun wtf() { - println("wtf") + fun listener3() = listener(-250) { + println("listener 3") + println(it.canceled) } } -interface Duck { - fun wtf() +class External { + var canceled = false } -- cgit