Facilitate mapping to arbitrary types in and/or functions

Closes #95
This commit is contained in:
Michael Bull 2024-03-02 16:36:56 +00:00
parent 6c155362dc
commit 05d50b7fec
3 changed files with 19 additions and 15 deletions

View File

@ -8,7 +8,7 @@ import kotlin.contracts.contract
* *
* - Rust: [Result.and](https://doc.rust-lang.org/std/result/enum.Result.html#method.and) * - Rust: [Result.and](https://doc.rust-lang.org/std/result/enum.Result.html#method.and)
*/ */
public infix fun <V, E> Result<V, E>.and(result: Result<V, E>): Result<V, E> { public infix fun <V, E, U> Result<V, E>.and(result: Result<U, E>): Result<U, E> {
return when (this) { return when (this) {
is Ok -> result is Ok -> result
is Err -> this is Err -> this
@ -16,7 +16,7 @@ public infix fun <V, E> Result<V, E>.and(result: Result<V, E>): Result<V, E> {
} }
@Deprecated("Use andThen instead", ReplaceWith("andThen { result() }")) @Deprecated("Use andThen instead", ReplaceWith("andThen { result() }"))
public inline infix fun <V, E> Result<V, E>.and(result: () -> Result<V, E>): Result<V, E> { public inline infix fun <V, E, U> Result<V, E>.and(result: () -> Result<U, E>): Result<U, E> {
contract { contract {
callsInPlace(result, InvocationKind.AT_MOST_ONCE) callsInPlace(result, InvocationKind.AT_MOST_ONCE)
} }

View File

@ -8,7 +8,7 @@ import kotlin.contracts.contract
* *
* - Rust: [Result.or](https://doc.rust-lang.org/std/result/enum.Result.html#method.or) * - Rust: [Result.or](https://doc.rust-lang.org/std/result/enum.Result.html#method.or)
*/ */
public infix fun <V, E> Result<V, E>.or(result: Result<V, E>): Result<V, E> { public infix fun <V, E, F> Result<V, E>.or(result: Result<V, F>): Result<V, F> {
return when (this) { return when (this) {
is Ok -> this is Ok -> this
is Err -> result is Err -> result
@ -16,7 +16,7 @@ public infix fun <V, E> Result<V, E>.or(result: Result<V, E>): Result<V, E> {
} }
@Deprecated("Use orElse instead", ReplaceWith("orElse { result() }")) @Deprecated("Use orElse instead", ReplaceWith("orElse { result() }"))
public inline infix fun <V, E> Result<V, E>.or(result: () -> Result<V, E>): Result<V, E> { public inline infix fun <V, E, F> Result<V, E>.or(result: () -> Result<V, F>): Result<V, F> {
contract { contract {
callsInPlace(result, InvocationKind.AT_MOST_ONCE) callsInPlace(result, InvocationKind.AT_MOST_ONCE)
} }
@ -30,7 +30,7 @@ public inline infix fun <V, E> Result<V, E>.or(result: () -> Result<V, E>): Resu
* *
* - Rust: [Result.or_else](https://doc.rust-lang.org/std/result/enum.Result.html#method.or_else) * - Rust: [Result.or_else](https://doc.rust-lang.org/std/result/enum.Result.html#method.or_else)
*/ */
public inline infix fun <V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Result<V, E> { public inline infix fun <V, E, F> Result<V, E>.orElse(transform: (E) -> Result<V, F>): Result<V, F> {
contract { contract {
callsInPlace(transform, InvocationKind.AT_MOST_ONCE) callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
} }

View File

@ -3,6 +3,10 @@ package com.github.michaelbull.result
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
private inline fun produce(number: Int, error: String): Result<Int, String> {
return Ok(number).and(Err(error))
}
class ZipTest { class ZipTest {
data class ZipData3(val a: String, val b: Int, val c: Boolean) data class ZipData3(val a: String, val b: Int, val c: Boolean)
@ -31,7 +35,7 @@ class ZipTest {
fun returnsErrIfOneOfTwoErr() { fun returnsErrIfOneOfTwoErr() {
val result = zip( val result = zip(
{ Ok(10) }, { Ok(10) },
{ Ok(20).and(Err("hello")) }, { produce(20, "hello") },
Int::plus Int::plus
) )
@ -46,8 +50,8 @@ class ZipTest {
@Test @Test
fun returnsFirstErrIfBothErr() { fun returnsFirstErrIfBothErr() {
val result = zip( val result = zip(
{ Ok(10).and(Err("foo")) }, { produce(10, "foo") },
{ Ok(20).and(Err("bar")) }, { produce(20, "bar") },
Int::plus Int::plus
) )
@ -225,11 +229,11 @@ class ZipTest {
@Test @Test
fun returnsAllErrsIfAllErr() { fun returnsAllErrsIfAllErr() {
val result = zipOrAccumulate( val result = zipOrAccumulate(
{ Ok(10).and(Err("error one")) }, { produce(10, "error one") },
{ Ok(20).and(Err("error two")) }, { produce(20, "error two") },
{ Ok(30).and(Err("error three")) }, { produce(30, "error three") },
{ Ok(40).and(Err("error four")) }, { produce(40, "error four") },
{ Ok(50).and(Err("error five")) }, { produce(50, "error five") },
) { a, b, c, d, e -> ) { a, b, c, d, e ->
a + b + c + d + e a + b + c + d + e
} }
@ -252,7 +256,7 @@ class ZipTest {
fun returnsOneErrsIfOneOfErr() { fun returnsOneErrsIfOneOfErr() {
val result = zipOrAccumulate( val result = zipOrAccumulate(
{ Ok(10) }, { Ok(10) },
{ Ok(20).and(Err("only error")) }, { produce(20, "only error") },
{ Ok(30) }, { Ok(30) },
{ Ok(40) }, { Ok(40) },
{ Ok(50) }, { Ok(50) },
@ -263,7 +267,7 @@ class ZipTest {
result as Err result as Err
assertEquals( assertEquals(
expected = listOf("only error",), expected = listOf("only error"),
actual = result.error, actual = result.error,
) )
} }