aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/me/bush/illnamethislater
diff options
context:
space:
mode:
authorbush-did-711 <39170869+bush-did-711@users.noreply.github.com>2022-03-29 23:37:52 -1000
committerbush-did-711 <39170869+bush-did-711@users.noreply.github.com>2022-03-29 23:37:52 -1000
commit1246f0f644eb1fca30f92c601941937506ca2beb (patch)
tree12d32f83193e854cb3fd67dd7e5ec9e43dd30d3e /src/main/kotlin/me/bush/illnamethislater
parente14ab8f09fd5cf2a8917d43c7edc9a402283b0a3 (diff)
downloadeventbus-kotlin-1246f0f644eb1fca30f92c601941937506ca2beb.tar.gz
eventbus-kotlin-1246f0f644eb1fca30f92c601941937506ca2beb.tar.bz2
eventbus-kotlin-1246f0f644eb1fca30f92c601941937506ca2beb.zip
added some experimental stuff, not done still messy shitcode
Diffstat (limited to 'src/main/kotlin/me/bush/illnamethislater')
-rw-r--r--src/main/kotlin/me/bush/illnamethislater/EventBus.kt23
-rw-r--r--src/main/kotlin/me/bush/illnamethislater/ListenerGroup.kt26
-rw-r--r--src/main/kotlin/me/bush/illnamethislater/ListenerList.kt43
-rw-r--r--src/main/kotlin/me/bush/illnamethislater/Util.kt56
4 files changed, 83 insertions, 65 deletions
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<KClass<*>, ListenerList>()
+ private val listeners = hashMapOf<KClass<*>, ListenerGroup>()
private val subscribers = mutableSetOf<Any>()
/**
@@ -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<Listener>()
+ val sequential = CopyOnWriteArrayList<Listener>()
+ 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<Listener>()
- val parallel = CopyOnWriteArrayList<Listener>()
-
- 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 <T : Any> KClass<T>.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 <R> KCallable<R>.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<KCallable<Listener>>
+ get() = allMembers.filter { it.returnType == typeOf<Listener>() } as Sequence<KCallable<Listener>>
+
+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<KClass<*>, 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<Boolean>() }
+ .filterIsInstance<KMutableProperty1<*, *>>().toList().let {
+ if (it.isEmpty()) null else {
+ if (it.size != 1) TODO() // warn
+ it[0]
+ }
+ }