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

zio.managed.package.scala Maven / Gradle / Ivy

There is a newer version: 2.1.14
Show newest version
/*
 * Copyright 2018-2024 John A. De Goes and the ZIO Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package zio

import zio.stacktracer.TracingImplicits.disableAutoTrace
import zio.stm._
import zio.stream._
import zio.ZLayer._

import java.io.{IOException, InputStream}

/**
 * The `Managed` library provides the `ZManaged` data type for backward
 * compatibility after the introduction of scopes. For the best experience,
 * import `zio.managed._` to get access to extension methods on ZIO data types
 * that convert to and from `ZManaged` values. This will give you the smoothest
 * possible experience until you are able to upgrade to using scopes directly.
 */
package object managed extends ZManagedCompatPlatformSpecific {

  type Managed[+E, +A]   = ZManaged[Any, E, A]         //Manage an `A`, may fail with `E`        , no requirements
  type TaskManaged[+A]   = ZManaged[Any, Throwable, A] //Manage an `A`, may fail with `Throwable`, no requirements
  type RManaged[-R, +A]  = ZManaged[R, Throwable, A]   //Manage an `A`, may fail with `Throwable`, requires an `R`
  type UManaged[+A]      = ZManaged[Any, Nothing, A]   //Manage an `A`, cannot fail              , no requirements
  type URManaged[-R, +A] = ZManaged[R, Nothing, A]     //Manage an `A`, cannot fail              , requires an `R`

  implicit final class ZManagedPromiseCompanionSyntax(private val self: Promise.type) extends AnyVal {
    def makeManaged[E, A](implicit trace: Trace): ZManaged[Any, Nothing, Promise[E, A]] =
      ZManaged.fromZIO(Promise.make[E, A])
  }

  implicit final class ZManagedFiberRefSyntax[A](private val self: FiberRef[A]) {

    /**
     * Returns a managed effect that sets the value associated with the curent
     * fiber to the specified value as its `acquire` action and restores it to
     * its original value as its `release` action.
     */
    def locallyManaged(value: A)(implicit trace: Trace): ZManaged[Any, Nothing, Unit] =
      ZManaged.scoped(self.locallyScoped(value))
  }

  implicit final class ZManagedZIOSyntax[R, E, A](private val self: ZIO[R, E, A]) {

    /**
     * Forks the fiber in a [[ZManaged]]. Using the [[ZManaged]] value will
     * execute the effect in the fiber, while ensuring its interruption when the
     * effect supplied to [[ZManaged#use]] completes.
     */
    final def forkManaged(implicit trace: Trace): ZManaged[R, Nothing, Fiber.Runtime[E, A]] =
      self.toManaged.fork

    /**
     * Converts this ZIO to [[ZManaged]] with no release action. It will be
     * performed interruptibly.
     */
    final def toManaged(implicit trace: Trace): ZManaged[R, E, A] =
      ZManaged.fromZIO(self)

    /**
     * Converts this ZIO to [[Managed]]. This ZIO and the provided release
     * action will be performed uninterruptibly.
     */
    final def toManagedWith[R1 <: R](release: A => URIO[R1, Any])(implicit trace: Trace): ZManaged[R1, E, A] =
      ZManaged.acquireReleaseWith(self)(release)
  }

  implicit final class ZManagedZIOAutoCloseableSyntax[R, E, A <: AutoCloseable](private val self: ZIO[R, E, A])
      extends AnyVal {

    /**
     * Converts this ZIO value to a ZManaged value. See
     * [[ZManaged.fromAutoCloseable]].
     */
    def toManagedAuto(implicit trace: Trace): ZManaged[R, E, A] =
      ZManaged.fromAutoCloseable(self)
  }

  implicit final class ZManagedZIOCompanionSyntax(private val self: ZIO.type) extends AnyVal {

    /**
     * Acquires a resource, uses the resource, and then releases the resource.
     * However, unlike `acquireReleaseWith`, the separation of these phases
     * allows the acquisition to be interruptible.
     *
     * Useful for concurrent data structures and other cases where the
     * 'deallocator' can tell if the allocation succeeded or not just by
     * inspecting internal / external state.
     */
    def reserve[R, E, A, B](reservation: => ZIO[R, E, Reservation[R, E, A]])(use: A => ZIO[R, E, B])(implicit
      trace: Trace
    ): ZIO[R, E, B] =
      ZManaged.fromReservationZIO(reservation).use(use)
  }

  implicit final class ZManagedZLayerSyntax[R, E, A](private val self: ZLayer[R, E, A]) extends AnyVal {

    /** Converts this layer to a ZManaged value. */
    def toManaged(implicit trace: Trace): ZManaged[R, E, ZEnvironment[A]] =
      ZManaged.scoped[R](self.build)
  }

  implicit final class ZManagedZLayerCompanionSyntax(private val self: ZLayer.type) extends AnyVal {

    /**
     * Constructs a layer from a managed resource.
     */
    def fromManaged[R, E, A: Tag](m: ZManaged[R, E, A])(implicit
      trace: Trace
    ): ZLayer[R, E, A] =
      ZLayer.scoped[R](m.scoped)

    /**
     * Constructs a layer from a managed resource, which must return one or more
     * services.
     */
    def fromManagedEnvironment[R, E, A](m: ZManaged[R, E, ZEnvironment[A]])(implicit
      trace: Trace
    ): ZLayer[R, E, A] =
      ZLayer.scopedEnvironment[R](m.scoped)
  }

  implicit final class ZManagedRefCompanionSyntax(private val self: Ref.type) extends AnyVal {
    def makeManaged[A](a: A)(implicit trace: Trace): ZManaged[Any, Nothing, Ref[A]] =
      ZManaged.fromZIO(Ref.make(a))
  }

  implicit final class ZManagedRefSynchronizedCompanionSyntax(private val self: Ref.Synchronized.type) extends AnyVal {
    def makeManaged[A](a: A)(implicit trace: Trace): ZManaged[Any, Nothing, Ref.Synchronized[A]] =
      ZManaged.fromZIO(Ref.Synchronized.make(a))
  }

  implicit final class ZManagedTHubSyntax[A](private val self: THub[A]) extends AnyVal {

    /**
     * Subscribes to receive messages from the hub. The resulting subscription
     * can be evaluated multiple times within the scope of the managed to take a
     * message from the hub each time.
     */
    final def subscribeManaged(implicit trace: Trace): ZManaged[Any, Nothing, TDequeue[A]] =
      ZManaged.scoped(self.subscribeScoped)
  }

  implicit final class ZManagedTSemaphoreSyntax(private val self: TSemaphore) extends AnyVal {

    /**
     * Returns a managed effect that describes acquiring a permit as the
     * `acquire` action and releasing it as the `release` action.
     */
    def withPermitManaged(implicit trace: Trace): ZManaged[Any, Nothing, Unit] =
      ZManaged.scoped(self.withPermitScoped)

    /**
     * Returns a managed effect that describes acquiring the specified number of
     * permits as the `acquire` action and releasing them as the `release`
     * action.
     */
    def withPermitsManaged(n: Long)(implicit trace: Trace): ZManaged[Any, Nothing, Unit] =
      ZManaged.scoped(self.withPermitsScoped(n))
  }

  implicit final class ZManagedZChannelSyntax[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone](
    private val self: ZChannel[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone]
  ) extends AnyVal {

    def runManaged(implicit
      ev1: Any <:< InElem,
      ev2: OutElem <:< Nothing,
      trace: Trace
    ): ZManaged[Env, OutErr, OutDone] =
      ZManaged.scoped[Env](self.runScoped)
  }

  implicit final class ZManagedZChannelCompanionSyntax(private val self: ZChannel.type) extends AnyVal {

    def managed[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone, A](m: => ZManaged[Env, OutErr, A])(
      use: A => ZChannel[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone]
    )(implicit trace: Trace): ZChannel[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone] =
      ZChannel.unwrapScoped[Env](m.scoped.map(use))

    def managedOut[R, E, A](
      m: => ZManaged[R, E, A]
    )(implicit trace: Trace): ZChannel[R, Any, Any, Any, E, A, Any] =
      ZChannel.scoped[R](m.scoped)

    def unwrapManaged[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone](
      channel: => ZManaged[Env, OutErr, ZChannel[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone]]
    )(implicit
      trace: Trace
    ): ZChannel[Env, InErr, InElem, InDone, OutErr, OutElem, OutDone] =
      ZChannel.unwrapScoped[Env](channel.scoped)
  }

  implicit final class ZManagedZSinkCompanionSyntax(private val self: ZSink.type) extends AnyVal {

    /**
     * Creates a sink produced from a managed effect.
     */
    def unwrapManaged[R, E, In, L, Z](managed: => ZManaged[R, E, ZSink[R, E, In, L, Z]])(implicit
      trace: Trace
    ): ZSink[R, E, In, L, Z] =
      ZSink.unwrapScoped[R](managed.scoped)
  }

  implicit final class ZManagedZStreamSyntax[R, E, A](private val self: ZStream[R, E, A]) extends AnyVal {

    /**
     * Executes a pure fold over the stream of values. Returns a managed value
     * that represents the scope of the stream.
     */
    final def runFoldManaged[S](s: => S)(f: (S, A) => S)(implicit trace: Trace): ZManaged[R, E, S] =
      ZManaged.scoped[R](self.runFoldScoped(s)(f))

    /**
     * Executes an effectful fold over the stream of values. Returns a managed
     * value that represents the scope of the stream.
     */
    final def runFoldManagedZIO[R1 <: R, E1 >: E, S](s: => S)(f: (S, A) => ZIO[R1, E1, S])(implicit
      trace: Trace
    ): ZManaged[R1, E1, S] =
      ZManaged.scoped[R1](self.runFoldScopedZIO[R1, E1, S](s)(f))

    /**
     * Executes an effectful fold over the stream of values. Returns a managed
     * value that represents the scope of the stream. Stops the fold early when
     * the condition is not fulfilled. Example:
     * {{{
     *   Stream(1)
     *     .fold(0)(_ <= 4)((s, a) => ZIO.succeed(s + a))  // Managed[Nothing, Int]
     *     .use(ZIO.succeed)                               // UIO[Int] == 5
     * }}}
     *
     * @param cont
     *   function which defines the early termination condition
     */
    final def runFoldWhileManagedZIO[R1 <: R, E1 >: E, S](
      s: => S
    )(cont: S => Boolean)(f: (S, A) => ZIO[R1, E1, S])(implicit trace: Trace): ZManaged[R1, E1, S] =
      ZManaged.scoped[R1](self.runFoldWhileScopedZIO[R1, E1, S](s)(cont)(f))

    /**
     * Executes a pure fold over the stream of values. Returns a managed value
     * that represents the scope of the stream. Stops the fold early when the
     * condition is not fulfilled.
     */
    final def runFoldWhileManaged[S](s: => S)(cont: S => Boolean)(f: (S, A) => S)(implicit
      trace: Trace
    ): ZManaged[R, E, S] =
      ZManaged.scoped[R](self.runFoldWhileScoped(s)(cont)(f))

    /**
     * Like [[ZStream#runForeachChunk]], but returns a scoped `ZIO` so the
     * finalization order can be controlled.
     */
    final def runForeachChunkManaged[R1 <: R, E1 >: E](f: Chunk[A] => ZIO[R1, E1, Any])(implicit
      trace: Trace
    ): ZManaged[R1, E1, Unit] =
      ZManaged.scoped[R1](self.runForeachChunkScoped(f))

    /**
     * Like [[ZStream#foreach]], but returns a `ZManaged` so the finalization
     * order can be controlled.
     */
    final def runForeachScoped[R1 <: R, E1 >: E](f: A => ZIO[R1, E1, Any])(implicit
      trace: Trace
    ): ZManaged[R1, E1, Unit] =
      ZManaged.scoped[R1](self.runForeachScoped(f))

    /**
     * Like [[ZStream#runForeachWhile]], but returns a scoped `ZIO` so the
     * finalization order can be controlled.
     */
    final def runForeachWhileManaged[R1 <: R, E1 >: E](f: A => ZIO[R1, E1, Boolean])(implicit
      trace: Trace
    ): ZManaged[R1, E1, Unit] =
      ZManaged.scoped[R1](self.runForeachWhileScoped(f))

    /**
     * Like [[ZStream#runIntoHub]], but provides the result as a [[ZManaged]] to
     * allow for scope composition.
     */
    final def runIntoHubManaged[E1 >: E, A1 >: A](
      hub: => Hub[Take[E1, A1]]
    )(implicit trace: Trace): ZManaged[R, E1, Unit] =
      ZManaged.scoped[R](self.runIntoHubScoped(hub))

    /**
     * Like [[ZStream#runIntoQueue]], but provides the result as a [[ZManaged]]
     * to allow for scope composition.
     */
    final def runIntoQueueManaged(
      queue: => Enqueue[Take[E, A]]
    )(implicit trace: Trace): ZManaged[R, E, Unit] =
      ZManaged.scoped[R](self.runIntoQueueScoped(queue))

    /**
     * Like [[ZStream#runIntoQueue]], but provides the result as a [[ZManaged]]
     * to allow for scope composition.
     */
    final def runIntoQueueElementsManaged(
      queue: => Enqueue[Exit[Option[E], A]]
    )(implicit trace: Trace): ZManaged[R, E, Unit] =
      ZManaged.scoped[R](self.runIntoQueueElementsScoped(queue))

    def runManaged[R1 <: R, E1 >: E, B](sink: => ZSink[R1, E1, A, Any, B])(implicit
      trace: Trace
    ): ZManaged[R1, E1, B] =
      ZManaged.scoped[R1](self.runScoped(sink))
  }

  implicit final class ZManagedZStreamCompanionSyntax(private val self: ZStream.type) extends AnyVal {

    /**
     * Creates a stream from a subscription to a hub in the context of a managed
     * effect. The managed effect describes subscribing to receive messages from
     * the hub while the stream describes taking messages from the hub.
     */
    def fromChunkHubManaged[O](
      hub: => Hub[Chunk[O]]
    )(implicit trace: Trace): ZManaged[Any, Nothing, ZStream[Any, Nothing, O]] =
      ZManaged.scoped(ZStream.fromChunkHubScoped(hub))

    /**
     * Creates a stream from a subscription to a hub in the context of a managed
     * effect. The managed effect describes subscribing to receive messages from
     * the hub while the stream describes taking messages from the hub.
     *
     * The hub will be shut down once the stream is closed.
     */
    def fromChunkHubManagedWithShutdown[O](
      hub: => Hub[Chunk[O]]
    )(implicit trace: Trace): ZManaged[Any, Nothing, ZStream[Any, Nothing, O]] =
      ZManaged.scoped(ZStream.fromChunkHubScopedWithShutdown(hub))

    /**
     * Creates a stream from a subscription to a hub in the context of a managed
     * effect. The managed effect describes subscribing to receive messages from
     * the hub while the stream describes taking messages from the hub.
     */
    def fromHubManaged[A](
      hub: => Hub[A],
      maxChunkSize: => Int = ZStream.DefaultChunkSize
    )(implicit trace: Trace): ZManaged[Any, Nothing, ZStream[Any, Nothing, A]] =
      ZManaged.scoped(ZStream.fromHubScoped(hub, maxChunkSize))

    /**
     * Creates a stream from a subscription to a hub in the context of a managed
     * effect. The managed effect describes subscribing to receive messages from
     * the hub while the stream describes taking messages from the hub.
     *
     * The hub will be shut down once the stream is closed.
     */
    def fromHubManagedWithShutdown[A](
      hub: => Hub[A],
      maxChunkSize: => Int = ZStream.DefaultChunkSize
    )(implicit trace: Trace): ZManaged[Any, Nothing, ZStream[Any, Nothing, A]] =
      ZManaged.scoped(ZStream.fromHubScopedWithShutdown(hub, maxChunkSize))

    /**
     * Creates a stream from a managed `java.io.InputStream` value.
     */
    def fromInputStreamManaged[R](
      is: => ZManaged[R, IOException, InputStream],
      chunkSize: => Int = ZStream.DefaultChunkSize
    )(implicit trace: Trace): ZStream[R, IOException, Byte] =
      ZStream.fromInputStreamScoped[R](is.scoped, chunkSize)

    /**
     * Creates a stream from a managed iterator
     */
    def fromIteratorManaged[R, A](
      iterator: => ZManaged[R, Throwable, Iterator[A]],
      maxChunkSize: => Int = ZStream.DefaultChunkSize
    )(implicit
      trace: Trace
    ): ZStream[R, Throwable, A] =
      ZStream.fromIteratorScoped[R, A](iterator.scoped, maxChunkSize)

    /**
     * Creates a stream from a managed iterator
     */
    def fromJavaIteratorManaged[R, A](iterator: => ZManaged[R, Throwable, java.util.Iterator[A]])(implicit
      trace: Trace
    ): ZStream[R, Throwable, A] =
      fromJavaIteratorManaged(iterator, ZStream.DefaultChunkSize)

    /**
     * Creates a stream from a managed iterator
     */
    def fromJavaIteratorManaged[R, A](
      iterator: => ZManaged[R, Throwable, java.util.Iterator[A]],
      chunkSize: Int
    )(implicit
      trace: Trace
    ): ZStream[R, Throwable, A] =
      ZStream.fromJavaIteratorScoped[R, A](iterator.scoped, chunkSize)

    def managed[R, E, A](managed: => ZManaged[R, E, A])(implicit trace: Trace): ZStream[R, E, A] =
      ZStream.scoped[R](managed.scoped)

    def unwrapScoped[R, E, A](fa: => ZManaged[R, E, ZStream[R, E, A]])(implicit
      trace: Trace
    ): ZStream[R, E, A] =
      ZStream.unwrapScoped[R](fa.scoped)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy