diff --git a/src/main/kotlin/com/github/michaelbull/result/Map.kt b/src/main/kotlin/com/github/michaelbull/result/Map.kt index 4c2a206..75d3927 100644 --- a/src/main/kotlin/com/github/michaelbull/result/Map.kt +++ b/src/main/kotlin/com/github/michaelbull/result/Map.kt @@ -41,6 +41,43 @@ inline infix fun Result.mapError(transform: (E) -> F): Result Result.mapOr(default: U, transform: (V) -> U): U { + contract { + callsInPlace(transform, InvocationKind.AT_MOST_ONCE) + } + + return when (this) { + is Ok -> transform(value) + is Err -> default + } +} + +/** + * Maps this [Result][Result] to [U] by applying either the [transform] function if this + * [Result] is [Ok], or the [default] function if this [Result] is an [Err]. Both of these + * functions must return the same type (`U`). + * + * - Rust: [Result.map_or_else](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_or_else) + */ +inline fun Result.mapOrElse(default: (E) -> U, transform: (V) -> U): U { + contract { + callsInPlace(default, InvocationKind.AT_MOST_ONCE) + callsInPlace(transform, InvocationKind.AT_MOST_ONCE) + } + + return when (this) { + is Ok -> transform(value) + is Err -> default(error) + } +} + /** * Returns a [Result, E>][Result] containing the results of applying the given [transform] * function to each element in the original collection, returning early with the first [Err] if a diff --git a/src/test/kotlin/com/github/michaelbull/result/MapTest.kt b/src/test/kotlin/com/github/michaelbull/result/MapTest.kt index 6bae634..e4cdd6e 100644 --- a/src/test/kotlin/com/github/michaelbull/result/MapTest.kt +++ b/src/test/kotlin/com/github/michaelbull/result/MapTest.kt @@ -66,6 +66,52 @@ class MapTest { } } + class MapOr { + @Test + fun returnsTransformedValueIfOk() { + val value = Ok("foo").mapOr(42, String::length) + + assertEquals( + expected = 3, + actual = value + ) + } + + @Test + fun returnsDefaultValueIfErr() { + val value = Err("bar").mapOr(42, String::length) + + assertEquals( + expected = 42, + actual = value + ) + } + } + + class MapOrElse { + private val k = 21 + + @Test + fun returnsTransformedValueIfOk() { + val value = Ok("foo").mapOrElse({ k * 2 }, String::length) + + assertEquals( + expected = 3, + actual = value + ) + } + + @Test + fun returnsDefaultValueIfErr() { + val value = Err("bar").mapOrElse({ k * 2 }, String::length) + + assertEquals( + expected = 42, + actual = value + ) + } + } + class MapBoth { @Test @Suppress("UNREACHABLE_CODE")