Add compiler contracts
See: https://kotlinlang.org/docs/reference/whatsnew13.html#contracts
This commit is contained in:
parent
e609f061ac
commit
66f1122efb
@ -1,7 +1,6 @@
|
|||||||
import com.jfrog.bintray.gradle.BintrayExtension
|
import com.jfrog.bintray.gradle.BintrayExtension
|
||||||
import com.jfrog.bintray.gradle.tasks.BintrayUploadTask
|
import com.jfrog.bintray.gradle.tasks.BintrayUploadTask
|
||||||
import org.jetbrains.dokka.gradle.DokkaTask
|
import org.jetbrains.dokka.gradle.DokkaTask
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
@ -22,9 +21,10 @@ allprojects {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.withType<KotlinPluginWrapper> {
|
tasks.withType<KotlinCompile> {
|
||||||
tasks.withType<KotlinCompile> {
|
kotlinOptions {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
|
freeCompilerArgs = listOf("-Xuse-experimental=kotlin.contracts.ExperimentalContracts")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("and { result }"))
|
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("and { result }"))
|
||||||
infix fun <V, E> Result<V, E>.and(result: Result<V, E>): Result<V, E> {
|
infix fun <V, E> Result<V, E>.and(result: Result<V, E>): Result<V, E> {
|
||||||
return and { result }
|
return and { result }
|
||||||
@ -11,6 +14,10 @@ infix fun <V, E> Result<V, E>.and(result: Result<V, E>): Result<V, E> {
|
|||||||
* - 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)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.and(result: () -> Result<V, E>): Result<V, E> {
|
inline infix fun <V, E> Result<V, E>.and(result: () -> Result<V, E>): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(result, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> result()
|
is Ok -> result()
|
||||||
is Err -> this
|
is Err -> this
|
||||||
@ -25,6 +32,10 @@ inline infix fun <V, E> Result<V, E>.and(result: () -> Result<V, E>): Result<V,
|
|||||||
* - Rust: [Result.and_then](https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then)
|
* - Rust: [Result.and_then](https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E, U> Result<V, E>.andThen(transform: (V) -> Result<U, E>): Result<U, E> {
|
inline infix fun <V, E, U> Result<V, E>.andThen(transform: (V) -> Result<U, E>): Result<U, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> transform(value)
|
is Ok -> transform(value)
|
||||||
is Err -> this
|
is Err -> this
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the [value][Ok.value] if this [Result] is [Ok], otherwise `null`.
|
* Returns the [value][Ok.value] if this [Result] is [Ok], otherwise `null`.
|
||||||
*
|
*
|
||||||
@ -7,6 +10,11 @@ package com.github.michaelbull.result
|
|||||||
* - 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)
|
||||||
*/
|
*/
|
||||||
fun <V, E> Result<V, E>.get(): V? {
|
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 (this) {
|
return when (this) {
|
||||||
is Ok -> value
|
is Ok -> value
|
||||||
is Err -> null
|
is Err -> null
|
||||||
@ -19,6 +27,11 @@ 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)
|
||||||
*/
|
*/
|
||||||
fun <V, E> Result<V, E>.getError(): E? {
|
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 (this) {
|
return when (this) {
|
||||||
is Ok -> null
|
is Ok -> null
|
||||||
is Err -> error
|
is Err -> error
|
||||||
@ -41,6 +54,10 @@ infix fun <V, E> Result<V, E>.getOr(default: V): V {
|
|||||||
* @return The [value][Ok.value] if [Ok], otherwise [default].
|
* @return The [value][Ok.value] if [Ok], otherwise [default].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.getOr(default: () -> V): V {
|
inline infix fun <V, E> Result<V, E>.getOr(default: () -> V): V {
|
||||||
|
contract {
|
||||||
|
callsInPlace(default, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> value
|
is Ok -> value
|
||||||
is Err -> default()
|
is Err -> default()
|
||||||
@ -61,6 +78,10 @@ infix fun <V, E> Result<V, E>.getErrorOr(default: E): E {
|
|||||||
* @return The [error][Err.error] if [Err], otherwise [default].
|
* @return The [error][Err.error] if [Err], otherwise [default].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.getErrorOr(default: () -> E): E {
|
inline infix fun <V, E> Result<V, E>.getErrorOr(default: () -> E): E {
|
||||||
|
contract {
|
||||||
|
callsInPlace(default, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> default()
|
is Ok -> default()
|
||||||
is Err -> error
|
is Err -> error
|
||||||
@ -75,6 +96,10 @@ inline infix fun <V, E> Result<V, E>.getErrorOr(default: () -> E): E {
|
|||||||
* - Rust: [Result.unwrap_or_else](https://doc.rust-lang.org/src/core/result.rs.html#735-740)
|
* - Rust: [Result.unwrap_or_else](https://doc.rust-lang.org/src/core/result.rs.html#735-740)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.getOrElse(transform: (E) -> V): V {
|
inline infix fun <V, E> Result<V, E>.getOrElse(transform: (E) -> V): V {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> value
|
is Ok -> value
|
||||||
is Err -> transform(error)
|
is Err -> transform(error)
|
||||||
@ -86,6 +111,10 @@ inline infix fun <V, E> Result<V, E>.getOrElse(transform: (E) -> V): V {
|
|||||||
* [transformation][transform] of the [value][Ok.value].
|
* [transformation][transform] of the [value][Ok.value].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.getErrorOrElse(transform: (V) -> E): E {
|
inline infix fun <V, E> Result<V, E>.getErrorOrElse(transform: (V) -> E): E {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> transform(value)
|
is Ok -> transform(value)
|
||||||
is Err -> error
|
is Err -> error
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps this [Result<V, E>][Result] to [Result<U, E>][Result] by either applying the [transform]
|
* Maps this [Result<V, E>][Result] to [Result<U, E>][Result] by either applying the [transform]
|
||||||
* function to the [value][Ok.value] if this [Result] is [Ok], or returning this [Err].
|
* function to the [value][Ok.value] if this [Result] is [Ok], or returning this [Err].
|
||||||
@ -9,6 +12,10 @@ package com.github.michaelbull.result
|
|||||||
* - Rust: [Result.map](https://doc.rust-lang.org/std/result/enum.Result.html#method.map)
|
* - Rust: [Result.map](https://doc.rust-lang.org/std/result/enum.Result.html#method.map)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E, U> Result<V, E>.map(transform: (V) -> U): Result<U, E> {
|
inline infix fun <V, E, U> Result<V, E>.map(transform: (V) -> U): Result<U, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> Ok(transform(value))
|
is Ok -> Ok(transform(value))
|
||||||
is Err -> this
|
is Err -> this
|
||||||
@ -24,6 +31,10 @@ inline infix fun <V, E, U> Result<V, E>.map(transform: (V) -> U): Result<U, E> {
|
|||||||
* - Rust: [Result.map_err](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err)
|
* - Rust: [Result.map_err](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E, F> Result<V, E>.mapError(transform: (E) -> F): Result<V, F> {
|
inline infix fun <V, E, F> Result<V, E>.mapError(transform: (E) -> F): Result<V, F> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> this
|
is Ok -> this
|
||||||
is Err -> Err(transform(error))
|
is Err -> Err(transform(error))
|
||||||
@ -54,10 +65,12 @@ inline infix fun <V, E, U> Result<Iterable<V>, E>.mapAll(transform: (V) -> Resul
|
|||||||
* - Elm: [Result.Extra.mapBoth](http://package.elm-lang.org/packages/elm-community/result-extra/2.2.0/Result-Extra#mapBoth)
|
* - Elm: [Result.Extra.mapBoth](http://package.elm-lang.org/packages/elm-community/result-extra/2.2.0/Result-Extra#mapBoth)
|
||||||
* - Haskell: [Data.Either.either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:either)
|
* - Haskell: [Data.Either.either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:either)
|
||||||
*/
|
*/
|
||||||
inline fun <V, E, U> Result<V, E>.mapBoth(
|
inline fun <V, E, U> Result<V, E>.mapBoth(success: (V) -> U, failure: (E) -> U): U {
|
||||||
success: (V) -> U,
|
contract {
|
||||||
failure: (E) -> U
|
callsInPlace(success, InvocationKind.AT_MOST_ONCE)
|
||||||
): U {
|
callsInPlace(failure, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> success(value)
|
is Ok -> success(value)
|
||||||
is Err -> failure(error)
|
is Err -> failure(error)
|
||||||
@ -74,10 +87,12 @@ inline fun <V, E, U> Result<V, E>.mapBoth(
|
|||||||
* - Elm: [Result.Extra.mapBoth](http://package.elm-lang.org/packages/elm-community/result-extra/2.2.0/Result-Extra#mapBoth)
|
* - Elm: [Result.Extra.mapBoth](http://package.elm-lang.org/packages/elm-community/result-extra/2.2.0/Result-Extra#mapBoth)
|
||||||
* - Haskell: [Data.Either.either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:either)
|
* - Haskell: [Data.Either.either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:either)
|
||||||
*/
|
*/
|
||||||
inline fun <V, E, U> Result<V, E>.fold(
|
inline fun <V, E, U> Result<V, E>.fold(success: (V) -> U, failure: (E) -> U): U {
|
||||||
success: (V) -> U,
|
contract {
|
||||||
failure: (E) -> U
|
callsInPlace(success, InvocationKind.AT_MOST_ONCE)
|
||||||
): U {
|
callsInPlace(failure, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return mapBoth(success, failure)
|
return mapBoth(success, failure)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,10 +102,12 @@ inline fun <V, E, U> Result<V, E>.fold(
|
|||||||
*
|
*
|
||||||
* - Haskell: [Data.Bifunctor.Bimap](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bifunctor.html#v:bimap)
|
* - Haskell: [Data.Bifunctor.Bimap](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bifunctor.html#v:bimap)
|
||||||
*/
|
*/
|
||||||
inline fun <V, E, U, F> Result<V, E>.mapEither(
|
inline fun <V, E, U, F> Result<V, E>.mapEither(success: (V) -> U, failure: (E) -> F): Result<U, F> {
|
||||||
success: (V) -> U,
|
contract {
|
||||||
failure: (E) -> F
|
callsInPlace(success, InvocationKind.AT_MOST_ONCE)
|
||||||
): Result<U, F> {
|
callsInPlace(failure, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> Ok(success(value))
|
is Ok -> Ok(success(value))
|
||||||
is Err -> Err(failure(error))
|
is Err -> Err(failure(error))
|
||||||
@ -106,5 +123,9 @@ inline fun <V, E, U, F> Result<V, E>.mapEither(
|
|||||||
* - Scala: [Either.flatMap](http://www.scala-lang.org/api/2.12.0/scala/util/Either.html#flatMap[AA>:A,Y](f:B=>scala.util.Either[AA,Y]):scala.util.Either[AA,Y])
|
* - Scala: [Either.flatMap](http://www.scala-lang.org/api/2.12.0/scala/util/Either.html#flatMap[AA>:A,Y](f:B=>scala.util.Either[AA,Y]):scala.util.Either[AA,Y])
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E, U> Result<V, E>.flatMap(transform: (V) -> Result<U, E>): Result<U, E> {
|
inline infix fun <V, E, U> Result<V, E>.flatMap(transform: (V) -> Result<U, E>): Result<U, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return andThen(transform)
|
return andThen(transform)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes an [action] if this [Result] is [Ok].
|
* Invokes an [action] if this [Result] is [Ok].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.onSuccess(action: (V) -> Unit): Result<V, E> {
|
inline infix fun <V, E> Result<V, E>.onSuccess(action: (V) -> Unit): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(action, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
if (this is Ok) {
|
if (this is Ok) {
|
||||||
action(value)
|
action(value)
|
||||||
}
|
}
|
||||||
@ -15,6 +22,10 @@ inline infix fun <V, E> Result<V, E>.onSuccess(action: (V) -> Unit): Result<V, E
|
|||||||
* Invokes an [action] if this [Result] is [Err].
|
* Invokes an [action] if this [Result] is [Err].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.onFailure(action: (E) -> Unit): Result<V, E> {
|
inline infix fun <V, E> Result<V, E>.onFailure(action: (E) -> Unit): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(action, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
if (this is Err) {
|
if (this is Err) {
|
||||||
action(error)
|
action(error)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("or { result }"))
|
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("or { result }"))
|
||||||
infix fun <V, E> Result<V, E>.or(result: Result<V, E>): Result<V, E> {
|
infix fun <V, E> Result<V, E>.or(result: Result<V, E>): Result<V, E> {
|
||||||
return or { result }
|
return or { result }
|
||||||
@ -11,6 +14,10 @@ infix fun <V, E> Result<V, E>.or(result: Result<V, E>): Result<V, E> {
|
|||||||
* - 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)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.or(result: () -> Result<V, E>): Result<V, E> {
|
inline infix fun <V, E> Result<V, E>.or(result: () -> Result<V, E>): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(result, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> this
|
is Ok -> this
|
||||||
is Err -> result()
|
is Err -> result()
|
||||||
@ -24,6 +31,10 @@ inline infix fun <V, E> Result<V, E>.or(result: () -> Result<V, E>): Result<V, E
|
|||||||
* - 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)
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Result<V, E> {
|
inline infix fun <V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> this
|
is Ok -> this
|
||||||
is Err -> transform(error)
|
is Err -> transform(error)
|
||||||
@ -35,6 +46,10 @@ inline infix fun <V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Res
|
|||||||
* otherwise this [Ok].
|
* otherwise this [Ok].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.recover(transform: (E) -> V): Ok<V> {
|
inline infix fun <V, E> Result<V, E>.recover(transform: (E) -> V): Ok<V> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> this
|
is Ok -> this
|
||||||
is Err -> Ok(transform(error))
|
is Err -> Ok(transform(error))
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Result] is a type that represents either success ([Ok]) or failure ([Err]).
|
* [Result] is a type that represents either success ([Ok]) or failure ([Err]).
|
||||||
*
|
*
|
||||||
@ -39,6 +42,10 @@ data class Err<out E>(val error: E) : Result<Nothing, E>()
|
|||||||
* non-null, otherwise the supplied [error].
|
* non-null, otherwise the supplied [error].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> V?.toResultOr(error: () -> E): Result<V, E> {
|
inline infix fun <V, E> V?.toResultOr(error: () -> E): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(error, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
null -> Err(error())
|
null -> Err(error())
|
||||||
else -> Ok(this)
|
else -> Ok(this)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
class UnwrapException(message: String) : Exception(message)
|
class UnwrapException(message: String) : Exception(message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,6 +13,10 @@ class UnwrapException(message: String) : Exception(message)
|
|||||||
* @throws UnwrapException if the [Result] is an [Err], with a message containing the [error][Err.error].
|
* @throws UnwrapException if the [Result] is an [Err], with a message containing the [error][Err.error].
|
||||||
*/
|
*/
|
||||||
fun <V, E> Result<V, E>.unwrap(): V {
|
fun <V, E> Result<V, E>.unwrap(): V {
|
||||||
|
contract {
|
||||||
|
returns() implies (this@unwrap is Ok<V>)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> value
|
is Ok -> value
|
||||||
is Err -> throw UnwrapException("called Result.wrap on an Err value $error")
|
is Err -> throw UnwrapException("called Result.wrap on an Err value $error")
|
||||||
@ -18,6 +25,10 @@ fun <V, E> Result<V, E>.unwrap(): V {
|
|||||||
|
|
||||||
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("expect { message }"))
|
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("expect { message }"))
|
||||||
infix fun <V, E> Result<V, E>.expect(message: String): V {
|
infix fun <V, E> Result<V, E>.expect(message: String): V {
|
||||||
|
contract {
|
||||||
|
returns() implies (this@expect is Ok<V>)
|
||||||
|
}
|
||||||
|
|
||||||
return expect { message }
|
return expect { message }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +41,11 @@ infix fun <V, E> Result<V, E>.expect(message: String): V {
|
|||||||
* @throws UnwrapException if the [Result] is an [Err], with the specified [message].
|
* @throws UnwrapException if the [Result] is an [Err], with the specified [message].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.expect(message: () -> Any): V {
|
inline infix fun <V, E> Result<V, E>.expect(message: () -> Any): V {
|
||||||
|
contract {
|
||||||
|
callsInPlace(message, InvocationKind.AT_MOST_ONCE)
|
||||||
|
returns() implies (this@expect is Ok<V>)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> value
|
is Ok -> value
|
||||||
is Err -> throw UnwrapException("${message()} $error")
|
is Err -> throw UnwrapException("${message()} $error")
|
||||||
@ -44,6 +60,10 @@ inline infix fun <V, E> Result<V, E>.expect(message: () -> Any): V {
|
|||||||
* @throws UnwrapException if the [Result] is [Ok], with a message containing the [value][Ok.value].
|
* @throws UnwrapException if the [Result] is [Ok], with a message containing the [value][Ok.value].
|
||||||
*/
|
*/
|
||||||
fun <V, E> Result<V, E>.unwrapError(): E {
|
fun <V, E> Result<V, E>.unwrapError(): E {
|
||||||
|
contract {
|
||||||
|
returns() implies (this@unwrapError is Err<E>)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> throw UnwrapException("called Result.unwrapError on an Ok value $value")
|
is Ok -> throw UnwrapException("called Result.unwrapError on an Ok value $value")
|
||||||
is Err -> error
|
is Err -> error
|
||||||
@ -52,6 +72,10 @@ fun <V, E> Result<V, E>.unwrapError(): E {
|
|||||||
|
|
||||||
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("expectError { message }"))
|
@Deprecated("Use lazy-evaluating variant instead", ReplaceWith("expectError { message }"))
|
||||||
infix fun <V, E> Result<V, E>.expectError(message: String): E {
|
infix fun <V, E> Result<V, E>.expectError(message: String): E {
|
||||||
|
contract {
|
||||||
|
returns() implies (this@expectError is Err<E>)
|
||||||
|
}
|
||||||
|
|
||||||
return expectError { message }
|
return expectError { message }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +88,11 @@ infix fun <V, E> Result<V, E>.expectError(message: String): E {
|
|||||||
* @throws UnwrapException if the [Result] is [Ok], with the specified [message].
|
* @throws UnwrapException if the [Result] is [Ok], with the specified [message].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.expectError(message: () -> Any): E {
|
inline infix fun <V, E> Result<V, E>.expectError(message: () -> Any): E {
|
||||||
|
contract {
|
||||||
|
callsInPlace(message, InvocationKind.AT_MOST_ONCE)
|
||||||
|
returns() implies (this@expectError is Err<E>)
|
||||||
|
}
|
||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Ok -> throw UnwrapException("${message()} $value")
|
is Ok -> throw UnwrapException("${message()} $value")
|
||||||
is Err -> error
|
is Err -> error
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
private typealias Producer<T, E> = () -> Result<T, E>
|
private typealias Producer<T, E> = () -> Result<T, E>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,6 +16,12 @@ inline fun <T1, T2, E, V> zip(
|
|||||||
result2: Producer<T2, E>,
|
result2: Producer<T2, E>,
|
||||||
transform: (T1, T2) -> V
|
transform: (T1, T2) -> V
|
||||||
): Result<V, E> {
|
): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
|
||||||
|
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return result1().flatMap { v1 ->
|
return result1().flatMap { v1 ->
|
||||||
result2().map { v2 ->
|
result2().map { v2 ->
|
||||||
transform(v1, v2)
|
transform(v1, v2)
|
||||||
@ -32,6 +41,13 @@ inline fun <T1, T2, T3, E, V> zip(
|
|||||||
result3: Producer<T3, E>,
|
result3: Producer<T3, E>,
|
||||||
transform: (T1, T2, T3) -> V
|
transform: (T1, T2, T3) -> V
|
||||||
): Result<V, E> {
|
): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
|
||||||
|
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(result3, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return result1().flatMap { v1 ->
|
return result1().flatMap { v1 ->
|
||||||
result2().flatMap { v2 ->
|
result2().flatMap { v2 ->
|
||||||
result3().map { v3 ->
|
result3().map { v3 ->
|
||||||
@ -54,6 +70,14 @@ inline fun <T1, T2, T3, T4, E, V> zip(
|
|||||||
result4: Producer<T4, E>,
|
result4: Producer<T4, E>,
|
||||||
transform: (T1, T2, T3, T4) -> V
|
transform: (T1, T2, T3, T4) -> V
|
||||||
): Result<V, E> {
|
): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
|
||||||
|
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(result3, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(result4, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return result1().flatMap { v1 ->
|
return result1().flatMap { v1 ->
|
||||||
result2().flatMap { v2 ->
|
result2().flatMap { v2 ->
|
||||||
result3().flatMap { v3 ->
|
result3().flatMap { v3 ->
|
||||||
@ -79,6 +103,15 @@ inline fun <T1, T2, T3, T4, T5, E, V> zip(
|
|||||||
result5: Producer<T5, E>,
|
result5: Producer<T5, E>,
|
||||||
transform: (T1, T2, T3, T4, T5) -> V
|
transform: (T1, T2, T3, T4, T5) -> V
|
||||||
): Result<V, E> {
|
): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
|
||||||
|
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(result3, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(result4, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(result5, InvocationKind.AT_MOST_ONCE)
|
||||||
|
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
return result1().flatMap { v1 ->
|
return result1().flatMap { v1 ->
|
||||||
result2().flatMap { v2 ->
|
result2().flatMap { v2 ->
|
||||||
result3().flatMap { v3 ->
|
result3().flatMap { v3 ->
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package com.github.michaelbull.result
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
import kotlin.test.*
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class ResultIteratorTest {
|
class ResultIteratorTest {
|
||||||
class HasNext {
|
class HasNext {
|
||||||
@ -36,7 +40,11 @@ class ResultIteratorTest {
|
|||||||
@Test
|
@Test
|
||||||
fun throwsExceptionIfUnyieldedAndErr() {
|
fun throwsExceptionIfUnyieldedAndErr() {
|
||||||
val iterator = Err("hello").iterator()
|
val iterator = Err("hello").iterator()
|
||||||
assertFailsWith<NoSuchElementException> { iterator.next() }
|
|
||||||
|
assertFailsWith<NoSuchElementException> {
|
||||||
|
@Suppress("IMPLICIT_NOTHING_AS_TYPE_PARAMETER")
|
||||||
|
iterator.next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -17,6 +17,7 @@ class UnwrapTest {
|
|||||||
@Test
|
@Test
|
||||||
fun throwsExceptionIfErr() {
|
fun throwsExceptionIfErr() {
|
||||||
assertFailsWith<UnwrapException>("called Result.wrap on an Err value 5000") {
|
assertFailsWith<UnwrapException>("called Result.wrap on an Err value 5000") {
|
||||||
|
@Suppress("IMPLICIT_NOTHING_AS_TYPE_PARAMETER")
|
||||||
Err(5000).unwrap()
|
Err(5000).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +39,7 @@ class UnwrapTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertFailsWith<UnwrapException>("the year should be 1994") {
|
assertFailsWith<UnwrapException>("the year should be 1994") {
|
||||||
|
@Suppress("IMPLICIT_NOTHING_AS_TYPE_PARAMETER")
|
||||||
Err(1994).expect { message }
|
Err(1994).expect { message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,6 +49,7 @@ class UnwrapTest {
|
|||||||
@Test
|
@Test
|
||||||
fun throwsExceptionIfOk() {
|
fun throwsExceptionIfOk() {
|
||||||
assertFailsWith<UnwrapException>("called Result.unwrapError on an Ok value example") {
|
assertFailsWith<UnwrapException>("called Result.unwrapError on an Ok value example") {
|
||||||
|
@Suppress("IMPLICIT_NOTHING_AS_TYPE_PARAMETER")
|
||||||
Ok("example").unwrapError()
|
Ok("example").unwrapError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,6 +71,7 @@ class UnwrapTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertFailsWith<UnwrapException>("the year should be 2010") {
|
assertFailsWith<UnwrapException>("the year should be 2010") {
|
||||||
|
@Suppress("IMPLICIT_NOTHING_AS_TYPE_PARAMETER")
|
||||||
Ok(2010).expectError { message }
|
Ok(2010).expectError { message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user