Rename subscribingGet to syncFromEvent, subscribingGetAsync to asyncFromEvent; Improve docs

This commit is contained in:
Him188 2020-04-21 14:30:35 +08:00
parent 5234226788
commit d94b1d3279

View File

@ -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 <reified E : Event, R : Any> subscribingGet(
@JvmSynthetic
@SinceMirai("0.38.0")
suspend inline fun <reified E : Event, R : Any> 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 <reified E : Event, R : Any> subscribingGetOrNull(
@JvmSynthetic
@SinceMirai("0.38.0")
suspend inline fun <reified E : Event, R : Any> syncFromEventOrNull(
timeoutMillis: Long = -1,
noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
): R? {
@ -55,11 +61,11 @@ suspend inline fun <reified E : Event, R : Any> subscribingGetOrNull(
return if (timeoutMillis == -1L) {
coroutineScope {
subscribingGetOrNullImpl<E, R>(this, mapper)
syncFromEventOrNullImpl<E, R>(E::class, this, mapper)
}
} else {
withTimeoutOrNull(timeoutMillis) {
subscribingGetOrNullImpl<E, R>(this, mapper)
syncFromEventOrNullImpl<E, R>(E::class, this, mapper)
}
}
}
@ -71,16 +77,42 @@ suspend inline fun <reified E : Event, R : Any> subscribingGetOrNull(
*
* @param timeoutMillis 超时. 单位为毫秒. `-1` 为不限制
* @param coroutineContext 额外的 [CoroutineContext]
* @param mapper 过滤转换器. 返回非 null 则代表得到了需要的值. [subscribingGet] 会返回这个值
* @param mapper 过滤转换器. 返回非 `null` 则代表得到了需要的值. [syncFromEvent] 会返回这个值
*/
@SinceMirai("0.29.0")
@MiraiExperimentalAPI
inline fun <reified E : Event, R : Any> CoroutineScope.subscribingGetAsync(
@Suppress("DeferredIsResult")
@SinceMirai("0.38.0")
inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEventOrNull(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
): Deferred<R> = this.async(coroutineContext) {
subscribingGet(timeoutMillis, mapper)
): Deferred<R?> {
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 <reified E : Event, R : Any> CoroutineScope.asyncFromEvent(
timeoutMillis: Long = -1,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
): Deferred<R> {
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
return this.async(coroutineContext) {
syncFromEvent(timeoutMillis, mapper)
}
}
@ -88,24 +120,19 @@ inline fun <reified E : Event, R : Any> CoroutineScope.subscribingGetAsync(
//// internal
//////////////
@PublishedApi
internal suspend inline fun <reified E : Event, R> subscribingGetOrNullImpl(
internal suspend fun <E : Event, R> syncFromEventOrNullImpl(
eventClass: KClass<E>,
coroutineScope: CoroutineScope,
noinline mapper: suspend E.(E) -> R?
): R? {
var result: Result<R?> = Result.success(null) // stub
mapper: suspend E.(E) -> R?
): R? = suspendCoroutine { cont ->
var listener: Listener<E>? = 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()
}