Skip to content

Commit

Permalink
Add andThen{Recover,RecoverIf,RecoverUnless}
Browse files Browse the repository at this point in the history
  • Loading branch information
Jhabkin authored and michaelbull committed Feb 6, 2024
1 parent 05a1e91 commit d4414b1
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,64 @@ public inline infix fun <V, E, U> Result<V, E>.andThen(transform: (V) -> Result<
is Err -> this
}
}

/**
* Returns the [transformation][transform] of the [error][Err.error] if this [Result] is [Err],
* otherwise this [Result].
*/
public inline fun <V, E> Result<V, E>.andThenRecover(transform: (E) -> Result<V, E>): Result<V, E> {
contract {
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return when (this) {
is Ok -> this
is Err -> transform(error)
}
}

/**
* Returns the [transformation][transform] of the [error][Err.error] if this [Result] is [Err] and
* satisfies the given [predicate], otherwise this [Result].
*/
public inline fun <V, E> Result<V, E>.andThenRecoverIf(
predicate: (E) -> Boolean,
transform: (E) -> Result<V, E>
): Result<V, E> {
contract {
callsInPlace(predicate, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return when (this) {
is Ok -> this
is Err -> if (predicate(error)) {
transform(error)
} else {
this
}
}
}

/**
* Returns the [transformation][transform] of the [error][Err.error] if this [Result] is [Err]
* and _does not_ satisfy the given [predicate], otherwise this [Result].
*/
public inline fun <V, E> Result<V, E>.andThenRecoverUnless(
predicate: (E) -> Boolean,
transform: (E) -> Result<V, E>
): Result<V, E> {
contract {
callsInPlace(predicate, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return when (this) {
is Ok -> this
is Err -> if (!predicate(error)) {
transform(error)
} else {
this
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,122 @@ class AndTest {
)
}
}

class AndThenRecover {
@Test
fun returnsValueIfOk() {
assertEquals(
expected = 5,
actual = Ok(5).andThenRecover { Ok(7) }.get()
)
}

@Test
fun returnsTransformValueIfErr() {
assertEquals(
expected = 20,
actual = Err(AndError).andThenRecover { Ok(20) }.get()
)
}
}

class AndThenRecoverIf {
@Test
fun returnsValueIfOk() {
fun predicate(int: Int): Boolean {
return int == 4000
}

assertEquals(
expected = Ok(3000),
actual = Ok(3000).andThenRecoverIf(::predicate) { Ok(2000) }
)
}

@Test
fun returnsTransformedErrorAsOkIfErrAndPredicateMatch() {
fun predicate(int: Int): Boolean {
return int == 4000
}

assertEquals(
expected = Ok(2000),
actual = Err(4000).andThenRecoverIf(::predicate) { Ok(2000) }
)
}

@Test
fun returnsTransformedErrorAsErrorIfErrAndPredicateMatch() {
fun predicate(int: Int): Boolean {
return int == 4000
}

assertEquals(
expected = Err(2000),
actual = Err(4000).andThenRecoverIf(::predicate) { Err(2000) }
)
}

@Test
fun doesNotReturnTransformationResultIfErrAndPredicateDoesNotMatch() {
fun predicate(int: Int): Boolean {
return int == 3000
}

assertEquals(
expected = Err(4000),
actual = Err(4000).andThenRecoverIf(::predicate) { Ok(2000) }
)
}
}

class AndThenRecoverUnless {
@Test
fun returnsValueIfOk() {
fun predicate(int: Int): Boolean {
return int == 4000
}

assertEquals(
expected = Ok(3000),
actual = Ok(3000).andThenRecoverUnless(::predicate) { Ok(2000) }
)
}

@Test
fun returnsTransformedErrorAsOkIfErrAndPredicateDoesNotMatch() {
fun predicate(int: Int): Boolean {
return int == 3000
}

assertEquals(
expected = Ok(2000),
actual = Err(4000).andThenRecoverUnless(::predicate) { Ok(2000) }
)
}

@Test
fun returnsTransformedErrorAsErrorIfErrAndPredicateDoesNotMatch() {
fun predicate(int: Int): Boolean {
return int == 3000
}

assertEquals(
expected = Err(2000),
actual = Err(4000).andThenRecoverUnless(::predicate) { Err(2000) }
)
}

@Test
fun doesNotReturnTransformationResultIfErrAndPredicateMatches() {
fun predicate(int: Int): Boolean {
return int == 4000
}

assertEquals(
expected = Err(4000),
actual = Err(4000).andThenRecoverUnless(::predicate) { Ok(2000) }
)
}
}
}

0 comments on commit d4414b1

Please sign in to comment.