Skip to content

Commit 7768f0a

Browse files
committed
steps evalutator trait
1 parent eb7b8e8 commit 7768f0a

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

src/main/scala/steps/result/package.scala

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import scala.util.boundary
1010
import scala.annotation.implicitNotFound
1111
import scala.Conversion.into
1212
import scala.util.boundary.Label
13+
import steps.result.Result.eval.break
1314

1415
/** Represents either a success value of type `T` or an error of type `E`. It
1516
* can be used when expecting results that have errors that should be inspected
@@ -457,6 +458,51 @@ object Result:
457458

458459
// Boundary and break
459460

461+
trait Evaluator[Impl[+_,+_]]:
462+
self =>
463+
type Success[+T]
464+
type Failure[+E]
465+
466+
inline def foldValue[T, E](impl: Impl[T, E])[U](inline onSuccess: T => U, inline onFailure: Failure[E] => U): U
467+
inline def failure[E](error: E): Failure[E]
468+
469+
extension [T, E](
470+
using @implicitNotFound(
471+
"`break` cannot be used outside of the `Result.apply` scope."
472+
)
473+
label: boundary.Label[Failure[E]])(impl: into[Impl[T, E]]) {
474+
final inline def ok: T = foldValue(impl)(t => t, boundary.break(_))
475+
}
476+
477+
trait EvaluatorCompanion[Impl[+_,+_]]:
478+
479+
final inline def raise[E](using eval: Evaluator[Impl])(using
480+
@implicitNotFound(
481+
"`raise` cannot be used outside of the `Result.apply` scope."
482+
)
483+
label: boundary.Label[eval.Failure[E]]
484+
)(inline err: into[E]): Nothing = boundary.break(eval.failure(err))
485+
486+
final inline def break[T, E](using eval: Evaluator[Impl])(using
487+
@implicitNotFound(
488+
"`break` cannot be used outside of the `Result.apply` scope."
489+
)
490+
label: boundary.Label[Impl[T, E]]
491+
)(inline res: into[Impl[T, E]]): Nothing = boundary.break(res)
492+
493+
given resultEvaluator: Evaluator[Result] with
494+
type Success[T] = Ok[T]
495+
type Failure[E] = Err[E]
496+
497+
inline def foldValue[T, E](impl: Result[T, E])[U](inline onSuccess: T => U, inline onFailure: Err[E] => U): U =
498+
impl match
499+
case Ok(value) => onSuccess(value)
500+
case err: Err[E] => onFailure(err)
501+
502+
inline def failure[E](error: E): Err[E] = Err(error)
503+
504+
object eval2 extends EvaluatorCompanion[Result]
505+
460506
// Currently under its own object `eval` due to https://github.com/scala/scala3/issues/20126
461507

462508
/** Evaluates `body`, returning the output as an [[Ok]] value.

src/test/scala/steps/result/Result.scala

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import scala.util.Try
33
import language.experimental.captureChecking
44

55
import steps.result.Result
6-
import steps.result.Result.*
7-
import steps.result.Result.eval.*
6+
import steps.result.Result.{eval as _, *}
7+
// import steps.result.Result.eval.*
8+
9+
import steps.result.Result.eval2.*
810

911
class ResultTest extends munit.FunSuite {
1012

@@ -165,12 +167,12 @@ class ResultTest extends munit.FunSuite {
165167

166168
def log2(input: Int): Result[Int, LogErr] =
167169
Result:
168-
if input < 1 then eval.raise(NoLog)
170+
if input < 1 then eval2.raise(NoLog)
169171
else if input == 1 then 0
170172
else log2(input / 2).ok + 1
171173

172174
Result[Int, Exception]: label ?=>
173-
log2(5).ok
175+
Result.resultEvaluator.ok(log2(5))//.ok
174176

175177
assertEquals(log2(4), Ok(2))
176178
assertEquals(log2(-1), Err(LogErr.NL(NoLog)))
@@ -208,15 +210,15 @@ class ResultTest extends munit.FunSuite {
208210
case Seq() => init
209211
case Seq(h, t*) =>
210212
val next = f(init, h).ok
211-
eval.break(tryFoldLeft(next, f)(t))
213+
eval2.break(tryFoldLeft(next, f)(t))
212214
}
213215

214216
test("implicit upcasting") {
215217
import steps.result.Conversions.Lift.given
216218

217219
Result[Int, Nothing]:
218220
val t: Result[Int, String] = 1
219-
eval.break(1)
221+
eval2.break(1)
220222
}
221223

222224
test("iterable") {
@@ -249,7 +251,7 @@ class ResultTest extends munit.FunSuite {
249251
Result[Int, Bar]: l1 ?=>
250252
Result[String, Foo]: l2 ?=>
251253
val r: Result[String, Int] = Result.Err(1)
252-
val str: String = eval.ok(using l1)(r)
254+
val str: String = eval2.ok(using l1)(r)
253255
str
254256
.ok.length
255257
}
@@ -259,7 +261,7 @@ class ResultTest extends munit.FunSuite {
259261
test("break error") {
260262
given Conversion[String, Int] = _.length // comment for failure
261263
Result[Int, Int]:
262-
val z = eval.break(err)
264+
val z = eval2.break(err)
263265
1
264266
}
265267

0 commit comments

Comments
 (0)