cats.effect.ExitCase Scala Examples

The following examples show how to use cats.effect.ExitCase. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: TaskInstances.scala    From shims   with Apache License 2.0 5 votes vote down vote up
package shims.effect.instances

import cats.{Applicative, Monad, Parallel, StackSafeMonad, ~>}
import cats.effect.{Effect, ExitCase, IO, SyncIO}

import scalaz.{Tag, -\/, \/, \/-}
import scalaz.concurrent.Task.ParallelTask
import scalaz.concurrent.{Future, Task}

import shims.conversions.MonadErrorConversions

import java.util.concurrent.atomic.AtomicBoolean

import scala.util.control.NonFatal

trait TaskInstances extends MonadErrorConversions {

  // cribbed from quasar, where it was mostly cribbed from scalaz-task-effect
  implicit object taskEffect extends Effect[Task] with StackSafeMonad[Task] {

    def pure[A](x: A): Task[A] = Task.now(x)

    def handleErrorWith[A](fa: Task[A])(f: Throwable => Task[A]): Task[A] =
      fa.handleWith(functionToPartial(f))

    def raiseError[A](e: Throwable): Task[A] = Task.fail(e)

    // In order to comply with `repeatedCallbackIgnored` law
    // on async, a custom AtomicBoolean is required to ignore
    // second callbacks.
    def async[A](k: (Either[Throwable, A] => Unit) => Unit): Task[A] = Task.async { registered =>
      val a = new AtomicBoolean(true)
      try k(e => if (a.getAndSet(false)) registered(\/.fromEither(e)) else ())
      catch { case NonFatal(t) => registered(-\/(t)) }
    }

    def asyncF[A](k: (Either[Throwable, A] => Unit) => Task[Unit]): Task[A] =
      async(k.andThen(_.unsafePerformAsync(forget)))

    // emulates using attempt
    def bracketCase[A, B](acquire: Task[A])(use: A => Task[B])(release: (A, ExitCase[Throwable]) => Task[Unit]): Task[B] = {
      for {
        a <- acquire
        bOr <- use(a).attempt
        ec = bOr.fold(ExitCase.Error(_), _ => ExitCase.Completed)
        _ <- release(a, ec)
        b <- bOr.fold(Task.fail, Task.now)
      } yield b
    }

    
    def runAsync[A](fa: Task[A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] =
      SyncIO {
        fa unsafePerformAsync { disjunction =>
          cb(disjunction.toEither).unsafeRunAsync(forget)
        }
      }

    def runSyncStep[A](fa: Task[A]): IO[Either[Task[A], A]] =
      IO {
        fa.get match {
          case Future.Now(-\/(_)) => Left(fa)

          case other => other.step match {
            case Future.Now(\/-(a)) => Right(a)
            case other => Left(new Task(other))
          }
        }
      }

    override def map[A, B](fa: Task[A])(f: A => B): Task[B] =
      fa.map(f)

    def flatMap[A, B](fa: Task[A])(f: A => Task[B]): Task[B] = fa.flatMap(f)

    override def delay[A](thunk: => A): Task[A] = Task.delay(thunk)

    def suspend[A](thunk: => Task[A]): Task[A] = Task.suspend(thunk)
  }

  implicit val taskParallel: Parallel.Aux[Task, ParallelTask] = new Parallel[Task] {
    import Task.taskParallelApplicativeInstance

    type F[A] = ParallelTask[A]

    val monad: Monad[Task] = taskEffect
    val applicative: Applicative[ParallelTask] = Applicative[ParallelTask]
    val sequential: ParallelTask ~> Task = λ[ParallelTask ~> Task](Tag.unwrap(_))
    val parallel: Task ~> ParallelTask = λ[Task ~> ParallelTask](Tag(_))
  }

  private def functionToPartial[A, B](f: A => B): PartialFunction[A, B] = {
    case a => f(a)
  }

  private def forget[A](x: A): Unit = ()
} 
Example 2
Source File: RerunnableInstances.scala    From catbird   with Apache License 2.0 5 votes vote down vote up
package io.catbird.util.effect

import cats.effect.{ Effect, ExitCase, IO, SyncIO }
import com.twitter.util.{ Future, Monitor, Promise, Return, Throw }
import io.catbird.util.{ Rerunnable, RerunnableMonadError }
import java.lang.Throwable
import scala.Unit
import scala.util.{ Either, Left, Right }

trait RerunnableInstances {
  implicit final val rerunnableEffectInstance: Effect[Rerunnable] =
    new RerunnableMonadError with Effect[Rerunnable] {
      final def suspend[A](thunk: => Rerunnable[A]): Rerunnable[A] = Rerunnable.suspend[A](thunk)

      override final def delay[A](thunk: => A): Rerunnable[A] = Rerunnable[A](thunk)

      final def async[A](k: (Either[Throwable, A] => Unit) => Unit): Rerunnable[A] =
        new Rerunnable[A] {
          final def run: Future[A] = {
            val promise = new Promise[A]

            k { e =>
              if (promise.isDefined) ()
              else
                e match {
                  case Right(a)  => promise.setValue(a)
                  case Left(err) => promise.setException(err)
                }
            }

            promise
          }
        }

      final def asyncF[A](k: (Either[Throwable, A] => Unit) => Rerunnable[Unit]): Rerunnable[A] =
        new Rerunnable[A] {
          final def run: Future[A] = {
            val promise = new Promise[A]

            val rerunnable = k { e =>
              if (promise.isDefined) ()
              else
                e match {
                  case Right(a)  => promise.setValue(a)
                  case Left(err) => promise.setException(err)
                }
            }

            rerunnable.run.flatMap(_ => promise)
          }
        }

      final def runAsync[A](fa: Rerunnable[A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] =
        rerunnableToIO[A](fa).runAsync(cb)

      final def bracketCase[A, B](acquire: Rerunnable[A])(use: A => Rerunnable[B])(
        release: (A, ExitCase[Throwable]) => Rerunnable[Unit]
      ): Rerunnable[B] = new Rerunnable[B] {
        final def run: Future[B] =
          acquire.run.flatMap { a =>
            val future = use(a).run
            future.transform {
              case Return(b)  => release(a, ExitCase.complete).run.handle(Monitor.catcher).flatMap(_ => future)
              case Throw(err) => release(a, ExitCase.error(err)).run.handle(Monitor.catcher).flatMap(_ => future)
            }
          }
      }
    }
} 
Example 3
Source File: ExpiryServiceTest.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.eventual.cassandra

import java.time.{Instant, LocalDate, ZoneOffset}

import cats.effect.ExitCase
import cats.implicits._
import cats.{Id, catsInstancesForId}
import com.evolutiongaming.kafka.journal.ExpireAfter
import com.evolutiongaming.kafka.journal.ExpireAfter.implicits._
import com.evolutiongaming.kafka.journal.eventual.cassandra.ExpireOn.implicits._
import com.evolutiongaming.kafka.journal.eventual.cassandra.ExpiryService.Action
import com.evolutiongaming.kafka.journal.util.BracketFromMonad
import org.scalatest.FunSuite
import org.scalatest.matchers.should.Matchers

import scala.concurrent.duration._
import scala.util.control.NonFatal

class ExpiryServiceTest extends FunSuite with Matchers {
  import ExpiryServiceTest._

  test("expireOn") {
    val expireAfter = 1.day.toExpireAfter
    val expected = LocalDate.of(2019, 12, 12).toExpireOn
    expireService.expireOn(expireAfter, timestamp) shouldEqual expected
  }

  for {
    (expiry, expireAfter, action) <- List(
      (
        none[Expiry],
        1.minute.toExpireAfter.some,
        Action.update(Expiry(
          1.minute.toExpireAfter,
          LocalDate.of(2019, 12, 11).toExpireOn))),
      (
        none[Expiry],
        1.day.toExpireAfter.some,
        Action.update(Expiry(
          1.day.toExpireAfter,
          LocalDate.of(2019, 12, 12).toExpireOn))),
      (
        Expiry(
          1.day.toExpireAfter,
          LocalDate.of(2019, 12, 11).toExpireOn).some,
        1.day.toExpireAfter.some,
        Action.update(Expiry(
          1.day.toExpireAfter,
          LocalDate.of(2019, 12, 12).toExpireOn))),
      (
        Expiry(
          1.day.toExpireAfter,
          LocalDate.of(2019, 12, 12).toExpireOn).some,
        1.day.toExpireAfter.some,
        Action.ignore),
      (
        Expiry(
          1.day.toExpireAfter,
          LocalDate.of(2019, 12, 12).toExpireOn).some,
        none[ExpireAfter],
        Action.remove))
  } yield {
    test(s"action expiry: $expiry, expireAfter: $expireAfter, action: $action") {
      expireService.action(expiry, expireAfter, timestamp) shouldEqual action
    }
  }
}

object ExpiryServiceTest {

  implicit val bracketId: BracketFromMonad[Id, Throwable] = new BracketFromMonad[Id, Throwable] {

    def F = catsInstancesForId

    def bracketCase[A, B](acquire: Id[A])(use: A => Id[B])(release: (A, ExitCase[Throwable]) => Id[Unit]) = {
      flatMap(acquire) { a =>
        try {
          val b = use(a)
          try release(a, ExitCase.Completed) catch { case NonFatal(_) => }
          b
        } catch {
          case NonFatal(e) =>
            release(a, ExitCase.Error(e))
            raiseError(e)
        }
      }
    }

    def raiseError[A](a: Throwable) = throw a

    def handleErrorWith[A](fa: Id[A])(f: Throwable => Id[A]) = fa
  }

  val timestamp: Instant = Instant.parse("2019-12-11T10:10:10.00Z")

  val zoneId: ZoneOffset = ZoneOffset.UTC

  val expireService: ExpiryService[Id] = ExpiryService[Id](zoneId)
} 
Example 4
Source File: TestSync.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.util

import cats.Monad
import cats.effect.{ExitCase, Sync}

import scala.util.control.NonFatal

object TestSync {

  def apply[F[_]](implicit F: Monad[F]): Sync[F] = new Sync[F] {

    def suspend[A](thunk: => F[A]) = thunk

    def bracketCase[A, B](acquire: F[A])(use: A => F[B])(release: (A, ExitCase[Throwable]) => F[Unit]) = {
      flatMap(acquire) { a =>
        try {
          val b = use(a)
          try release(a, ExitCase.Completed) catch { case NonFatal(_) => }
          b
        } catch {
          case NonFatal(e) =>
            release(a, ExitCase.Error(e))
            raiseError(e)
        }
      }
    }

    def raiseError[A](e: Throwable) = throw e

    def handleErrorWith[A](fa: F[A])(f: Throwable => F[A]) = try fa catch { case NonFatal(e) => f(e) }

    def flatMap[A, B](fa: F[A])(f: A => F[B]) = F.flatMap(fa)(f)

    def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]) = F.tailRecM(a)(f)

    def pure[A](a: A) = F.pure(a)
  }
} 
Example 5
Source File: ConditionalLogger.scala    From odin   with Apache License 2.0 5 votes vote down vote up
package io.odin.extras.loggers

import cats.MonadError
import cats.effect.{Concurrent, ContextShift, ExitCase, Resource, Timer}
import cats.syntax.applicativeError._
import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.syntax.order._
import io.odin.loggers.DefaultLogger
import io.odin.{Level, Logger, LoggerMessage}
import monix.catnap.ConcurrentQueue
import monix.execution.{BufferCapacity, ChannelType}

final case class ConditionalLogger[F[_]: Timer] private (
    queue: ConcurrentQueue[F, LoggerMessage],
    inner: Logger[F],
    override val minLevel: Level
)(implicit F: MonadError[F, Throwable])
    extends DefaultLogger[F](minLevel) {

  def log(msg: LoggerMessage): F[Unit] =
    queue.tryOffer(msg).void

  private def drain(exitCase: ExitCase[Throwable]): F[Unit] = {
    val level = exitCase match {
      case ExitCase.Completed => inner.minLevel
      case _                  => minLevel
    }

    queue
      .drain(0, Int.MaxValue)
      .flatMap(msgs => inner.log(msgs.filter(_.level >= level).toList))
      .attempt
      .void
  }

}

object ConditionalLogger {

  
  def create[F[_]: Timer: Concurrent: ContextShift](
      inner: Logger[F],
      minLevelOnError: Level,
      maxBufferSize: Option[Int]
  ): Resource[F, Logger[F]] = {

    val queueCapacity = maxBufferSize match {
      case Some(value) => BufferCapacity.Bounded(value)
      case None        => BufferCapacity.Unbounded()
    }

    def acquire: F[ConditionalLogger[F]] =
      for {
        queue <- ConcurrentQueue.withConfig[F, LoggerMessage](queueCapacity, ChannelType.MPSC)
      } yield ConditionalLogger(queue, inner, minLevelOnError)

    def release(logger: ConditionalLogger[F], exitCase: ExitCase[Throwable]): F[Unit] =
      logger.drain(exitCase)

    Resource.makeCase(acquire)(release).widen
  }

} 
Example 6
Source File: KafkaDistributedProcessingTest.scala    From aecor   with MIT License 5 votes vote down vote up
package aecor.kafkadistributedprocessing

import cats.effect.concurrent.{ Deferred, Ref }
import cats.effect.{ ExitCase, IO }
import cats.implicits._
import fs2.concurrent.Queue
import org.apache.kafka.clients.consumer.ConsumerConfig
import org.scalatest.funsuite.AnyFunSuiteLike
import scala.concurrent.duration._
class KafkaDistributedProcessingTest extends AnyFunSuiteLike with KafkaSupport with IOSupport {

  val topicName = "process-distribution"

  createCustomTopic(topicName, partitions = 4)

  val settings =
    DistributedProcessingSettings(Set(s"localhost:${kafkaConfig.kafkaPort}"), topicName)

  test("Process error propagation") {
    val exception = new RuntimeException("Oops!")

    val result = DistributedProcessing(settings)
      .start("Process error propagation", List(IO.raiseError[Unit](exception)))
      .attempt
      .timeout(20.seconds)
      .unsafeRunSync()

    assert(result == Left(exception))
  }

  test("Process lifecycle") {

    val test = Ref.of[IO, (Boolean, Boolean)]((false, false)).flatMap { ref =>
      Deferred[IO, Unit]
        .flatMap { done =>
          val process =
            ref.set((true, false)) >>
              done.complete(()) >>
              IO.never.guaranteeCase {
                case ExitCase.Canceled => ref.set((true, true))
                case _                 => IO.unit
              }.void

          val run = DistributedProcessing(settings)
            .start("Process lifecycle", List(process))

          IO.race(run, done.get) >> ref.get
        }
    }

    val (started, finished) = test.timeout(20.seconds).unsafeRunSync()

    assert(started)
    assert(finished)
  }

  test("Process distribution") {
    val test = Queue.unbounded[IO, Int].flatMap { queue =>
      def run(client: Int) =
        DistributedProcessing(
          settings.withConsumerSetting(ConsumerConfig.CLIENT_ID_CONFIG, client.toString)
        ).start(
          "Process distribution",
          Stream
            .from(0)
            .take(8)
            .map { n =>
              val idx = client * 10 + n
              (queue.enqueue1(idx) >> IO.cancelBoundary <* IO.never)
                .guarantee(queue.enqueue1(-idx))
            }
            .toList
        )

      def dequeue(size: Long): IO[List[Int]] =
        queue.dequeue.take(size).compile.to[List]

      for {
        d1 <- run(1).start
        s1 <- dequeue(8)
        d2 <- run(2).start
        s2 <- dequeue(16)
        _ <- d1.cancel
        s3 <- dequeue(16)
        _ <- d2.cancel
        s4 <- dequeue(8)
      } yield (s1, s2, s3, s4)
    }

    val (s1, s2, s3, s4) = test.timeout(20.seconds).unsafeRunSync()

    assert(s1.toSet == Set(10, 11, 12, 13, 14, 15, 16, 17))
    assert((s1 ++ s2 ++ s3 ++ s4).sum == 0)
  }

} 
Example 7
Source File: Memoize.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.memo

import cats.effect.{Concurrent, ExitCase}
import cats.effect.concurrent.{Deferred, Ref}
import simulacrum.typeclass
import tofu.syntax.monadic._
import cats.syntax.option._
import cats.effect.syntax.concurrent._
import cats.effect.syntax.bracket._


  def memoizeOnSuccess[A](fa: F[A]): F[F[A]]
}

object Memoize {
  def concurrentMemoize[F[_]](implicit F: Concurrent[F]): Memoize[F] =
    new Memoize[F] {
      def memoize[A](fa: F[A]): F[F[A]] = Concurrent.memoize(fa)

      //copy of Concurrent.memoize accepting success only
      def memoizeOnSuccess[A](f: F[A]): F[F[A]] = {
        {
          sealed trait State
          case class Subs(n: Int) extends State
          case object Done        extends State

          case class Fetch(state: State, v: Deferred[F, A], stop: Deferred[F, F[Unit]])

          Ref[F].of(Option.empty[Fetch]).map { state =>
            (Deferred[F, A] product Deferred[F, F[Unit]]).flatMap {
              case (v, stop) =>
                def endState(ec: ExitCase[Throwable]) =
                  state.modify {
                    case None                          => throw new AssertionError("unreachable")
                    case s @ Some(Fetch(Done, _, _))   => s -> F.unit
                    case Some(Fetch(Subs(n), v, stop)) =>
                      if (ec == ExitCase.Canceled && n == 1) None -> stop.get.flatten
                      else if (ec == ExitCase.Canceled) Fetch(Subs(n - 1), v, stop).some -> F.unit
                      else Fetch(Done, v, stop).some                                     -> F.unit
                  }.flatten

                def fetch =
                  f.flatMap(v.complete)
                    .start
                    .flatMap(fiber => stop.complete(fiber.cancel))

                state.modify {
                  case s @ Some(Fetch(Done, v, _))   =>
                    s -> v.get
                  case Some(Fetch(Subs(n), v, stop)) =>
                    Fetch(Subs(n + 1), v, stop).some -> v.get.guaranteeCase(endState)
                  case None                          =>
                    Fetch(Subs(1), v, stop).some -> fetch.bracketCase(_ => v.get) { case (_, ec) => endState(ec) }
                }.flatten
            }
          }
        }
      }
    }
} 
Example 8
Source File: Exit.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.concurrent

import cats.{Applicative, Eval, Traverse}
import cats.effect.ExitCase
import tofu.control.ApplicativeZip
import tofu.syntax.monadic._

sealed trait Exit[+E, +A] {
  def exitCase: ExitCase[E]
}

object Exit {

  sealed trait Incomplete[+E] extends Exit[E, Nothing]

  case object Canceled                 extends Incomplete[Nothing] {
    def exitCase = ExitCase.Canceled
  }
  final case class Error[+E](e: E)     extends Incomplete[E]       {
    def exitCase = ExitCase.Error(e)
  }
  final case class Completed[+A](a: A) extends Exit[Nothing, A]    {
    override def exitCase = ExitCase.Completed
  }

  private[this] object exitInstanceAny extends Traverse[Exit[Any, *]] with ApplicativeZip[Exit[Any, *]] {
    def traverse[G[_], A, B](fa: Exit[Any, A])(f: A => G[B])(implicit G: Applicative[G]): G[Exit[Any, B]] =
      fa match {
        case Canceled     => G.pure(Canceled)
        case Error(e)     => G.pure(Error(e))
        case Completed(a) => f(a).map(Completed(_))
      }
    def foldLeft[A, B](fa: Exit[Any, A], b: B)(f: (B, A) => B): B                                         =
      fa match {
        case Canceled | Error(_) => b
        case Completed(a)        => f(b, a)
      }
    def foldRight[A, B](fa: Exit[Any, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B]               =
      fa match {
        case Canceled | Error(_) => lb
        case Completed(a)        => f(a, lb)
      }
    override def map[A, B](fa: Exit[Any, A])(f: A => B): Exit[Any, B]                                     =
      fa match {
        case Canceled      => Canceled
        case e: Error[Any] => e
        case Completed(a)  => Completed(f(a))
      }

    def zipWith[A, B, C](fa: Exit[Any, A], fb: Exit[Any, B])(f: (A, B) => C): Exit[Any, C] =
      fa match {
        case Canceled        => Canceled
        case err: Error[Any] => err
        case Completed(a)    =>
          fb match {
            case Canceled        => Canceled
            case err: Error[Any] => err
            case Completed(b)    => Completed(f(a, b))
          }
      }
    def pure[A](x: A): Exit[Any, A]                                                        = Completed(x)
  }

  implicit def exitInstance[E]: Traverse[Exit[E, *]] with Applicative[Exit[E, *]] =
    exitInstanceAny.asInstanceOf[Traverse[Exit[E, *]] with Applicative[Exit[E, *]]]
} 
Example 9
Source File: Guarantee.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu

import cats.effect.{Bracket, ExitCase}


  def finallyCase[A, B, C](init: F[A])(action: A => F[B])(release: (A, Exit[B]) => F[C]): F[B]
}

object Finally extends FinallyInstanceChain[Finally]

trait FinallyInstanceChain[T[f[_], exit[_]] >: Finally[f, exit]] {
  final implicit def fromBracket[F[_], E](implicit F: Bracket[F, E]): T[F, TConst[ExitCase[E], *]] =
    new Finally[F, TConst[ExitCase[E], *]] {
      def finallyCase[A, B, C](init: F[A])(action: A => F[B])(release: (A, ExitCase[E]) => F[C]): F[B] =
        F.bracketCase(init)(action) {
          case (a, exit) => F.void(release(a, exit))
        }
      def bracket[A, B, C](init: F[A])(action: A => F[B])(release: (A, Boolean) => F[C]): F[B]         =
        F.bracketCase(init)(action) {
          case (a, ExitCase.Completed) => F.void(release(a, true))
          case (a, _)                  => F.void(release(a, false))
        }
    }
} 
Example 10
Source File: unlift.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.syntax

import cats.effect.{CancelToken, ConcurrentEffect, Effect, ExitCase, Fiber, IO, SyncIO}
import cats.{FlatMap, Functor, ~>}
import tofu.lift.Unlift

object unlift {

  implicit final class UnliftEffectOps[F[_], G[_]](private val U: Unlift[F, G]) extends AnyVal {
    def effect(implicit G: Functor[G], E: Effect[F]): G[Effect[G]] =
      G.map(U.unlift) { unliftF =>
        new EffectInstance[F, G] {
          def toG: F ~> G           = U.liftF
          def toF: G ~> F           = unliftF
          implicit def F: Effect[F] = E
        }
      }

    def effectWith[A](f: Effect[G] => G[A])(implicit G: FlatMap[G], E: Effect[F]): G[A] =
      G.flatMap(U.unlift) { unliftF =>
        val eff = new EffectInstance[F, G] {
          def toG: F ~> G           = U.liftF
          def toF: G ~> F           = unliftF
          implicit def F: Effect[F] = E
        }
        f(eff)
      }

    def concurrentEffect(implicit G: Functor[G], CE: ConcurrentEffect[F]): G[ConcurrentEffect[G]] =
      G.map(U.unlift) { unliftF =>
        new ConcurrentEffectInstance[F, G] {
          def toG: F ~> G                     = U.liftF
          def toF: G ~> F                     = unliftF
          implicit def F: ConcurrentEffect[F] = CE
        }
      }

    def concurrentEffectWith[A](f: ConcurrentEffect[G] => G[A])(implicit G: FlatMap[G], CE: ConcurrentEffect[F]): G[A] =
      G.flatMap(U.unlift) { unliftF =>
        val ce = new ConcurrentEffectInstance[F, G] {
          def toG: F ~> G                     = U.liftF
          def toF: G ~> F                     = unliftF
          implicit def F: ConcurrentEffect[F] = CE
        }
        f(ce)
      }

  }

  private[unlift] trait EffectInstance[F[_], G[_]] extends Effect[G] {
    def toG: F ~> G
    def toF: G ~> F
    implicit def F: Effect[F]

    def pure[A](x: A): G[A] = toG(F.pure(x))

    def flatMap[A, B](ga: G[A])(f: A => G[B]): G[B] = toG(F.flatMap(toF(ga))(a => toF(f(a))))

    def tailRecM[A, B](a: A)(f: A => G[Either[A, B]]): G[B] = toG(F.tailRecM(a)(a => toF(f(a))))

    def raiseError[A](e: Throwable): G[A] = toG(F.raiseError(e))

    def handleErrorWith[A](ga: G[A])(f: Throwable => G[A]): G[A] = toG(F.handleErrorWith(toF(ga))(t => toF(f(t))))

    def bracketCase[A, B](acquire: G[A])(use: A => G[B])(release: (A, ExitCase[Throwable]) => G[Unit]): G[B] =
      toG(F.bracketCase(toF(acquire))(a => toF(use(a)))((a, e) => toF(release(a, e))))

    def suspend[A](thunk: => G[A]): G[A] = toG(F.suspend(toF(thunk)))

    def async[A](k: (Either[Throwable, A] => Unit) => Unit): G[A] = toG(F.async(k))

    def asyncF[A](k: (Either[Throwable, A] => Unit) => G[Unit]): G[A] = toG(F.asyncF[A](cb => toF(k(cb))))

    def runAsync[A](ga: G[A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit] = F.runAsync(toF(ga))(cb)
  }

  private[unlift] trait ConcurrentEffectInstance[F[_], G[_]] extends EffectInstance[F, G] with ConcurrentEffect[G] {
    implicit def F: ConcurrentEffect[F]

    def start[A](ga: G[A]): G[Fiber[G, A]] = toG(F.map(F.start(toF(ga)))(_.mapK(toG)))

    def racePair[A, B](ga: G[A], gb: G[B]): G[Either[(A, Fiber[G, B]), (Fiber[G, A], B)]] =
      toG(F.map(F.racePair(toF(ga), toF(gb))) {
        case Left((a, fb))  => Left((a, fb.mapK(toG)))
        case Right((fa, b)) => Right((fa.mapK(toG), b))
      })

    def runCancelable[A](ga: G[A])(cb: Either[Throwable, A] => IO[Unit]): SyncIO[CancelToken[G]] =
      F.runCancelable(toF(ga))(cb).map(toG(_))
  }

} 
Example 11
Source File: Monix.scala    From neotypes   with MIT License 5 votes vote down vote up
package neotypes.monix

import cats.effect.{ExitCase, Resource}
import monix.eval.Task

trait Monix {
  implicit final def monixAsync: neotypes.Async.Aux[Task, Monix.TaskResource] =
    Monix.instance
}

object Monix {
  private[neotypes] final type TaskResource[A] = Resource[Task, A]

  private final val instance: neotypes.Async.Aux[Task, TaskResource] =
    new neotypes.Async[Task] {
      override final type R[A] = Resource[Task, A]

      override final def async[T](cb: (Either[Throwable, T] => Unit) => Unit): Task[T] =
        Task.async(cb)

      override final def delay[A](t: => A): Task[A] =
        Task.delay(t)

      override final def failed[T](e: Throwable): Task[T] =
        Task.raiseError(e)

      override final def flatMap[T, U](m: Task[T])(f: T => Task[U]): Task[U] =
        m.flatMap(f)

      override final def guarantee[A, B](fa: Task[A])
                                        (f: A => Task[B])
                                        (finalizer: (A, Option[Throwable]) => Task[Unit]): Task[B] =
        Resource.makeCase(fa) {
          case (a, ExitCase.Completed | ExitCase.Canceled) => finalizer(a, None)
          case (a, ExitCase.Error(ex))                     => finalizer(a, Some(ex))
        }.use(f)

      override final def map[T, U](m: Task[T])(f: T => U): Task[U] =
        m.map(f)

      override final def recoverWith[T, U >: T](m: Task[T])(f: PartialFunction[Throwable, Task[U]]): Task[U] =
        m.onErrorRecoverWith(f)

      override final def resource[A](input: => A)(close: A => Task[Unit]): Resource[Task, A] =
        Resource.make(Task.delay(input))(close)
    }
} 
Example 12
Source File: BracketSyntax.scala    From cats-effect   with Apache License 2.0 5 votes vote down vote up
package cats.effect.syntax

import cats.effect.{Bracket, ExitCase}

trait BracketSyntax {
  implicit def catsEffectSyntaxBracket[F[_], A, E](fa: F[A])(implicit bracket: Bracket[F, E]): BracketOps[F, E, A] = {
    // Bracket instance here is required to ensure correct inference for E
    val _ = bracket
    new BracketOps[F, E, A](fa)
  }
}

final class BracketOps[F[_], E, A](val self: F[A]) extends AnyVal {
  def bracketCase[B](use: A => F[B])(release: (A, ExitCase[E]) => F[Unit])(implicit F: Bracket[F, E]): F[B] =
    F.bracketCase(self)(use)(release)

  def bracket[B](use: A => F[B])(release: A => F[Unit])(implicit F: Bracket[F, E]): F[B] =
    F.bracket(self)(use)(release)

  def guarantee(finalizer: F[Unit])(implicit F: Bracket[F, E]): F[A] =
    F.guarantee(self)(finalizer)

  def guaranteeCase(finalizer: ExitCase[E] => F[Unit])(implicit F: Bracket[F, E]): F[A] =
    F.guaranteeCase(self)(finalizer)

  def uncancelable(implicit F: Bracket[F, E]): F[A] =
    F.uncancelable(self)

  def onCancel(finalizer: F[Unit])(implicit F: Bracket[F, E]): F[A] =
    F.onCancel(self)(finalizer)
} 
Example 13
Source File: monix.scala    From sangria-monix   with Apache License 2.0 5 votes vote down vote up
package sangria.streaming

import scala.language.higherKinds
import _root_.monix.execution.Scheduler
import _root_.monix.reactive._
import _root_.monix.eval.Task
import cats.effect.ExitCase

import scala.concurrent.Future

object monix {
  class ObservableSubscriptionStream(implicit scheduler: Scheduler) extends SubscriptionStream[Observable] {
    def supported[T[_]](other: SubscriptionStream[T]) = other.isInstanceOf[ObservableSubscriptionStream]

    def map[A, B](source: Observable[A])(fn: A => B) = source.map(fn)

    def singleFuture[T](value: Future[T]) =
      Observable.fromFuture(value)

    def single[T](value: T) = Observable(value)

    def mapFuture[A, B](source: Observable[A])(fn: A => Future[B]) =
      source.mergeMap(a => Observable.fromFuture(fn(a)))

    def first[T](s: Observable[T]) =
      s.firstOrElseL(throw new IllegalStateException("Promise was not completed - observable haven't produced any elements.")).runToFuture

    def failed[T](e: Throwable) = Observable.raiseError(e)

    def onComplete[Ctx, Res](result: Observable[Res])(op: => Unit) =
      result.guaranteeCase {
        case ExitCase.Error(e) => Task(op)
        case _ => Task(op)
      }

    def flatMapFuture[Ctx, Res, T](future: Future[T])(resultFn: T => Observable[Res]) =
      Observable.fromFuture(future).mergeMap(resultFn)

    def merge[T](streams: Vector[Observable[T]]) =
      if (streams.nonEmpty)
        Observable(streams: _*).merge
      else
        throw new IllegalStateException("No streams produced!")

    def recover[T](stream: Observable[T])(fn: Throwable => T) =
      stream onErrorRecover {case e => fn(e)}
  }

  implicit def observableSubscriptionStream(implicit scheduler: Scheduler): SubscriptionStream[Observable] =
    new ObservableSubscriptionStream
} 
Example 14
Source File: package.scala    From interop-cats   with Apache License 2.0 5 votes vote down vote up
package zio

import cats.effect.{ Effect, ExitCase, LiftIO }
import zio.interop.catz.taskEffectInstance

package object interop {
  type ParIO[-R, +E, +A] = Par.T[R, E, A]

  type Queue[F[+_], A] = CQueue[F, A, A]

  @inline private[interop] final def exitToExitCase(exit: Exit[Any, Any]): ExitCase[Throwable] = exit match {
    case Exit.Success(_)                          => ExitCase.Completed
    case Exit.Failure(cause) if cause.interrupted => ExitCase.Canceled
    case Exit.Failure(cause) =>
      cause.failureOrCause match {
        case Left(t: Throwable) => ExitCase.Error(t)
        case _                  => ExitCase.Error(FiberFailure(cause))
      }
  }

  @inline private[interop] final def exitCaseToExit[E](exitCase: ExitCase[E]): Exit[E, Unit] = exitCase match {
    case ExitCase.Completed => Exit.unit
    case ExitCase.Error(e)  => Exit.fail(e)
    case ExitCase.Canceled  => Exit.interrupt(Fiber.Id.None)
  }

  private[interop] def fromEffect[F[+_], R, A](
    eff: F[A]
  )(implicit R: Runtime[R], F: Effect[F]): RIO[R, A] =
    taskEffectInstance.liftIO[A](F.toIO(eff))

  private[interop] def toEffect[F[+_], R, A](zio: RIO[R, A])(implicit R: Runtime[R], F: LiftIO[F]): F[A] =
    F.liftIO(taskEffectInstance.toIO(zio))
}