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
open Opentelemetry_atomic
module Int_map = Map.Make (struct
type t = int
let compare = compare
end)
type cb = unit -> unit
type state =
| On of {
n: int;
m: cb Int_map.t; (** removable callbacks *)
l: cb list;
}
| Off
type t = { st: state Atomic.t } [@@unboxed]
type trigger = t
let dummy : t = { st = Atomic.make Off }
let on_turn_off (self : t) (f : cb) : unit =
let must_fire =
Util_atomic.update_cas self.st @@ function
| Off -> true, Off
| On r -> false, On { r with l = f :: r.l }
in
if must_fire then f ()
let turn_off' self =
match Atomic.exchange self.st Off with
| Off -> `Was_off
| On { l; m; n = _ } ->
List.iter (fun f -> f ()) l;
Int_map.iter (fun _ f -> f ()) m;
`Was_on
let[@inline] turn_off self = ignore (turn_off' self : [> `Was_on ])
let[@inline] link parent tr : unit = on_turn_off parent (fun () -> turn_off tr)
let create ?parent () : t * trigger =
let self = { st = Atomic.make (On { l = []; n = 0; m = Int_map.empty }) } in
Option.iter (fun p -> link p self) parent;
self, self
let[@inline] is_on self : bool =
match Atomic.get self.st with
| On _ -> true
| Off -> false
let[@inline] is_off self = not (is_on self)
let show self = Printf.sprintf "<switch on=%B>" (is_on self)
let pp out self = Format.fprintf out "<switch on=%B>" (is_on self)
module Unsafe = struct
let trigger_of_switch = Fun.id
end