From 34ee44b532c5b92b258e471a3a30b58f857aa21d Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 8 Sep 2016 13:08:45 +0200 Subject: [PATCH] Minor: move ErrorOr into the core module and tweak its API a bit. Add a Path div operator. --- .../kotlin/com/r3corda/client/mock/ErrorOr.kt | 40 ----------------- .../com/r3corda/client/mock/Generator.kt | 23 ++++++---- .../src/main/kotlin/com/r3corda/core/Utils.kt | 43 ++++++++++++++++++- 3 files changed, 56 insertions(+), 50 deletions(-) delete mode 100644 client/src/main/kotlin/com/r3corda/client/mock/ErrorOr.kt diff --git a/client/src/main/kotlin/com/r3corda/client/mock/ErrorOr.kt b/client/src/main/kotlin/com/r3corda/client/mock/ErrorOr.kt deleted file mode 100644 index 1dee4278be..0000000000 --- a/client/src/main/kotlin/com/r3corda/client/mock/ErrorOr.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.r3corda.client.mock - -class ErrorOr private constructor( - val value: A?, - val error: Exception? -) { - constructor(value: A): this(value, null) - constructor(error: Exception): this(null, error) - - fun match(onValue: (A) -> T, onError: (Exception) -> T): T { - if (value != null) { - return onValue(value) - } else { - return onError(error!!) - } - } - - fun getValueOrThrow(): A { - if (value != null) { - return value - } else { - throw error!! - } - } - - // Functor - fun map(function: (A) -> B): ErrorOr { - return ErrorOr(value?.let(function), error) - } - - // Applicative - fun combine(other: ErrorOr, function: (A, B) -> C): ErrorOr { - return ErrorOr(value?.let { a -> other.value?.let { b -> function(a, b) } }, error ?: other.error) - } - - // Monad - fun bind(function: (A) -> ErrorOr): ErrorOr { - return value?.let(function) ?: ErrorOr(error!!) - } -} diff --git a/client/src/main/kotlin/com/r3corda/client/mock/Generator.kt b/client/src/main/kotlin/com/r3corda/client/mock/Generator.kt index 6991dec7a5..1d998c442d 100644 --- a/client/src/main/kotlin/com/r3corda/client/mock/Generator.kt +++ b/client/src/main/kotlin/com/r3corda/client/mock/Generator.kt @@ -1,5 +1,7 @@ package com.r3corda.client.mock +import com.r3corda.client.mock.Generator.Companion.choice +import com.r3corda.core.ErrorOr import java.util.* /** @@ -54,7 +56,7 @@ class Generator(val generate: (Random) -> ErrorOr) { companion object { fun pure(value: A) = Generator { ErrorOr(value) } fun impure(valueClosure: () -> A) = Generator { ErrorOr(valueClosure()) } - fun fail(error: Exception) = Generator { ErrorOr(error) } + fun fail(error: Exception) = Generator { ErrorOr.of(error) } // Alternative fun choice(generators: List>) = intRange(0, generators.size - 1).bind { generators[it] } @@ -85,10 +87,11 @@ class Generator(val generate: (Random) -> ErrorOr) { val result = mutableListOf() for (generator in generators) { val element = generator.generate(it) - if (element.value != null) { - result.add(element.value) + val v = element.value + if (v != null) { + result.add(v) } else { - return@Generator ErrorOr(element.error!!) + return@Generator ErrorOr.of(element.error!!) } } ErrorOr(result) @@ -99,11 +102,12 @@ class Generator(val generate: (Random) -> ErrorOr) { fun Generator.Companion.oneOf(list: List) = intRange(0, list.size - 1).map { list[it] } fun Generator.generateOrFail(random: Random, numberOfTries: Int = 1): A { - var error: Exception? = null + var error: Throwable? = null for (i in 0 .. numberOfTries - 1) { val result = generate(random) - if (result.value != null) { - return result.value + val v = result.value + if (v != null) { + return v } else { error = result.error } @@ -146,8 +150,9 @@ fun Generator.Companion.replicatePoisson(meanSize: Double, generator: Genera ErrorOr(Unit) } } - if (errorOr.error != null) { - return@Generator ErrorOr(errorOr.error) + val e = errorOr.error + if (e != null) { + return@Generator ErrorOr.of(e) } } ErrorOr(result) diff --git a/core/src/main/kotlin/com/r3corda/core/Utils.kt b/core/src/main/kotlin/com/r3corda/core/Utils.kt index 33eecc541c..67a3eb4ed8 100644 --- a/core/src/main/kotlin/com/r3corda/core/Utils.kt +++ b/core/src/main/kotlin/com/r3corda/core/Utils.kt @@ -218,4 +218,45 @@ fun extractZipFile(zipPath: Path, toPath: Path) { // TODO: Generic csv printing utility for clases. -val Throwable.rootCause: Throwable get() = Throwables.getRootCause(this) \ No newline at end of file +val Throwable.rootCause: Throwable get() = Throwables.getRootCause(this) + +/** Allows you to write code like: Paths.get("someDir") / "subdir" / "filename" but using the Paths API to avoid platform separator problems. */ +operator fun Path.div(other: String): Path = resolve(other) + +/** Representation of an operation that may have thrown an error. */ +data class ErrorOr private constructor(val value: A?, val error: Throwable?) { + constructor(value: A) : this(value, null) + + companion object { + /** Runs the given lambda and wraps the result. */ + inline fun catch(body: () -> T): ErrorOr = try { ErrorOr(body()) } catch (t: Throwable) { ErrorOr.of(t) } + fun of(t: Throwable) = ErrorOr(null, t) + } + + fun match(onValue: (A) -> T, onError: (Throwable) -> T): T { + if (value != null) { + return onValue(value) + } else { + return onError(error!!) + } + } + + fun getOrThrow(): A { + if (value != null) { + return value + } else { + throw error!! + } + } + + // Functor + fun map(function: (A) -> B) = ErrorOr(value?.let(function), error) + + // Applicative + fun combine(other: ErrorOr, function: (A, B) -> C): ErrorOr { + return ErrorOr(value?.let { a -> other.value?.let { b -> function(a, b) } }, error ?: other.error) + } + + // Monad + fun bind(function: (A) -> ErrorOr) = value?.let(function) ?: ErrorOr.of(error!!) +} \ No newline at end of file