All Downloads are FREE. Search and download functionalities are using the official Maven repository.

colibri.ext.zio.package.scala Maven / Gradle / Ivy

package colibri.ext

import colibri._
import colibri.effect._

import _root_.zio.stream.{ZSink, ZStream}
import _root_.zio.{Runtime, ZIO, RIO, Unsafe}

trait ZioLowPrio {
  type RSink[-Env, A]    = ZSink[Env, Throwable, A, A, Unit]
  type RStream[-Env, +A] = ZStream[Env, Throwable, A]

  implicit val zioTaskRunEffect: RunEffect[RIO[Any, *]] = new RunEffectZIOWithRuntime(Runtime.default)
  implicit val zioSinkSink: Sink[RSink[Any, *]]         = new SinkZIOWithRuntime(Runtime.default)
  implicit val zioStreamSource: Source[RStream[Any, *]] = new SourceZIOWithRuntime(Runtime.default)
}

package object zio extends ZioLowPrio {
  @inline implicit def zioTaskRunEffectRuntime[Env](implicit runtime: Runtime[Env]): RunEffect[RIO[Env, *]] =
    new RunEffectZIOWithRuntime[Env](runtime)

  // Sink

  @inline implicit def zioSinkSinkRuntime[Env](implicit runtime: Runtime[Env]): Sink[RSink[Env, *]] = new SinkZIOWithRuntime(runtime)

  implicit object zioSinkLiftSink extends LiftSink[RSink[Any, *]] {
    def lift[G[_]: Sink, A](sink: G[A]): RSink[Any, A] = ZSink
      .foreach[Any, Throwable, A](elem => ZIO.succeed(Sink[G].unsafeOnNext(sink)(elem)))
      .foldSink(error => ZSink.fromZIO(ZIO.succeed(Sink[G].unsafeOnError(sink)(error))), _ => ZSink.drain)
  }

  // Source

  @inline implicit def zioStreamSourceRuntime[Env](implicit runtime: Runtime[Env]): Source[RStream[Env, *]] = new SourceZIOWithRuntime(
    runtime,
  )

  implicit object zioStreamLiftSource extends LiftSource[RStream[Any, *]] {
    override def lift[G[_]: Source, A](source: G[A]): RStream[Any, A] = ZStream.fromZIO(ZIO.asyncInterrupt { emit =>
      val cancelable = Source[G].unsafeSubscribe(source)(new Observer[A] {
        override def unsafeOnNext(value: A): Unit          = emit(ZIO.succeed(value))
        override def unsafeOnError(error: Throwable): Unit = emit(ZIO.fail(error))
      })
      Left(ZIO.succeed(cancelable.unsafeCancel()))
    })
  }
}

private final class SinkZIOWithRuntime[Env](runtime: Runtime[Env]) extends Sink[zio.RSink[Env, *]] {
  override def unsafeOnNext[A](sink: zio.RSink[Env, A])(value: A): Unit = {
    Unsafe.unsafe(implicit u => runtime.unsafe.run(ZStream.succeed(value).run(sink)))
    ()
  }

  override def unsafeOnError[A](sink: zio.RSink[Env, A])(error: Throwable): Unit = {
    Unsafe.unsafe(implicit u => runtime.unsafe.run(ZStream.fail(error).run(sink)))
    ()
  }
}

private final class SourceZIOWithRuntime[Env](runtime: Runtime[Env]) extends Source[zio.RStream[Env, *]] {
  override def unsafeSubscribe[A](source: zio.RStream[Env, A])(sink: Observer[A]): Cancelable = {
    val canceler = Unsafe.unsafe(implicit u =>
      runtime.unsafe.runToFuture(
        source
          .onError(cause => ZIO.succeed(sink.unsafeOnError(cause.squash)))
          .foreach(value => ZIO.succeed(sink.unsafeOnNext(value))),
      ),
    )

    Cancelable.withIsEmpty(canceler.isCompleted) { () =>
      canceler.cancel()
      ()
    }
  }
}

private final class RunEffectZIOWithRuntime[Env](runtime: Runtime[Env]) extends RunEffect[RIO[Env, *]] {
  override def unsafeRunAsyncCancelable[T](effect: RIO[Env, T])(cb: Either[Throwable, T] => Unit): Cancelable =
    unsafeRunSyncOrAsyncCancelable(ZIO.yieldNow *> effect)(cb)

  override def unsafeRunSyncOrAsyncCancelable[T](effect: RIO[Env, T])(cb: Either[Throwable, T] => Unit): Cancelable = {
    val cancelableFuture = Unsafe.unsafe(implicit u => runtime.unsafe.runToFuture(effect))
    RunEffectExecution.handleFutureCancelable(cancelableFuture, cancelableFuture.cancel)(cb)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy