Last active
October 13, 2024 16:17
-
-
Save ubourdon/7b7e929117343b2324cde6eab57674a6 to your computer and use it in GitHub Desktop.
utils function for navigate between scala Future, scalaz Task and scalaz ZIO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package service.utils | |
import scalaz.{-\/, \/, \/-} | |
import scalaz.zio.{DefaultRuntime, IO, ZIO} | |
import play.api.libs.concurrent.Execution.Implicits | |
import scalaz.concurrent.{Task => ZTask} | |
import scala.concurrent.{ExecutionContext, Future} | |
package object zio { | |
case object ErrorConsumed extends Throwable | |
val zioRuntime = new DefaultRuntime {} | |
def fromEither[E, A](e: E \/ A): IO[E, A] = ZIO.fromEither(e.toEither) | |
/** | |
* ZIO Ops | |
*/ | |
implicit class IOOps_Running[E, A](val io: IO[Nothing, A]) extends AnyVal { | |
def unsafePerform: Future[A] = zioRuntime.unsafeRunToFuture(io) | |
} | |
implicit class IOOps_RunningT[E, A](val io: IO[Throwable, A]) extends AnyVal { | |
def unsafePerform: Future[A] = zioRuntime.unsafeRunToFuture(io) | |
} | |
/** | |
* Allow you to produce an IO[Nothing, E\/A] that can't fail and | |
* force you to handle possible errors in the result of the IO. | |
* | |
* @param io the io to consume | |
* @tparam E the type of the Error | |
* @tparam A the type of the result | |
*/ | |
implicit class IOOps[E,A](val io: IO[E,A]) extends AnyVal { | |
def consume: IO[Nothing, E \/ A] = io.either.map { \/.fromEither } | |
} | |
implicit class IOOps_Either[E, A](val io: IO[Nothing, E \/ A]) extends AnyVal { | |
def absolveZ: IO[E,A] = ZIO.absolve(io.orDie.map { _.toEither }) | |
} | |
implicit class IOOps_TEither[E, A](val io: IO[Throwable, E \/ A]) extends AnyVal { | |
def absolveZ: IO[E,A] = ZIO.absolve(io.orDie.map { _.toEither }) | |
} | |
implicit class IOOps_RichEither[E, A](val io: IO[E, E \/ A]) extends AnyVal { | |
def absolveZ: IO[E,A] = ZIO.absolve(io.map { _.toEither }) | |
} | |
/** | |
* scala Future Ops | |
*/ | |
implicit class FutureToIOOps[A](val f: Future[A]) extends AnyVal { | |
def io(implicit ec: ExecutionContext = Implicits.defaultContext): ZIO[Any, Nothing, A] = | |
ZIO.fromFuture(_ => f).orDie | |
def iot(implicit ec: ExecutionContext = Implicits.defaultContext): ZIO[Any, Throwable, A] = | |
ZIO.fromFuture(_ => f) | |
def ioe[E](error: Throwable => E)(implicit ec: ExecutionContext = Implicits.defaultContext): ZIO[Any, E, A] = | |
ZIO.fromFuture(_ => f).mapError(error) | |
} | |
implicit class RichFutureOps[E, A](val f: Future[E \/ A]) extends AnyVal { | |
def io(implicit ec: ExecutionContext = Implicits.defaultContext): IO[E, A] = | |
ZIO.absolve(ZIO.fromFuture(_ => f.map(_.toEither)).orDie) | |
} | |
/** | |
* scalaz Task Ops | |
*/ | |
object ScalazTaskOps { | |
implicit class TaskOps[A](val t: ZTask[A]) extends AnyVal { | |
def io(implicit ec: ExecutionContext = Implicits.defaultContext): ZIO[Any, Nothing, A] = | |
buildIOFromTask(t).orDie | |
def iot: IO[Throwable, A] = buildIOFromTask(t) | |
def ioe[E](error: Throwable => E): IO[E, A] = buildIOFromTask(t).mapError(error) | |
} | |
implicit class RichTaskOps[E, A](val t: ZTask[E \/ A]) extends AnyVal { | |
def io(implicit ec: ExecutionContext = Implicits.defaultContext): ZIO[Any, E, A] = | |
ZIO.absolve(buildIOFromTask(t.map { _.toEither }).orDie) | |
} | |
private def buildIOFromTask[A](t: ZTask[A]): IO[Throwable, A] = | |
ZIO.effectAsync { callback => | |
t.runAsync { | |
case -\/(t) => callback(IO.fail(t)) | |
case \/-(x) => callback(IO.effect(x)) | |
} | |
} | |
} | |
/** | |
* scalaz DisjonctionOps | |
*/ | |
object ScalazDisjonctionOps { | |
implicit class EitherOps[E,A](val e: E \/ A) extends AnyVal { | |
def io: IO[E, A] = ZIO.succeed(e.toEither).absolve | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment