Deprecate "ResultBinding" in favour of "BindingScope"

This matches the Kotlin stdlib naming convention used for
sequences[1] and coroutines[2].

[1] https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/-sequence-scope/
[2] https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/
This commit is contained in:
Michael Bull 2024-03-10 23:32:17 +00:00
parent 09818a7d50
commit dd5c96f983
3 changed files with 30 additions and 18 deletions

View File

@ -20,16 +20,16 @@ import kotlin.coroutines.CoroutineContext
* This new scope is [cancelled][CoroutineScope.cancel] once a failing bind is encountered, eagerly cancelling all * This new scope is [cancelled][CoroutineScope.cancel] once a failing bind is encountered, eagerly cancelling all
* child [jobs][Job]. * child [jobs][Job].
*/ */
public suspend inline fun <V, E> binding(crossinline block: suspend SuspendableResultBinding<E>.() -> V): Result<V, E> { public suspend inline fun <V, E> binding(crossinline block: suspend CoroutineBindingScope<E>.() -> V): Result<V, E> {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
} }
lateinit var receiver: SuspendableResultBindingImpl<E> lateinit var receiver: CoroutineBindingScopeImpl<E>
return try { return try {
coroutineScope { coroutineScope {
receiver = SuspendableResultBindingImpl(this) receiver = CoroutineBindingScopeImpl(this)
with(receiver) { with(receiver) {
Ok(block()) Ok(block())
@ -42,14 +42,20 @@ public suspend inline fun <V, E> binding(crossinline block: suspend SuspendableR
internal object BindCancellationException : CancellationException(null as String?) internal object BindCancellationException : CancellationException(null as String?)
public interface SuspendableResultBinding<E> : CoroutineScope { @Deprecated(
message = "Use CoroutineBindingScope instead",
replaceWith = ReplaceWith("CoroutineBindingScope<E>")
)
public typealias SuspendableResultBinding<E> = CoroutineBindingScope<E>
public interface CoroutineBindingScope<E> : CoroutineScope {
public suspend fun <V> Result<V, E>.bind(): V public suspend fun <V> Result<V, E>.bind(): V
} }
@PublishedApi @PublishedApi
internal class SuspendableResultBindingImpl<E>( internal class CoroutineBindingScopeImpl<E>(
delegate: CoroutineScope, delegate: CoroutineScope,
) : SuspendableResultBinding<E>, CoroutineScope by delegate { ) : CoroutineBindingScope<E>, CoroutineScope by delegate {
private val mutex = Mutex() private val mutex = Mutex()
var result: Result<Nothing, E>? = null var result: Result<Nothing, E>? = null

View File

@ -4,10 +4,10 @@ import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
/** /**
* Calls the specified function [block] with [ResultBinding] as its receiver and returns its [Result]. * Calls the specified function [block] with [BindingScope] as its receiver and returns its [Result].
* *
* When inside a [binding] block, the [bind][ResultBinding.bind] function is accessible on any [Result]. Calling the * When inside a [binding] block, the [bind][BindingScope.bind] function is accessible on any [Result]. Calling the
* [bind][ResultBinding.bind] function will attempt to unwrap the [Result] and locally return its [value][Ok.value]. If * [bind][BindingScope.bind] function will attempt to unwrap the [Result] and locally return its [value][Ok.value]. If
* the [Result] is an [Err], the binding block will terminate with that bind and return that failed-to-bind [Err]. * the [Result] is an [Err], the binding block will terminate with that bind and return that failed-to-bind [Err].
* *
* Example: * Example:
@ -22,12 +22,12 @@ import kotlin.contracts.contract
* } * }
* ``` * ```
*/ */
public inline fun <V, E> binding(crossinline block: ResultBinding<E>.() -> V): Result<V, E> { public inline fun <V, E> binding(crossinline block: BindingScope<E>.() -> V): Result<V, E> {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
} }
return with(ResultBindingImpl<E>()) { return with(BindingScopeImpl<E>()) {
try { try {
Ok(block()) Ok(block())
} catch (ex: BindException) { } catch (ex: BindException) {
@ -38,12 +38,18 @@ public inline fun <V, E> binding(crossinline block: ResultBinding<E>.() -> V): R
internal expect object BindException : Exception internal expect object BindException : Exception
public interface ResultBinding<E> { @Deprecated(
message = "Use BindingScope instead",
replaceWith = ReplaceWith("BindingScope<E>")
)
public typealias ResultBinding<E> = BindingScope<E>
public interface BindingScope<E> {
public fun <V> Result<V, E>.bind(): V public fun <V> Result<V, E>.bind(): V
} }
@PublishedApi @PublishedApi
internal class ResultBindingImpl<E> : ResultBinding<E> { internal class BindingScopeImpl<E> : BindingScope<E> {
var result: Result<Nothing, E>? = null var result: Result<Nothing, E>? = null
@ -51,7 +57,7 @@ internal class ResultBindingImpl<E> : ResultBinding<E> {
return when (this) { return when (this) {
is Ok -> value is Ok -> value
is Err -> { is Err -> {
this@ResultBindingImpl.result = this this@BindingScopeImpl.result = this
throw BindException throw BindException
} }
} }

View File

@ -1,10 +1,10 @@
package com.github.michaelbull.result.coroutines package com.github.michaelbull.result.coroutines
import com.github.michaelbull.result.BindException import com.github.michaelbull.result.BindException
import com.github.michaelbull.result.BindingScope
import com.github.michaelbull.result.BindingScopeImpl
import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result import com.github.michaelbull.result.Result
import com.github.michaelbull.result.ResultBinding
import com.github.michaelbull.result.ResultBindingImpl
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
@ -17,12 +17,12 @@ import kotlin.contracts.contract
"Please import the kotlin-result-coroutines library to continue using this feature.", "Please import the kotlin-result-coroutines library to continue using this feature.",
level = DeprecationLevel.WARNING level = DeprecationLevel.WARNING
) )
public suspend inline fun <V, E> binding(crossinline block: suspend ResultBinding<E>.() -> V): Result<V, E> { public suspend inline fun <V, E> binding(crossinline block: suspend BindingScope<E>.() -> V): Result<V, E> {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
} }
return with(ResultBindingImpl<E>()) { return with(BindingScopeImpl<E>()) {
try { try {
Ok(block()) Ok(block())
} catch (ex: BindException) { } catch (ex: BindException) {