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

com.evolutiongaming.kafka.journal.util.ResourceRef.scala Maven / Gradle / Ivy

The newest version!
package com.evolutiongaming.kafka.journal.util

import cats.effect.concurrent.Ref
import cats.effect.implicits._
import cats.effect.{Resource, Sync}
import cats.syntax.all._

import scala.util.control.NoStackTrace

trait ResourceRef[F[_], A] {

  def get: F[A]

  def set(a: A, release: F[Unit]): F[Unit]

  def set(a: Resource[F, A]): F[Unit]
}

object ResourceRef {

  def of[F[_] : Sync, A](resource: Resource[F, A]): Resource[F, ResourceRef[F, A]] = {

    case class State(a: A, release: F[Unit])

    Resource
      .make {
        for {
          ab           <- resource.allocated
          (a, release)  = ab
          ref          <- Ref[F].of(State(a, release).some)
        } yield ref
      } { ref =>
        ref
          .getAndSet(none)
          .flatMap { _.foldMapM { _.release } }
      }
      .map { ref =>
        new ResourceRef[F, A] {

          def get = {
            ref
              .get
              .flatMap {
                case Some(state) => state.a.pure[F]
                case None        => ResourceReleasedError.raiseError[F, A]
              }
          }

          def set(a: A, release: F[Unit]) = {
            ref
              .modify {
                case Some(state) => (State(a, release).some, state.release )
                case None        => (none, ResourceReleasedError.raiseError[F, Unit])
              }
              .flatten
              .uncancelable
          }

          def set(a: Resource[F, A]) = {
            a
              .allocated
              .flatMap { case (a, release) => set(a, release) }
          }
        }
      }
  }
}

case object ResourceReleasedError extends RuntimeException("Resource released") with NoStackTrace




© 2015 - 2024 Weber Informatics LLC | Privacy Policy