Skip to content

Instantly share code, notes, and snippets.

@erickok
Created December 24, 2020 12:15
Show Gist options
  • Save erickok/3a6f5b8a997e1c78e2f03d1f67ef8486 to your computer and use it in GitHub Desktop.
Save erickok/3a6f5b8a997e1c78e2f03d1f67ef8486 to your computer and use it in GitHub Desktop.
Lazy deferred properties in Kotlin
/*
* Copyright 2019 Louis Cognault Ayeva Derman. Use of this source code is governed by the Apache 2.0 license.
*/
package nl.nl2312.core.ext
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
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 = CoroutineStart.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