From d085e48e89062de307aab0d0629fba2f867cb49a Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 28 Jun 2023 10:27:45 +0200 Subject: [PATCH] results: add `mapConvertErr`, `mapCastErr` (#178) We already have `mapConvert` and `mapCast` - this completes the API with corresponding `Err` versions similar to `mapErr`. The `Convert` / `Cast` operators are of somewhat dubious value - ie they exist as "efficiency" shortcuts for `map` for the case that the mapping should be done as a simple cast / conversion - an alternative would be to deprecate these features and aim for some other, more generic version that involves a type conversion library such as https://github.com/status-im/nim-stew/pull/34, though this inherently, and perhaps rightly, would be limited to "error-free" conversions. Regardless, these helpers provide balance to the existing API. --- stew/results.nim | 30 ++++++++++++++++++++++++++++++ tests/test_results.nim | 3 +++ 2 files changed, 33 insertions(+) diff --git a/stew/results.nim b/stew/results.nim index 5c29a991..cd24d2d1 100644 --- a/stew/results.nim +++ b/stew/results.nim @@ -628,6 +628,36 @@ func mapCast*[T0: not void, E]( else: result.err(self.eResultPrivate) +func mapConvertErr*[T, E0]( + self: Result[T, E0], E1: type): Result[T, E1] {.inline.} = + ## Convert result error to E1 using an conversion + # Would be nice if it was automatic... + when E0 is E1: + result = self + else: + if self.oResultPrivate: + when T is void: + result.ok() + else: + result.ok(self.vResultPrivate) + else: + when E1 is void: + result.err() + else: + result.err(E1(self.eResultPrivate)) + +func mapCastErr*[T, E0]( + self: Result[T, E0], E1: type): Result[T, E1] {.inline.} = + ## Convert result value to A using a cast + ## Would be nice with nicer syntax... + if self.oResultPrivate: + when T is void: + result.ok() + else: + result.ok(self.vResultPrivate) + else: + result.err(cast[E1](self.eResultPrivate)) + template `and`*[T0, E, T1](self: Result[T0, E], other: Result[T1, E]): Result[T1, E] = ## Evaluate `other` iff self.isOk, else return error ## fail-fast - will not evaluate other if a is an error diff --git a/tests/test_results.nim b/tests/test_results.nim index 3ce5fb78..3e894c2a 100644 --- a/tests/test_results.nim +++ b/tests/test_results.nim @@ -131,6 +131,9 @@ block: doAssert (rErr.orErr(32)).error == 32 doAssert (rOk.orErr(failFast())).get() == rOk.get() + doAssert rErr.mapConvertErr(cstring).error() == cstring(rErr.error()) + doAssert rErr.mapCastErr(seq[byte]).error() == cast[seq[byte]](rErr.error()) + # string conversion doAssert $rOk == "ok(42)" doAssert $rErr == "err(dummy)"