aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/concurrency/atom.lux
blob: c60edd01eaade655ebbdcd636d5ebb80c9c9f105 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(.module:
  lux
  (lux [function]
       [io #- run]))

(type: #export (Atom a)
  {#.doc "Atomic references that are safe to mutate concurrently."}
  (#.Primitive "#Atom" (#.Cons a #.Nil)))

(def: #export (atom value)
  (All [a] (-> a (Atom a)))
  ("lux atom new" value))

(def: #export (read atom)
  (All [a] (-> (Atom a) (IO a)))
  (io ("lux atom read" atom)))

(def: #export (compare-and-swap current new atom)
  {#.doc "Only mutates an atom if you can present it's current value.

          That guarantees that atom was not updated since you last read from it."}
  (All [a] (-> a a (Atom a) (IO Bool)))
  (io ("lux atom compare-and-swap" atom current new)))

(def: #export (update f atom)
  {#.doc "Updates an atom by applying a function to its current value.

          If it fails to update it (because some other process wrote to it first), it will retry until it succeeds.

          The retries will be done with the new values of the atom, as they show up."}
  (All [a] (-> (-> a a) (Atom a) (IO a)))
  (io (loop [_ []]
        (let [old ("lux atom read" atom)
              new (f old)]
          (if ("lux atom compare-and-swap" atom old new)
            new
            (recur []))))))

(def: #export (write value atom)
  (All [a] (-> a (Atom a) (IO Top)))
  (update (function.const value) atom))