Convert Result to an inline value class
This commit is contained in:
parent
eecd1b7d99
commit
981fbe2812
@ -10,11 +10,6 @@ import kotlin.contracts.contract
|
|||||||
* - Rust: [Result.ok](https://doc.rust-lang.org/std/result/enum.Result.html#method.ok)
|
* - Rust: [Result.ok](https://doc.rust-lang.org/std/result/enum.Result.html#method.ok)
|
||||||
*/
|
*/
|
||||||
public fun <V, E> Result<V, E>.get(): V? {
|
public fun <V, E> Result<V, E>.get(): V? {
|
||||||
contract {
|
|
||||||
returnsNotNull() implies (this@get is Ok<V>)
|
|
||||||
returns(null) implies (this@get is Err<E>)
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isOk -> value
|
isOk -> value
|
||||||
else -> null
|
else -> null
|
||||||
@ -27,11 +22,6 @@ public fun <V, E> Result<V, E>.get(): V? {
|
|||||||
* - Rust: [Result.err](https://doc.rust-lang.org/std/result/enum.Result.html#method.err)
|
* - Rust: [Result.err](https://doc.rust-lang.org/std/result/enum.Result.html#method.err)
|
||||||
*/
|
*/
|
||||||
public fun <V, E> Result<V, E>.getError(): E? {
|
public fun <V, E> Result<V, E>.getError(): E? {
|
||||||
contract {
|
|
||||||
returns(null) implies (this@getError is Ok<V>)
|
|
||||||
returnsNotNull() implies (this@getError is Err<E>)
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isErr -> error
|
isErr -> error
|
||||||
else -> null
|
else -> null
|
||||||
@ -111,10 +101,6 @@ public inline infix fun <V, E> Result<V, E>.getErrorOrElse(transform: (V) -> E):
|
|||||||
* This is functionally equivalent to [`getOrElse { throw it }`][getOrElse].
|
* This is functionally equivalent to [`getOrElse { throw it }`][getOrElse].
|
||||||
*/
|
*/
|
||||||
public fun <V, E : Throwable> Result<V, E>.getOrThrow(): V {
|
public fun <V, E : Throwable> Result<V, E>.getOrThrow(): V {
|
||||||
contract {
|
|
||||||
returns() implies (this@getOrThrow is Ok<V>)
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isOk -> value
|
isOk -> value
|
||||||
else -> throw error
|
else -> throw error
|
||||||
@ -127,7 +113,6 @@ public fun <V, E : Throwable> Result<V, E>.getOrThrow(): V {
|
|||||||
*/
|
*/
|
||||||
public inline infix fun <V, E> Result<V, E>.getOrThrow(transform: (E) -> Throwable): V {
|
public inline infix fun <V, E> Result<V, E>.getOrThrow(transform: (E) -> Throwable): V {
|
||||||
contract {
|
contract {
|
||||||
returns() implies (this@getOrThrow is Ok<V>)
|
|
||||||
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Result] that [is ok][Result.isOk] and contains a [value][Result.value].
|
* Returns a [Result] that [is ok][Result.isOk] and contains a [value][Result.value].
|
||||||
*/
|
*/
|
||||||
@Suppress("FunctionName", "DEPRECATION")
|
@Suppress("FunctionName")
|
||||||
public fun <V> Ok(value: V): Result<V, Nothing> {
|
public fun <V> Ok(value: V): Result<V, Nothing> {
|
||||||
return Ok(value, null)
|
return Result(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Result] that [is an error][Result.isErr] and contains an [error][Result.error].
|
* Returns a [Result] that [is an error][Result.isErr] and contains an [error][Result.error].
|
||||||
*/
|
*/
|
||||||
@Suppress("FunctionName", "DEPRECATION")
|
@Suppress("FunctionName")
|
||||||
public fun <E> Err(error: E): Result<Nothing, E> {
|
public fun <E> Err(error: E): Result<Nothing, E> {
|
||||||
return Err(error, null)
|
return Result(Failure(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,94 +39,66 @@ public inline fun <V, E, F> Result<V, E>.asErr(): Result<Nothing, F> {
|
|||||||
/**
|
/**
|
||||||
* [Result] is a type that represents either success ([Ok]) or failure ([Err]).
|
* [Result] is a type that represents either success ([Ok]) or failure ([Err]).
|
||||||
*
|
*
|
||||||
|
* A [Result] that [is ok][Result.isOk] will have a [value][Result.value] of type [V], whereas a
|
||||||
|
* [Result] that [is an error][Result.isErr] will have an [error][Result.error] of type [E].
|
||||||
|
*
|
||||||
* - Elm: [Result](http://package.elm-lang.org/packages/elm-lang/core/5.1.1/Result)
|
* - Elm: [Result](http://package.elm-lang.org/packages/elm-lang/core/5.1.1/Result)
|
||||||
* - Haskell: [Data.Either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html)
|
* - Haskell: [Data.Either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html)
|
||||||
* - Rust: [Result](https://doc.rust-lang.org/std/result/enum.Result.html)
|
* - Rust: [Result](https://doc.rust-lang.org/std/result/enum.Result.html)
|
||||||
*/
|
*/
|
||||||
public sealed class Result<out V, out E> {
|
@JvmInline
|
||||||
|
public value class Result<out V, out E> internal constructor(
|
||||||
|
private val inlineValue: Any?,
|
||||||
|
) {
|
||||||
|
|
||||||
public abstract val value: V
|
@Suppress("UNCHECKED_CAST")
|
||||||
public abstract val error: E
|
public val value: V
|
||||||
|
get() = inlineValue as V
|
||||||
|
|
||||||
public abstract val isOk: Boolean
|
@Suppress("UNCHECKED_CAST")
|
||||||
public abstract val isErr: Boolean
|
public val error: E
|
||||||
|
get() = (inlineValue as Failure<E>).error
|
||||||
|
|
||||||
public abstract operator fun component1(): V?
|
public val isOk: Boolean
|
||||||
public abstract operator fun component2(): E?
|
get() = inlineValue !is Failure<*>
|
||||||
|
|
||||||
|
public val isErr: Boolean
|
||||||
|
get() = inlineValue is Failure<*>
|
||||||
|
|
||||||
|
public operator fun component1(): V? {
|
||||||
|
return when {
|
||||||
|
isOk -> value
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public operator fun component2(): E? {
|
||||||
* Represents a successful [Result], containing a [value].
|
return when {
|
||||||
*/
|
isErr -> error
|
||||||
@Deprecated(
|
else -> null
|
||||||
message = "Using Ok as a return type is deprecated.",
|
}
|
||||||
replaceWith = ReplaceWith("Result<V, Nothing>"),
|
|
||||||
)
|
|
||||||
public class Ok<out V> internal constructor(
|
|
||||||
override val value: V,
|
|
||||||
@Suppress("UNUSED_PARAMETER") placeholder: Any?,
|
|
||||||
) : Result<V, Nothing>() {
|
|
||||||
|
|
||||||
override val error: Nothing
|
|
||||||
get() {
|
|
||||||
throw NoSuchElementException()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isOk: Boolean = true
|
override fun toString(): String {
|
||||||
override val isErr: Boolean = false
|
return when {
|
||||||
|
isOk -> "Ok($value)"
|
||||||
override fun component1(): V = value
|
else -> "Err($error)"
|
||||||
override fun component2(): Nothing? = null
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Failure<out E>(
|
||||||
|
val error: E,
|
||||||
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
return other is Failure<*> && error == other.error
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as Ok<*>
|
|
||||||
|
|
||||||
if (value != other.value) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int = value.hashCode()
|
override fun hashCode(): Int {
|
||||||
override fun toString(): String = "Ok($value)"
|
return error.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun toString(): String {
|
||||||
* Represents a failed [Result], containing an [error].
|
return "Failure($error)"
|
||||||
*/
|
|
||||||
@Deprecated(
|
|
||||||
message = "Using Err as a return type is deprecated.",
|
|
||||||
replaceWith = ReplaceWith("Result<Nothing, E>"),
|
|
||||||
)
|
|
||||||
public class Err<out E> internal constructor(
|
|
||||||
override val error: E,
|
|
||||||
@Suppress("UNUSED_PARAMETER") placeholder: Any?,
|
|
||||||
) : Result<Nothing, E>() {
|
|
||||||
|
|
||||||
override val value: Nothing
|
|
||||||
get() {
|
|
||||||
throw NoSuchElementException()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isOk: Boolean = false
|
|
||||||
override val isErr: Boolean = true
|
|
||||||
|
|
||||||
override fun component1(): Nothing? = null
|
|
||||||
override fun component2(): E = error
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other == null || this::class != other::class) return false
|
|
||||||
|
|
||||||
other as Err<*>
|
|
||||||
|
|
||||||
if (error != other.error) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int = error.hashCode()
|
|
||||||
override fun toString(): String = "Err($error)"
|
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,6 @@ public class UnwrapException(message: String) : Exception(message)
|
|||||||
* @throws UnwrapException if this result [is an error][Result.isErr].
|
* @throws UnwrapException if this result [is an error][Result.isErr].
|
||||||
*/
|
*/
|
||||||
public fun <V, E> Result<V, E>.unwrap(): V {
|
public fun <V, E> Result<V, E>.unwrap(): V {
|
||||||
contract {
|
|
||||||
returns() implies (this@unwrap is Ok<V>)
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isOk -> value
|
isOk -> value
|
||||||
else -> throw UnwrapException("called Result.unwrap on an Err value $error")
|
else -> throw UnwrapException("called Result.unwrap on an Err value $error")
|
||||||
@ -38,7 +34,6 @@ public fun <V, E> Result<V, E>.unwrap(): V {
|
|||||||
public inline infix fun <V, E> Result<V, E>.expect(message: () -> Any): V {
|
public inline infix fun <V, E> Result<V, E>.expect(message: () -> Any): V {
|
||||||
contract {
|
contract {
|
||||||
callsInPlace(message, InvocationKind.AT_MOST_ONCE)
|
callsInPlace(message, InvocationKind.AT_MOST_ONCE)
|
||||||
returns() implies (this@expect is Ok<V>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
@ -56,10 +51,6 @@ public inline infix fun <V, E> Result<V, E>.expect(message: () -> Any): V {
|
|||||||
* @throws UnwrapException if this result [is ok][Result.isOk].
|
* @throws UnwrapException if this result [is ok][Result.isOk].
|
||||||
*/
|
*/
|
||||||
public fun <V, E> Result<V, E>.unwrapError(): E {
|
public fun <V, E> Result<V, E>.unwrapError(): E {
|
||||||
contract {
|
|
||||||
returns() implies (this@unwrapError is Err<E>)
|
|
||||||
}
|
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isErr -> error
|
isErr -> error
|
||||||
else -> throw UnwrapException("called Result.unwrapError on an Ok value $value")
|
else -> throw UnwrapException("called Result.unwrapError on an Ok value $value")
|
||||||
@ -80,7 +71,6 @@ public fun <V, E> Result<V, E>.unwrapError(): E {
|
|||||||
public inline infix fun <V, E> Result<V, E>.expectError(message: () -> Any): E {
|
public inline infix fun <V, E> Result<V, E>.expectError(message: () -> Any): E {
|
||||||
contract {
|
contract {
|
||||||
callsInPlace(message, InvocationKind.AT_MOST_ONCE)
|
callsInPlace(message, InvocationKind.AT_MOST_ONCE)
|
||||||
returns() implies (this@expectError is Err<E>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
|
Loading…
Reference in New Issue
Block a user