Source file mutable_outputs.ml
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
open! Core
open Async_kernel
open! Import
module State = struct
type t =
{ default_outputs : Output.t list
; named_outputs : Output.t Output_name.Map.t
; previous_outputs_flushed : unit Deferred.t
; stop_watching_for_background_errors : unit Ivar.t
}
[@@deriving fields ~getters ~iterators:create]
let all_outputs { default_outputs; named_outputs; _ } =
default_outputs @ Map.data named_outputs
;;
let watch_for_background_errors t ~stop ~on_background_output_error:on_error =
List.iter (all_outputs t) ~f:(fun output ->
match Output.Private.buffered_background_error output with
| `Error e -> don't_wait_for (choose [ choice stop Fn.id; choice e on_error ])
| `Output_is_unbuffered -> ())
;;
let flushed t =
let open Eager_deferred.Use in
let%bind () = t.previous_outputs_flushed in
Deferred.List.iter (all_outputs t) ~how:`Sequential ~f:Output.flush
;;
let create ~default_outputs ~named_outputs ~previous ~on_background_output_error =
let stop_watching_for_background_errors = Ivar.create () in
let previous_outputs_flushed =
match previous with
| None -> Deferred.unit
| Some previous ->
let%map.Eager_deferred () = flushed previous in
Ivar.fill_if_empty previous.stop_watching_for_background_errors ()
in
let t =
{ default_outputs
; named_outputs
; previous_outputs_flushed
; stop_watching_for_background_errors
}
in
watch_for_background_errors
t
~stop:(Ivar.read stop_watching_for_background_errors)
~on_background_output_error;
t
;;
let is_empty t = t |> all_outputs |> List.is_empty
let write t msg =
t |> all_outputs |> List.iter ~f:(fun output -> Output.write output msg)
;;
end
type t =
{ mutable state : State.t
; mutable last_update : [ `Flush of unit Deferred.t | `Not_a_flush ]
; on_background_output_error : exn -> unit
}
let create ~default_outputs ~named_outputs ~on_background_output_error =
{ state =
State.create
~default_outputs
~named_outputs
~previous:None
~on_background_output_error
; last_update = `Not_a_flush
; on_background_output_error
}
;;
let is_empty t = State.is_empty t.state
let write t =
t.last_update <- `Not_a_flush;
State.write t.state
;;
let flushed t =
match t.last_update with
| `Flush flush -> flush
| `Not_a_flush ->
let flush = State.flushed t.state in
t.last_update <- `Flush flush;
flush
;;
let update_default_outputs t outputs =
t.last_update <- `Not_a_flush;
t.state
<- State.create
~default_outputs:outputs
~named_outputs:t.state.named_outputs
~previous:(Some t.state)
~on_background_output_error:t.on_background_output_error
;;
let update_named_outputs t named_outputs =
t.last_update <- `Not_a_flush;
t.state
<- State.create
~default_outputs:t.state.default_outputs
~named_outputs
~previous:(Some t.state)
~on_background_output_error:t.on_background_output_error
;;
let set_named_output t name output =
let named_outputs = Map.set t.state.named_outputs ~key:name ~data:output in
update_named_outputs t named_outputs
;;
let remove_named_output t name =
let named_outputs = Map.remove t.state.named_outputs name in
update_named_outputs t named_outputs
;;
let current_default_outputs t = t.state.default_outputs
let current_named_outputs t = t.state.named_outputs