himilsbach0.1.0A tiny actor library for Clojure dependencies
| (this space intentionally left almost blank) | ||||||
(ns himilsbach.core
(use [clojure.core.match :only [match]])
(import java.util.concurrent.Semaphore
java.util.concurrent.ConcurrentLinkedQueue)) | |||||||
Internal use only. Please don't touch. | (def -kill-order (Object.)) | ||||||
Creates a new actor. It has to be explicitly started with the `start' function. Takes a set of pattern/callback pairs. If a message sent to the actor matches a given pattern the respective callback is evaluated with binding specified in the pattern. In scopes of all callbacks following special vars are defined.
Pattern/callback pairs can be preceded with a single argument specifying an actor to be notified when this actor throws an exception. The notified actor will receive a message [:error other ex], where `other' is the actor which thrown exception `ex'. See `clojure.core.match/match' for details regarding pattern matching. | (defmacro new
[& body]
(let [msg (gensym)]
`(let [inbox# (ConcurrentLinkedQueue.)
sem# (Semaphore. 0)
fun# (fn [~msg]
(let [~'self [inbox# sem#]
~'die (fn [] -kill-order)]
~(if (odd? (count body))
`(try
(match
~msg
~@(rest body))
(catch Throwable ex#
(send! ~(first body) :error ~'self ex#)
(~'die)))
`(match
~msg
~@body))))]
[inbox# sem# fun#]))) | ||||||
Sends a message to a given actor. | (defn send! [[^ConcurrentLinkedQueue inbox ^Semaphore sem _] & msg] (.add inbox (vec msg)) (.release sem)) | ||||||
(defn- inbox-pop [[^ConcurrentLinkedQueue inbox ^Semaphore sem _]] (.acquire sem) (.poll inbox)) | |||||||
Starts the actor created with `new' in a new future. Immediately returns nil. | (defn start
[actor]
(future
(let [[_ _ f] actor]
(loop []
(when-not (= -kill-order (f (inbox-pop actor)))
(recur)))))
nil) | ||||||
Returns the unique identifier of a given actor. | (let [ids (ref {})]
(defn id
[[inbox & _]]
(dosync
(if-let [id (@ids inbox)]
id
(let [sym (gensym 'actor_)]
(ref-set ids (conj @ids [inbox sym]))
sym))))) | ||||||
Returns true if any message in the inbox of the given actor matches the given pattern. | (defmacro any-matching? [actor pattern] `(some #(match % ~pattern true) (first ~actor))) | ||||||