From 15fc1ff0139306b640a38f00922748b34e2e1d5b Mon Sep 17 00:00:00 2001 From: Michael Bull Date: Fri, 8 Mar 2024 20:36:21 +0000 Subject: [PATCH] Add mapCatching See: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/map-catching.html --- .../com/github/michaelbull/result/Map.kt | 23 ++++++++++++ .../com/github/michaelbull/result/MapTest.kt | 35 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Map.kt b/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Map.kt index ade93e5..67690e3 100644 --- a/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Map.kt +++ b/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Map.kt @@ -22,6 +22,29 @@ public inline infix fun Result.map(transform: (V) -> U): Result< } } +/** + * Maps this [Result][Result] to [Result][Result] by either applying + * the [transform] function to the [value][Ok.value] if this [Result] is [Ok], or returning this + * [Err]. + * + * This function catches any [Throwable] exception thrown by [transform] function and encapsulates + * it as a failure. + * + * - Elm: [Result.map](http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map) + * - Haskell: [Data.Bifunctor.first](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bifunctor.html#v:first) + * - Rust: [Result.map](https://doc.rust-lang.org/std/result/enum.Result.html#method.map) + */ +public inline infix fun Result.mapCatching(transform: (V) -> U): Result { + contract { + callsInPlace(transform, InvocationKind.AT_MOST_ONCE) + } + + return when (this) { + is Ok -> runCatching { transform(value) } + is Err -> this + } +} + /** * Maps this [Result, E>][Result] to [Result][Result]. * diff --git a/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/MapTest.kt b/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/MapTest.kt index 3afd768..31cabd1 100644 --- a/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/MapTest.kt +++ b/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/MapTest.kt @@ -41,6 +41,41 @@ class MapTest { } } + class MapCatching { + + private object MapException : Throwable() + + @Test + fun returnsTransformedValueIfOk() { + val value: Result = Ok(10) + + assertEquals( + expected = Ok(30), + actual = value.mapCatching { it + 20 }, + ) + } + + @Test + fun returnsErrIfTransformationThrows() { + val value: Result = Ok(10) + + assertEquals( + expected = Err(MapException), + actual = value.mapCatching { throw MapException }, + ) + } + + @Test + fun returnsErrorIfErr() { + val value: Result = Err(MapException) + + assertEquals( + expected = Err(MapException), + actual = value.mapCatching { "hello $it" }, + ) + } + } + class Flatten { @Test