Add rswap!

Works just like swap!, except that it allows recursive swaps on
the same atom, and it always returns nil.
This commit is contained in:
Dan Holmsand 2015-09-14 19:35:48 +02:00
parent 8e7624ea45
commit e11c881aa7
2 changed files with 45 additions and 0 deletions

View File

@ -277,6 +277,27 @@ another cursor) these cursors are equivalent:
;; Utilities
(defn rswap!
"Swaps the value of a to be (apply f current-value-of-atom args).
rswap! works like swap!, except that recursive calls to rswap! on
the same atom are allowed and it always returns nil."
[a f & args]
{:pre [(satisfies? IAtom a)
(ifn? f)]}
(if a.rswapping
(-> (or a.rswapfs (set! a.rswapfs (array)))
(.push #(apply f % args)))
(do (set! a.rswapping true)
(try (swap! a (fn [state]
(loop [s (apply f state args)]
(if-some [sf (some-> a.rswapfs .shift)]
(recur (sf s))
s))))
(finally
(set! a.rswapping false)))))
nil)
(defn next-tick
"Run f using requestAnimationFrame or equivalent."
[f]

View File

@ -265,3 +265,27 @@
(set! rv/silent false)
(dispose c)
(is (= runs (running)))))
(deftest test-rswap
(let [a (atom {:foo 1})]
(r/rswap! a update-in [:foo] inc)
(is (= (:foo @a) 2))
(r/rswap! a #(assoc %1 :foo %2) 3)
(is (= (:foo @a) 3))
(r/rswap! a #(assoc %1 :foo %3) 0 4)
(is (= (:foo @a) 4))
(r/rswap! a #(assoc %1 :foo %4) 0 0 5)
(is (= (:foo @a) 5))
(r/rswap! a #(assoc %1 :foo %5) 0 0 0 6)
(is (= (:foo @a) 6))
(let [disp (atom nil)
f (fn [o v]
(assert (= v :add))
(if (< (:foo o) 10)
(do
(@disp v)
(update-in o [:foo] inc))
o))
_ (reset! disp #(r/rswap! a f %))]
(@disp :add)
(is (= (:foo @a) 10)))))