Skip to content

Instantly share code, notes, and snippets.

@ubourdon
Last active October 13, 2024 16:17
Show Gist options
  • Save ubourdon/7b7e929117343b2324cde6eab57674a6 to your computer and use it in GitHub Desktop.
Save ubourdon/7b7e929117343b2324cde6eab57674a6 to your computer and use it in GitHub Desktop.
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