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))) | ||||||