From d94b1d3279040fdc0ce1c900c4ea5d01af5d5b7a Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 21 Apr 2020 14:30:35 +0800 Subject: [PATCH] Rename `subscribingGet` to `syncFromEvent`, `subscribingGetAsync` to `asyncFromEvent`; Improve docs --- .../kotlin/net.mamoe.mirai/event/linear.kt | 103 +++++++++++------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt index 8aa8082f1..9dd618e5e 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/linear.kt @@ -7,47 +7,53 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress("unused") + package net.mamoe.mirai.event import kotlinx.coroutines.* -import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.SinceMirai import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext +import kotlin.coroutines.suspendCoroutine +import kotlin.jvm.JvmSynthetic +import kotlin.reflect.KClass /** - * 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值. + * 挂起当前协程, 监听事件 [E], 并尝试从这个事件中**同步**一个值, 在超时时抛出 [TimeoutCancellationException] * - * 若 [mapper] 抛出了一个异常, 本函数会立即抛出这个异常. + * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制. + * @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值 * - * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制 - * @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值 + * @see asyncFromEvent 本函数的异步版本 * - * @see subscribingGetAsync 本函数的异步版本 + * @throws TimeoutCancellationException 在超时后抛出. + * @throws Throwable 当 [mapper] 抛出任何异常时, 本函数会抛出该异常 */ -@SinceMirai("0.29.0") -@MiraiExperimentalAPI -suspend inline fun subscribingGet( +@JvmSynthetic +@SinceMirai("0.38.0") +suspend inline fun syncFromEvent( timeoutMillis: Long = -1, noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常 ): R { require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" } - return subscribingGetOrNull(timeoutMillis, mapper) ?: error("timeout subscribingGet") + return syncFromEventOrNull(timeoutMillis, mapper) ?: error("timeout $timeoutMillis ms asyncFromEvent") } /** - * 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值. - * - * 若 [mapper] 抛出了一个异常, 本函数会立即抛出这个异常. + * 挂起当前协程, 监听这个事件, 并尝试从这个事件中获取一个值, 在超时时返回 `null` * * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制 - * @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值 + * @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. * - * @see subscribingGetAsync 本函数的异步版本 + * @return 超时返回 `null`, 否则返回 [mapper] 返回的第一个非 `null` 值. + * + * @see asyncFromEvent 本函数的异步版本 + * @throws Throwable 当 [mapper] 抛出任何异常时, 本函数会抛出该异常 */ -@SinceMirai("0.29.0") -@MiraiExperimentalAPI -suspend inline fun subscribingGetOrNull( +@JvmSynthetic +@SinceMirai("0.38.0") +suspend inline fun syncFromEventOrNull( timeoutMillis: Long = -1, noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常 ): R? { @@ -55,11 +61,11 @@ suspend inline fun subscribingGetOrNull( return if (timeoutMillis == -1L) { coroutineScope { - subscribingGetOrNullImpl(this, mapper) + syncFromEventOrNullImpl(E::class, this, mapper) } } else { withTimeoutOrNull(timeoutMillis) { - subscribingGetOrNullImpl(this, mapper) + syncFromEventOrNullImpl(E::class, this, mapper) } } } @@ -71,16 +77,42 @@ suspend inline fun subscribingGetOrNull( * * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制 * @param coroutineContext 额外的 [CoroutineContext] - * @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值 + * @param mapper 过滤转换器. 返回非 `null` 则代表得到了需要的值. [syncFromEvent] 会返回这个值 */ -@SinceMirai("0.29.0") -@MiraiExperimentalAPI -inline fun CoroutineScope.subscribingGetAsync( +@Suppress("DeferredIsResult") +@SinceMirai("0.38.0") +inline fun CoroutineScope.asyncFromEventOrNull( timeoutMillis: Long = -1, coroutineContext: CoroutineContext = EmptyCoroutineContext, noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常 -): Deferred = this.async(coroutineContext) { - subscribingGet(timeoutMillis, mapper) +): Deferred { + require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" } + return this.async(coroutineContext) { + syncFromEventOrNull(timeoutMillis, mapper) + } +} + + +/** + * 异步监听这个事件, 并尝试从这个事件中获取一个值. + * + * 若 [mapper] 抛出的异常将会被传递给 [Deferred.await] 抛出. + * + * @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制 + * @param coroutineContext 额外的 [CoroutineContext] + * @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [syncFromEvent] 会返回这个值 + */ +@Suppress("DeferredIsResult") +@SinceMirai("0.38.0") +inline fun CoroutineScope.asyncFromEvent( + timeoutMillis: Long = -1, + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常 +): Deferred { + require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" } + return this.async(coroutineContext) { + syncFromEvent(timeoutMillis, mapper) + } } @@ -88,24 +120,19 @@ inline fun CoroutineScope.subscribingGetAsync( //// internal ////////////// - @PublishedApi -internal suspend inline fun subscribingGetOrNullImpl( +internal suspend fun syncFromEventOrNullImpl( + eventClass: KClass, coroutineScope: CoroutineScope, - noinline mapper: suspend E.(E) -> R? -): R? { - var result: Result = Result.success(null) // stub + mapper: suspend E.(E) -> R? +): R? = suspendCoroutine { cont -> var listener: Listener? = null @Suppress("DuplicatedCode") // for better performance - listener = coroutineScope.subscribe { - result = kotlin.runCatching { + listener = coroutineScope.subscribe(eventClass) { + cont.resumeWith(kotlin.runCatching { mapper.invoke(this, it) ?: return@subscribe ListeningStatus.LISTENING - } + }) listener!!.complete() return@subscribe ListeningStatus.STOPPED - } - listener.join() - - return result.getOrThrow() } \ No newline at end of file