Skip to content

Commit ad8946e

Browse files
committed
Better destroyable listeners
1 parent 3396537 commit ad8946e

File tree

3 files changed

+24
-17
lines changed

3 files changed

+24
-17
lines changed

common/src/main/kotlin/com/lambda/event/listener/SafeListener.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,10 @@ class SafeListener(
104104
*
105105
* Usage:
106106
* ```kotlin
107-
* listenerOnce<MyEvent> { event ->
108-
* player.sendMessage("Event received: $event")
109-
* }
110-
*
111-
* listenerOnce<MyEvent>(priority = 1) { event ->
112-
* player.sendMessage("Event received before the previous listener: $event")
107+
* private val event by listenOnce<MyEvent> { event ->
108+
* player.sendMessage("Event received only once: $event")
109+
* // event is stored in the value
110+
* // event is unsubscribed after execution
113111
* }
114112
* ```
115113
*
@@ -122,18 +120,23 @@ class SafeListener(
122120
inline fun <reified T : Event> Any.listenOnce(
123121
priority: Int = 0,
124122
alwaysListen: Boolean = false,
125-
noinline function: SafeContext.(T) -> Unit,
126-
): SafeListener {
123+
noinline function: SafeContext.(T) -> Unit = {},
124+
): Lazy<T?> {
125+
// This doesn't leak memory because the owner still has a reference to the listener
126+
var value: T? = null
127+
127128
val destroyable by selfReference<SafeListener> {
128129
SafeListener(priority, this@listenOnce, alwaysListen) { event ->
129130
function(event as T)
131+
value = event
132+
130133
EventFlow.syncListeners.unsubscribe(self)
131134
}
132135
}
133136

134137
EventFlow.syncListeners.subscribe<T>(destroyable)
135138

136-
return destroyable
139+
return lazy { value }
137140
}
138141

139142
/**

common/src/main/kotlin/com/lambda/event/listener/UnsafeListener.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,11 @@ class UnsafeListener(
9191
*
9292
* Usage:
9393
* ```kotlin
94-
* unsafeListenOnce<MyEvent> { event ->
94+
* private val event by unsafeListenOnce<MyEvent> { event ->
9595
* println("Unsafe event received only once: $event")
96-
* }
97-
*
98-
* unsafeListenOnce<MyEvent>(priority = 1) { event ->
99-
* println("Unsafe event received only once before the previous listener: $event")
96+
* // no safe access to player or world
97+
* // event is stored in the value
98+
* // event is unsubscribed after execution
10099
* }
101100
* ```
102101
*
@@ -112,17 +111,22 @@ class UnsafeListener(
112111
priority: Int = 0,
113112
alwaysListen: Boolean = false,
114113
noinline function: (T) -> Unit,
115-
): UnsafeListener {
114+
): Lazy<T?> {
115+
// This doesn't leak memory because the owner still has a reference to the listener
116+
var value: T? = null
117+
116118
val destroyable by selfReference<UnsafeListener> {
117119
UnsafeListener(priority, this@unsafeListenOnce, alwaysListen) { event ->
118120
function(event as T)
121+
value = event
122+
119123
EventFlow.syncListeners.unsubscribe(self)
120124
}
121125
}
122126

123127
EventFlow.syncListeners.subscribe<T>(destroyable)
124128

125-
return destroyable
129+
return lazy { value }
126130
}
127131

128132
/**

common/src/main/kotlin/com/lambda/util/SelfReference.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.lambda.util
22

33
class SelfReference<T>(initializer: SelfReference<T>.() -> T) {
4-
val self: T by lazy { inner ?: throw IllegalStateException("Do not use `self` until initialized.") }
4+
val self: T by lazy { inner }
55

66
private val inner = initializer()
77
operator fun getValue(thisRef: Any?, property: Any?) = self

0 commit comments

Comments
 (0)