Skip to content

Commit

Permalink
kotlin.time.Duration support
Browse files Browse the repository at this point in the history
  • Loading branch information
fvasco committed Feb 16, 2020
1 parent bf9509d commit ff9d472
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
15 changes: 15 additions & 0 deletions kotlinx-coroutines-core/common/src/Delay.kt
Expand Up @@ -6,6 +6,8 @@ package kotlinx.coroutines

import kotlinx.coroutines.selects.*
import kotlin.coroutines.*
import kotlin.time.Duration
import kotlin.time.ExperimentalTime

/**
* This dispatcher _feature_ is implemented by [CoroutineDispatcher] implementations that natively support
Expand Down Expand Up @@ -75,5 +77,18 @@ public suspend fun delay(timeMillis: Long) {
}
}

/**
* Delays coroutine for a given [duration] without blocking a thread and resumes it after the specified time.
* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
* immediately resumes with [CancellationException].
*
* Note that delay can be used in [select] invocation with [onTimeout][SelectBuilder.onTimeout] clause.
*
* Implementation note: how exactly time is tracked is an implementation detail of [CoroutineDispatcher] in the context.
*/
@ExperimentalTime
public suspend inline fun delay(duration: Duration) = delay(duration.toLongMilliseconds())

/** Returns [Delay] implementation of the given context */
internal val CoroutineContext.delay: Delay get() = get(ContinuationInterceptor) as? Delay ?: DefaultDelay
34 changes: 34 additions & 0 deletions kotlinx-coroutines-core/common/src/Timeout.kt
Expand Up @@ -10,6 +10,8 @@ import kotlinx.coroutines.selects.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import kotlin.jvm.*
import kotlin.time.Duration
import kotlin.time.ExperimentalTime

/**
* Runs a given suspending [block] of code inside a coroutine with a specified [timeout][timeMillis] and throws
Expand All @@ -32,6 +34,22 @@ public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineSco
}
}

/**
* Runs a given suspending [block] of code inside a coroutine with the specified [timeout] and throws
* a [TimeoutCancellationException] if the timeout was exceeded.
*
* The code that is executing inside the [block] is cancelled on timeout and the active or next invocation of
* the cancellable suspending function inside the block throws a [TimeoutCancellationException].
*
* The sibling function that does not throw an exception on timeout is [withTimeoutOrNull].
* Note that the timeout action can be specified for a [select] invocation with [onTimeout][SelectBuilder.onTimeout] clause.
*
* Implementation note: how the time is tracked exactly is an implementation detail of the context's [CoroutineDispatcher].
*/
@ExperimentalTime
public suspend inline fun <T> withTimeout(timeout: Duration, noinline block: suspend CoroutineScope.() -> T): T =
withTimeout(timeout.toLongMilliseconds(), block)

/**
* Runs a given suspending block of code inside a coroutine with a specified [timeout][timeMillis] and returns
* `null` if this timeout was exceeded.
Expand Down Expand Up @@ -65,6 +83,22 @@ public suspend fun <T> withTimeoutOrNull(timeMillis: Long, block: suspend Corout
}
}

/**
* Runs a given suspending block of code inside a coroutine with the specified [timeout] and returns
* `null` if this timeout was exceeded.
*
* The code that is executing inside the [block] is cancelled on timeout and the active or next invocation of
* cancellable suspending function inside the block throws a [TimeoutCancellationException].
*
* The sibling function that throws an exception on timeout is [withTimeout].
* Note that the timeout action can be specified for a [select] invocation with [onTimeout][SelectBuilder.onTimeout] clause.
*
* Implementation note: how the time is tracked exactly is an implementation detail of the context's [CoroutineDispatcher].
*/
@ExperimentalTime
public suspend inline fun <T> withTimeoutOrNull(timeout: Duration, noinline block: suspend CoroutineScope.() -> T): T? =
withTimeoutOrNull(timeout.toLongMilliseconds(), block)

private fun <U, T: U> setupTimeout(
coroutine: TimeoutCoroutine<U, T>,
block: suspend CoroutineScope.() -> T
Expand Down
14 changes: 14 additions & 0 deletions kotlinx-coroutines-core/common/src/selects/Select.kt
Expand Up @@ -14,6 +14,8 @@ import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import kotlin.jvm.*
import kotlin.native.concurrent.*
import kotlin.time.Duration
import kotlin.time.ExperimentalTime

/**
* Scope for [select] invocation.
Expand Down Expand Up @@ -52,6 +54,18 @@ public interface SelectBuilder<in R> {
public fun onTimeout(timeMillis: Long, block: suspend () -> R)
}


/**
* Clause that selects the given [block] after the specified [timeout] passes.
* If timeout is negative or zero, [block] is selected immediately.
*
* **Note: This is an experimental api.** It may be replaced with light-weight timer/timeout channels in the future.
*/
@ExperimentalCoroutinesApi
@ExperimentalTime
public inline fun <R> SelectBuilder<R>.onTimeout(timeout: Duration, noinline block: suspend () -> R) =
onTimeout(timeout.toLongMilliseconds(), block)

/**
* Clause for [select] expression without additional parameters that does not select any value.
*/
Expand Down

0 comments on commit ff9d472

Please sign in to comment.