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

scalaz.concurrent.Actor.scala Maven / Gradle / Ivy

The newest version!
package org.specs2.internal.scalaz
package concurrent

import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.ConcurrentLinkedQueue

/**
 * Processes messages of type `A` sequentially. Messages are submitted to
 * the actor with the method `!`. Processing is typically performed asynchronously,
 * this is controlled by the provided `strategy`.
 *
 * @see scalaz.concurrent.Promise
 *
 * @param handler  The message handler
 * @param onError  Exception handler, called if the message handler throws any `Throwable`.
 * @param strategy Execution strategy, for example, a strategy that is backed by an `ExecutorService`
 * @tparam A       The type of messages accepted by this actor.
 */
final case class Actor[A](handler: A => Unit, onError: Throwable => Unit = throw(_))
                         (implicit val strategy: Strategy) {
  self =>

  private val suspended = new AtomicBoolean(true)
  private val mbox = new ConcurrentLinkedQueue[A]

  val toEffect: Run[A] = Run[A]((a) => this ! a)

  /** Alias for `apply` */
  def !(a: A) {
    mbox offer a
    work
  }

  /** Pass the message `a` to the mailbox of this actor */
  def apply(a: A) {
    this ! a
  }

  def contramap[B](f: B => A): Actor[B] =
    Actor[B]((b: B) => (this ! f(b)), onError)(strategy)

  private def work {
    if (!mbox.isEmpty && suspended.compareAndSet(true, false))
      strategy(act)
  }

  private def act {
    var i = 0
    val batchSize = 1000
    while (i < batchSize) {
      val m = mbox.poll
      if (m != null) try {
        handler(m)
        i = i + 1
      } catch {
        case ex => onError(ex)
      }
      else i = batchSize
    }
    suspended.set(true)
    work
  }
}

object Actor extends ActorFunctions with ActorInstances

trait ActorInstances {
  implicit def actorContravariant: Contravariant[Actor] = new Contravariant[Actor] {
    def contramap[A, B](r: Actor[A])(f: (B) => A): Actor[B] = r contramap f
  }
}

trait ActorFunctions {
  def actor[A](e: A => Unit, err: Throwable => Unit = throw (_))(implicit s: Strategy): Actor[A] =
    Actor[A](e, err)

  implicit def ToFunctionFromActor[A](a: Actor[A]): A => Unit = a ! _
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy