aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/control/concurrency/atom.lux
blob: 6309f4f35630057a539af71e77c8e69af3d29fdb (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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
(.module:
  [library
   [lux "*"
    ["@" target]
    ["[0]" ffi]
    [abstract
     [monad {"+" [do]}]]
    [control
     ["[0]" function]
     ["[0]" io {"+" [IO]} ("[1]\[0]" functor)]]
    [data
     ["[0]" product]
     [collection
      ["[0]" array]]]
    [type
     abstract]]])

(with_expansions [<jvm> (as_is (ffi.import: (java/util/concurrent/atomic/AtomicReference a)
                                 ["[1]::[0]"
                                  (new [a])
                                  (get [] a)
                                  (compareAndSet [a a] boolean)]))]
  (for {@.old <jvm>
        @.jvm <jvm>}
       (as_is)))

(with_expansions [<new> (for {@.js "js array new"
                              @.python "python array new"
                              @.lua "lua array new"
                              @.ruby "ruby array new"
                              @.php "php array new"
                              @.scheme "scheme array new"}
                             (as_is))
                  <write> (for {@.js "js array write"
                                @.python "python array write"
                                @.lua "lua array write"
                                @.ruby "ruby array write"
                                @.php "php array write"
                                @.scheme "scheme array write"}
                               (as_is))
                  
                  <read> (for {@.js "js array read"
                               @.python "python array read"
                               @.lua "lua array read"
                               @.ruby "ruby array read"
                               @.php "php array read"
                               @.scheme "scheme array read"}
                              (as_is))]
  (abstract: .public (Atom a)
    (with_expansions [<jvm> (java/util/concurrent/atomic/AtomicReference a)]
      (for {@.old <jvm>
            @.jvm <jvm>}
           (array.Array a)))

    [(def: .public (atom value)
       (All (_ a) (-> a (Atom a)))
       (:abstraction (with_expansions [<jvm> (java/util/concurrent/atomic/AtomicReference::new value)]
                       (for {@.old <jvm>
                             @.jvm <jvm>}
                            (<write> 0 value (<new> 1))))))

     (def: .public (read! atom)
       (All (_ a) (-> (Atom a) (IO a)))
       (io.io (with_expansions [<jvm> (java/util/concurrent/atomic/AtomicReference::get (:representation atom))]
                (for {@.old <jvm>
                      @.jvm <jvm>}
                     (<read> 0 (:representation atom))))))

     (def: .public (compare_and_swap! current new atom)
       (All (_ a) (-> a a (Atom a) (IO Bit)))
       (io.io (with_expansions [<jvm> (java/util/concurrent/atomic/AtomicReference::compareAndSet current new (:representation atom))]
                (for {@.old <jvm>
                      @.jvm <jvm>}
                     (let [old (<read> 0 (:representation atom))]
                       (if (same? old current)
                         (exec (<write> 0 new (:representation atom))
                           true)
                         false))))))]
    ))

(def: .public (update! f atom)
  (All (_ a) (-> (-> a a) (Atom a) (IO [a a])))
  (loop [_ []]
    (do io.monad
      [old (read! atom)
       .let [new (f old)]
       swapped? (compare_and_swap! old new atom)]
      (if swapped?
        (in [old new])
        (recur [])))))

(def: .public (write! value atom)
  (All (_ a) (-> a (Atom a) (IO a)))
  (|> atom
      (..update! (function.constant value))
      (io\each product.left)))