aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/concurrency/atom.lux
blob: c879db02d26d01de5591be9c865990be3382b776 (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
42
43
44
45
46
47
48
49
##  Copyright (c) Eduardo Julian. All rights reserved.
##  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
##  If a copy of the MPL was not distributed with this file,
##  You can obtain one at http://mozilla.org/MPL/2.0/.

(;module:
  lux
  (lux [io #- run]
       host))

(jvm-import (java.util.concurrent.atomic.AtomicReference V)
  (new [V])
  (compareAndSet [V V] boolean)
  (get [] V))

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

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

(def: #export (get atom)
  (All [a] (-> (Atom a) (IO a)))
  (io (AtomicReference.get [] 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 wasn't updated since you last read from it."}
  (All [a] (-> a a (Atom a) (IO Bool)))
  (io (AtomicReference.compareAndSet [current new] atom)))

(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 Unit)))
  (io (let [old (AtomicReference.get [] atom)]
        (if (AtomicReference.compareAndSet [old (f old)] atom)
          []
          (io;run (update f atom))))))

(def: #export (set value atom)
  (All [a] (-> a (Atom a) (IO Unit)))
  (update (lambda [_] value) atom))