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

loci.runtime.Dispatcher.scala Maven / Gradle / Ivy

The newest version!
package loci
package runtime

import scala.collection.mutable
import scala.concurrent.ExecutionContext
import scala.util.control.NonFatal

trait Dispatch[D <: Dispatch[D]] extends Runnable {
  def blockedBy(dispatch: D): Boolean

  final def blockedBy(dispatches: compatibility.IterableOnce[D]): Boolean =
    compatibility.iterable.exists(dispatches) { blockedBy }
}

trait Undispatchable[D <: Dispatch[D]] { this: Dispatch[D] =>
  final def blockedBy(dispatch: D) = false
  final def run() = { }
}

class Dispatcher[D <: Dispatch[D]](implicit context: ExecutionContext) {
  private val dispatches = mutable.ListBuffer.empty[(D, Boolean)]

  def dispatch(dispatch: D*): Unit = dispatches synchronized {
    dispatch foreach { dispatches += _ -> false }
    next(Seq.empty)
  }

  def ignoreDispatched(dispatch: D*): Unit = dispatches synchronized {
    dispatch foreach { dispatches -= _ -> false }
    next(Seq.empty)
  }

  private def next(executed: compatibility.Iterable[D]): Unit = dispatches synchronized {
    executed foreach { dispatches -= _ -> true }

    val pendings = dispatches collect { case (dispatch, true) => dispatch }

    val dispatchings = mutable.ListBuffer.empty[mutable.ListBuffer[D]]

    compatibility.listBuffer.mapInPlace(dispatches) { case (dispatch, running) =>
      dispatch match {
        case _: Undispatchable[_] =>
          pendings += dispatch
          dispatch -> false

        case _ =>
          if (!running) {
            if (!(dispatch blockedBy pendings)) {
              dispatchings filter dispatch.blockedBy match {
                case mutable.ListBuffer() =>
                  dispatchings += mutable.ListBuffer(dispatch)
                  dispatch -> true

                case mutable.ListBuffer(dispatching) =>
                  dispatching += dispatch
                  dispatch -> true

                case _ =>
                  pendings += dispatch
                  dispatch -> false
              }
            }
            else {
              pendings += dispatch
              dispatch -> false
            }
          }
          else
            dispatch -> true
      }
    }

    dispatchings foreach { dispatching =>
      context.execute(new Runnable {
        def run() = {
          var throwable: Throwable = null

          dispatching foreach { dispatch =>
            try dispatch.run()
            catch {
              case NonFatal(exception) =>
                if (throwable == null)
                  throwable = exception
                else
                  throwable.addSuppressed(exception)
            }
          }

          next(dispatching)

          if (throwable != null)
            throw throwable
        }
      })
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy