Skip to content

Instantly share code, notes, and snippets.

@ayanyev
Created August 9, 2021 06:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayanyev/a318c9098febc212831c95bcc4ab269a to your computer and use it in GitHub Desktop.
Save ayanyev/a318c9098febc212831c95bcc4ab269a to your computer and use it in GitHub Desktop.
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart.LAZY
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
fun <T> suspendBlockingLazy(
dispatcher: CoroutineDispatcher = Dispatchers.Default,
initializer: () -> T
): SuspendLazy<T> = SuspendLazyBlockingImpl(dispatcher, initializer)
fun <T> CoroutineScope.suspendLazy(
context: CoroutineContext = EmptyCoroutineContext,
initializer: suspend CoroutineScope.() -> T
): SuspendLazy<T> = SuspendLazySuspendingImpl(this, context, initializer)
interface SuspendLazy<out T> {
suspend operator fun invoke(): T
}
private class SuspendLazyBlockingImpl<out T>(
private val dispatcher: CoroutineDispatcher = Dispatchers.Default,
initializer: () -> T
) : SuspendLazy<T> {
private val lazyValue = lazy(initializer)
override suspend operator fun invoke(): T = with(lazyValue) {
if (isInitialized()) value else withContext(dispatcher) { value }
}
}
private class SuspendLazySuspendingImpl<out T>(
coroutineScope: CoroutineScope,
context: CoroutineContext,
initializer: suspend CoroutineScope.() -> T
) : SuspendLazy<T> {
private val deferred = coroutineScope.async(context, start = LAZY, block = initializer)
override suspend operator fun invoke(): T = deferred.await()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment