Skip to content

Instantly share code, notes, and snippets.

@Groostav
Last active August 7, 2018 02:10
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 Groostav/ac3f4090199153b2db94fa2016b20852 to your computer and use it in GitHub Desktop.
Save Groostav/ac3f4090199153b2db94fa2016b20852 to your computer and use it in GitHub Desktop.
orAsync implementation attempt
private enum class Side { Left, Right }
infix fun Deferred<Boolean>.orAsync(right: Deferred<Boolean>) = async<Boolean> {
val left: Deferred<Boolean> = this@orAsync
//note: I didnt take a context object.
//`infix` might not be possible...
// 'short circuit'
if(left.isCompleted && left.getCompleted()) return@async true
if(right.isCompleted && right.getCompleted()) return@async true
//we have no choice but to wait for one of them to return
val (side, sideTrue) = select<Pair<Side, Boolean>> {
left.onAwait { Side.Left to it }
right.onAwait { Side.Right to it }
}
return@async when {
//if that value was true, we're done
sideTrue -> true
//else wait for the other to complete
side == Side.Left -> right.await()
side == Side.Right -> left.await()
else -> TODO()
}
}
@Test fun `when using async or and one of the two operands returns true`() = runBlocking {
val left = CompletableDeferred<Boolean>()
val right = CompletableDeferred<Boolean>()
val result = left orAsync right
delay(10)
left.complete(true)
assertTrue(result.await())
}
infix fun Deferred<Boolean>.orAsyncLazy(right: suspend () -> Boolean) = async<Boolean> {
val left: Deferred<Boolean> = this@orAsyncLazy
// 'short circuit'
if(left.isCompleted && left.getCompleted()) return@async true
val leftValue = left.await()
return@async leftValue || right()
}
@Test fun `when using orAsyncLazy should not start until left completes`() = runBlocking {
val left = CompletableDeferred<Boolean>()
val right: suspend () -> Nothing = { TODO("blam: you evaluated right eagerly!") }
val result = left orAsyncLazy { right() }
delay(10)
left.complete(true)
assertTrue(result.await())
}
@Test fun `when using orAsyncLazy should evaluate right when left is false`() = runBlocking {
val left = CompletableDeferred<Boolean>()
var evaluatedRight: Boolean = false
val right: suspend () -> Boolean = right@ { evaluatedRight = true; return@right true }
val result = left orAsyncLazy { right() }
delay(10)
left.complete(false)
assertTrue(result.await())
assertTrue(evaluatedRight)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment