utils function for navigate between scala Future, scalaz Task and scalaz ZIO
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