aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--README.md2
-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
-rw-r--r--src/test/kotlin/Main.kt52
6 files changed, 114 insertions, 88 deletions
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<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]
+ }
+ }
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<Int> {
// println(it)
// })
@@ -27,32 +27,40 @@ fun main() {
// unsubscribe(topLevelListenerKey)
//
// debugInfo()
-// }
+ }
- val not = NotDuck()
- not.wtf()
- doDuck(not)
- //doDuck(Any())
}
-fun topLevelListener() = listener<Int> { println("topLevelListener(): $it") }
+fun topLevelListener() = listener<Int> {
+ println("topLevelListener(): $it")
+}
class Subscriber {
- val listener0 get() = listener<String>(500, true, false) {
- println(it.uppercase())
+ val listener0 = listener<External>(500) {
+ println("listener 0")
+ println(it.canceled)
+ it.canceled = true
}
-}
-fun doDuck(any: Any) {
-}
+ val listener1 = listener<External>(250, receiveCancelled = true) {
+ println("listener 1")
+ println(it.canceled)
+ it.canceled = false
+ }
+
+ val listener2 get() = listener<External> {
+ println("listener 2")
+ println(it.canceled)
+ it.canceled = true
+ }
-class NotDuck {
- fun wtf() {
- println("wtf")
+ fun listener3() = listener<External>(-250) {
+ println("listener 3")
+ println(it.canceled)
}
}
-interface Duck {
- fun wtf()
+class External {
+ var canceled = false
}