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

japgolly.webapputil.locks.AbstractSharedLock.scala Maven / Gradle / Ivy

There is a newer version: 2.0.0-RC12
Show newest version
package japgolly.webapputil.locks

import japgolly.scalajs.react.callback.AsyncCallback
import japgolly.webapputil.general.Effect
import java.util.concurrent.TimeUnit
import scala.concurrent.duration.FiniteDuration

trait AbstractSharedLock extends GenericSharedLock.Safe.Default[AsyncCallback] {
  protected def unsafeRelease(): Unit
  /** @return await if already locked */
  protected def unsafeTryAcquire(): Option[AsyncCallback[Unit]]

  protected final type Locked =
    GenericSharedLock.Safe.Locked[AsyncCallback]

  override final protected def F: Effect[AsyncCallback] =
    implicitly

  private val locked: Locked =
    GenericSharedLock.Safe.Locked(F.delay {
      unsafeRelease()
    })

  private def acquire[A](onLock: AsyncCallback[A], onAwait: Option[AsyncCallback[A]]): AsyncCallback[A] = {
    lazy val self: AsyncCallback[A] =
      F.suspend {
        unsafeTryAcquire() match {

          case None =>
            // Lock acquired
            onLock

          case Some(await) =>
            // Mutex in use
            onAwait.getOrElse(F.flatMap(await)(_ => self))
        }
      }
    self
  }

  override val lock: AsyncCallback[Locked] =
    acquire[Locked](
      onLock = F.pure(locked),
      onAwait = None,
    )

  override val lockInterruptibly: AsyncCallback[Locked] =
    lock

  override val tryLock: AsyncCallback[Option[Locked]] =
    acquire[Option[Locked]](
      onLock = F.pure(Some(locked)),
      onAwait = Some(F.pure(None)),
    )

  override def tryLock(time: Long, unit: TimeUnit): AsyncCallback[Option[Locked]] =
    F.suspend {
      type X = AsyncCallback[Option[Locked]]
      var allowRun = true
      val timer: X = AsyncCallback.delay {allowRun = false; None}.delay(FiniteDuration(time, unit))
      val run: X = F.flatMap(lock) { l =>
        if (allowRun)
          F.pure(Some(l))
        else
          F.map(l.unlock)(_ => None)
      }
      timer.race(run).map(_.merge)
    }

  /** not re-entrant */
  override def apply[A](fa: AsyncCallback[A]): AsyncCallback[A] =
    F.flatMap(lock)(l => fa.finallyRun(l.unlock))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy