diff options
author | therealbush <therealbush@users.noreply.github.com> | 2022-04-01 00:01:19 -1000 |
---|---|---|
committer | therealbush <therealbush@users.noreply.github.com> | 2022-04-01 00:01:19 -1000 |
commit | 48b57ceb1680af6c426b6f928a403c958b1d3279 (patch) | |
tree | b2a8282e118bf8197638d8c053185ca5ae09ad50 /src/main/kotlin/me/bush/illnamethislater/CancelledState.kt | |
parent | 90c216a853af28b5298a52d9436f9f81995f3caf (diff) | |
download | eventbus-kotlin-48b57ceb1680af6c426b6f928a403c958b1d3279.tar.gz eventbus-kotlin-48b57ceb1680af6c426b6f928a403c958b1d3279.tar.bz2 eventbus-kotlin-48b57ceb1680af6c426b6f928a403c958b1d3279.zip |
more stuffs
Diffstat (limited to 'src/main/kotlin/me/bush/illnamethislater/CancelledState.kt')
-rw-r--r-- | src/main/kotlin/me/bush/illnamethislater/CancelledState.kt | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/main/kotlin/me/bush/illnamethislater/CancelledState.kt b/src/main/kotlin/me/bush/illnamethislater/CancelledState.kt new file mode 100644 index 0000000..ed2263a --- /dev/null +++ b/src/main/kotlin/me/bush/illnamethislater/CancelledState.kt @@ -0,0 +1,54 @@ +package me.bush.illnamethislater + +import sun.misc.Unsafe +import kotlin.reflect.KClass +import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.full.declaredMembers +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.jvm.javaField +import kotlin.reflect.typeOf + +/** + * A simple SAM interface for determining if an event (or any class) is cancellable. + * + * @author bush + * @since 1.0.0 + */ +internal fun interface CancelledState { + + /** + * Returns whether [event] is cancelled or not. [event] should only ever be of the type + * that was passed to [CancelledState.of], or this will cause an error. + */ + fun isCancelled(event: Any): Boolean + + // Maybe move this to eventbus or util? todo + // Make CancelledState a class? todo + companion object { + private val UNSAFE = Unsafe::class.declaredMembers.single { it.name == "theUnsafe" }.handleCall() as Unsafe + private val CANCELLED_NAMES = arrayOf("canceled", "cancelled") + private val NOT_CANCELLABLE = CancelledState { false } + private val OFFSETS = hashMapOf<KClass<*>, Long>() + + /** + * Creates a [CancelledState] object for events of class [type]. + */ + // TODO: 3/31/2022 static/singleton fields + fun of(type: KClass<*>, config: Config): CancelledState { + // Default impl for our event class + if (type.isSubclassOf(Event::class)) return CancelledState { (it as Event).cancelled } + // If compat is disabled + if (!config.thirdPartyCompatibility) return NOT_CANCELLABLE + // Find a field named "cancelled" or "canceled" + type.allMembers.filter { it.name in CANCELLED_NAMES && it.returnType == typeOf<Boolean>() } + .filterIsInstance<KMutableProperty1<*, *>>().toList().let { + if (it.isEmpty()) return NOT_CANCELLABLE + if (it.size != 1) config.logger.warn("Multiple possible cancel fields found for event type $type") + OFFSETS[type] = UNSAFE.objectFieldOffset(it[0].javaField) + // This is not using reflection, and it is the same speed as direct access. + // If you are familiar with C, this is essentially the same idea as pointers. + return CancelledState { event -> UNSAFE.getBoolean(event, OFFSETS[type]!!) } + } + } + } +} |