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

almond.interpreter.util.Cancellable.scala Maven / Gradle / Ivy

There is a newer version: 0.6.0
Show newest version
package almond.interpreter.util

import cats.effect.IO

import scala.util.{Failure, Success}

/**
  * Handles cancellation of prior running requests, in case a new one is incoming.
  *
  * This only applies if `asyncOpt` returns non-empty results, meaning [[B]] is asynchronously calculated,
  * and that this calculation can be stopped. If a new request arrives, [[CancellableFuture.cancel]] is
  * called on previous requests that are still running.
  */
final class Cancellable[A, B](
  sync: A => IO[B],
  asyncOpt: A => Option[CancellableFuture[B]]
) {

  private var runningCompletionOpt = Option.empty[CancellableFuture[B]]
  private val runningCompletionLock = new Object

  def run(a: A): IO[B] = {

    val ioOrFutureCompletion =
      runningCompletionLock.synchronized {

        for (c <- runningCompletionOpt) {
          c.cancel()
          runningCompletionOpt = None
        }

        asyncOpt(a) match {
          case None =>
            Left(sync(a))
          case Some(f) =>
            runningCompletionOpt = Some(f)
            Right(f)
        }
      }

    ioOrFutureCompletion match {
      case Left(io) => io
      case Right(f) =>
        IO.async[B] { cb =>
          import scala.concurrent.ExecutionContext.Implicits.global // meh
          f.future.onComplete { res =>
            runningCompletionLock.synchronized {
              runningCompletionOpt = runningCompletionOpt.filter(_ != f)
            }
            res match {
              case Success(c) =>
                cb(Right(c))
              case Failure(e) =>
                cb(Left(e))
            }
          }
        }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy