Created
September 21, 2022 07:19
-
-
Save nomisRev/e1b5cf39ca4f2931365a1a30f9e0c565 to your computer and use it in GitHub Desktop.
Timed Value monad.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface Timed<A> { | |
public fun result(): A | |
public fun startMs(): Long | |
public fun endMs(): Long | |
} | |
// Add strategies as needed | |
public enum class TimedStrategy { EarliestStartAndLatestEnd; } | |
public interface TimedDSL { | |
public fun <A> Timed<A>.bind(): A | |
} | |
public inline fun <A> timed( | |
strategy: TimedStrategy = TimedStrategy.EarliestStartAndLatestEnd, | |
block: TimedDSL.() -> A | |
): Timed<A> { | |
val dsl = TimedDSLImpl(strategy, System.currentTimeMillis()) | |
val result = block(dsl) | |
return TimedValue( | |
result, | |
dsl.start.get(), | |
dsl.end.get() ?: System.currentTimeMillis() | |
) | |
} | |
// We need to make it internal, and publish the API to be able to inline timed so you can also mix it with other _suspend code_. | |
@PublishedApi | |
internal data class TimedValue<A>(private val _result: A, private val _startMs: Long, private val _endMs: Long) : Timed<A> { | |
override fun result(): A = _result | |
override fun startMs(): Long = _startMs | |
override fun endMs(): Long = _endMs | |
} | |
// We need to make it internal, and publish the API to be able to inline timed so you can also mix it with other _suspend code_. | |
@PublishedApi | |
internal class TimedDSLImpl(private val strategy: TimedStrategy, start: Long) : TimedDSL { | |
// Protect with atomatics, since `inline fun timed` can contain suspend / parallel code. | |
val start = AtomicRef(start) | |
val end: AtomicRef<Long?> = AtomicRef(null) | |
override fun <A> Timed<A>.bind(): A { | |
when(strategy) { | |
TimedStrategy.EarliestStartAndLatestEnd -> { | |
start.update { min(it, startMs()) } | |
end.update { it?.let { current -> max(current, endMs()) } ?: endMs() } | |
} | |
} | |
return result() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Code example for a question on KotlinLang Slack. https://kotlinlang.slack.com/archives/C5UPMM0A0/p1663742658572539