diff --git a/pixie/stdlib.pxi b/pixie/stdlib.pxi index 6c908a82..6070f410 100644 --- a/pixie/stdlib.pxi +++ b/pixie/stdlib.pxi @@ -3110,3 +3110,15 @@ ex: (vary-meta x assoc :foo 42)" :added "0.1"} [f x] (->Iterate f x)) + +(defn compare-and-set! + {:doc "Atomically sets the value of the atom to newval iff the current value of atom is oldval. + Returns true if reset happens, else false." + :signatures [[atom oldval newval]] + :added "0.2"} + [atom oldval newval] + (if (= @atom oldval) + (do + (reset! atom newval) + true) + false) diff --git a/pixie/vm/atom.py b/pixie/vm/atom.py index 28254673..e21f2dfe 100644 --- a/pixie/vm/atom.py +++ b/pixie/vm/atom.py @@ -13,18 +13,28 @@ def with_meta(self, meta): def meta(self): return self._meta - def __init__(self, boxed_value, meta=nil): + def with_watch(self, watch_key, watch_fn): + return Atom(self._boxed_value, + self._meta, + watch_key, + watch_fn) + + def __init__(self, boxed_value, + meta=nil, + watch_key=nil, watch_fn=nil): self._boxed_value = boxed_value self._meta = meta - + self._watch_key = watch_key + self._watch_fn = watch_fn @extend(proto._reset_BANG_, Atom) def _reset(self, v): assert isinstance(self, Atom) + if self._watch_fn is not nil: + self._watch_fn.invoke([self._watch_key, self, self._boxed_value, v]) self._boxed_value = v return v - @extend(proto._deref, Atom) def _deref(self): assert isinstance(self, Atom) @@ -40,6 +50,11 @@ def _with_meta(self, meta): assert isinstance(self, Atom) return self.with_meta(meta) +@extend(proto._with_watch, Atom) +def _with_watch(self, watch_key, watch_fn): + assert isinstance(self, Atom) + return self.with_watch(watch_key, watch_fn) + @as_var("atom") def atom(val=nil): return Atom(val) diff --git a/pixie/vm/stdlib.py b/pixie/vm/stdlib.py index d8611d72..ed8a49d6 100644 --- a/pixie/vm/stdlib.py +++ b/pixie/vm/stdlib.py @@ -63,6 +63,9 @@ defprotocol("pixie.stdlib", "IMessageObject", ["-call-method", "-get-attr"]) +defprotocol("pixie.stdlib", "IWatch", ["-with-watch"]) +defprotocol("pixie.stdlib", "IValidate", ["-with-validator"]) + def maybe_mark_finalizer(self, tp): if self is _finalize_BANG_: print "MARKING ", tp @@ -278,6 +281,10 @@ def __meta(a): def __with_meta(a, b): return rt._with_meta(a, b) +@as_var("with-watch") +def __with_watch(a, b, c): + return rt._with_watch(a, b, c) + @returns(bool) @as_var("has-meta?") def __has_meta(a):