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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
type 'a info = { name : string; root : root }
and root = Root of int option | Value
let pp_info ppf { name; root } =
match root with
| Root (Some p) -> Format.fprintf ppf "<%s:%d>" name p
| Root None -> Format.fprintf ppf "<%s>" name
| Value -> Format.fprintf ppf "%s" name
module Mirage_protocol = Mirage_protocol
module Info = struct type 'a t = 'a info end
module Hmap0 = Hmap.Make (Info)
let pp_value ppf value = Format.fprintf ppf "%a" pp_info (Hmap0.Key.info value)
let src = Logs.Src.create "mimic" ~doc:"logs mimic's event"
module Log = (val Logs.src_log src : Logs.LOG)
module rec Fun : sig
type ('k, 'res) args =
| [] : ('res, 'res) args
| ( :: ) : 'a arg * ('k, 'res) args -> ('a -> 'k, 'res) args
and 'v arg =
| Map : ('f, 'a) args * 'f -> 'a arg
| Req : 'a Hmap0.key -> 'a arg
| Opt : 'a Hmap0.key -> 'a option arg
| Dft : 'a * 'a Hmap0.key -> 'a arg
val req : 'a Hmap0.key -> 'a arg
val opt : 'a Hmap0.key -> 'a option arg
val dft : 'a Hmap0.key -> 'a -> 'a arg
val map : ('k, 'a) args -> 'k -> 'a arg
end = struct
type ('k, 'res) args =
| [] : ('res, 'res) args
| ( :: ) : 'a arg * ('k, 'res) args -> ('a -> 'k, 'res) args
and 'v arg =
| Map : ('f, 'a) args * 'f -> 'a arg
| Req : 'a Hmap0.key -> 'a arg
| Opt : 'a Hmap0.key -> 'a option arg
| Dft : 'a * 'a Hmap0.key -> 'a arg
let req value = Req value
let opt value = Opt value
let dft value v = Dft (v, value)
let map args k = Map (args, k)
end
and Value : sig
type 'a elt =
| Val : 'a -> 'a elt
| Fun : ('k, 'a option Lwt.t) Fun.args * 'k -> 'a elt
type 'a t = 'a elt list
end = struct
type 'a elt =
| Val : 'a -> 'a elt
| Fun : ('k, 'a option Lwt.t) Fun.args * 'k -> 'a elt
type 'a t = 'a elt list
end
module Hmap = Hmap0.Make (Value)
type ctx = Hmap.t
type 'edn value = 'edn Hmap0.key
let merge ctx0 ctx1 =
let f :
type a.
a value -> a Value.t option -> a Value.t option -> a Value.t option =
fun _k lst0 lst1 ->
match lst0, lst1 with
| Some lst0, Some lst1 -> Some (lst0 @ lst1)
| Some x, None | None, Some x -> Some x
| None, None -> None
in
Hmap.merge { f } ctx0 ctx1
module Merge (A : sig
val ctx : ctx
end) (B : sig
val ctx : ctx
end) =
struct
let ctx = merge A.ctx B.ctx
end
let add value v ctx =
match Hmap.find value ctx with
| Some lst -> Hmap.add value (lst @ [ Val v ]) ctx
| None -> Hmap.add value [ Val v ] ctx
let fold value args ~k ctx =
match Hmap.find value ctx with
| Some lst -> Hmap.add value (lst @ [ Fun (args, k) ]) ctx
| None -> Hmap.add value [ Fun (args, k) ] ctx
let replace value v ctx =
match Hmap.find value ctx with
| None -> Hmap.add value [ Val v ] ctx
| Some lst ->
let lst =
List.fold_left
(fun acc -> function
| Value.Fun _ as v -> v :: acc
| Value.Val _ -> acc)
[] lst
in
let lst = List.rev lst in
Hmap.add value (Val v :: lst) ctx
module Implicit0 = Implicit.Make (struct
type 'flow t = (module Mirage_flow.S with type flow = 'flow)
end)
type flow = Implicit0.t = private ..
type error = [ `Msg of string | `Not_found | `Cycle ]
type write_error = [ `Msg of string | `Closed ]
let pp_error ppf = function
| `Msg err -> Format.pp_print_string ppf err
| `Not_found -> Format.pp_print_string ppf "No connection found"
| `Cycle -> Format.pp_print_string ppf "Context contains a cycle"
let pp_write_error ppf = function
| `Msg err -> Format.pp_print_string ppf err
| `Closed -> Format.pp_print_string ppf "Connection closed by peer"
let to_to_string pp v = Format.asprintf "%a" pp v
let read flow =
let (Implicit0.Value (flow, (module Flow))) = Implicit0.prj flow in
let open Lwt.Infix in
Flow.read flow
>|= Result.map_error (fun fe -> `Msg (to_to_string Flow.pp_error fe))
let write flow cs =
let (Implicit0.Value (flow, (module Flow))) = Implicit0.prj flow in
let open Lwt.Infix in
Flow.write flow cs >|= function
| Error `Closed -> Error `Closed
| Error e -> Error (`Msg (to_to_string Flow.pp_write_error e))
| Ok _ as v -> v
let writev flow css =
let (Implicit0.Value (flow, (module Flow))) = Implicit0.prj flow in
let open Lwt.Infix in
Flow.writev flow css
>|= Result.map_error (fun fe -> `Msg (to_to_string Flow.pp_write_error fe))
let shutdown flow mode =
let (Implicit0.Value (flow, (module Flow))) = Implicit0.prj flow in
Flow.shutdown flow mode
let close flow =
let (Implicit0.Value (flow, (module Flow))) = Implicit0.prj flow in
Flow.close flow
type ('edn, 'flow) snd = Snd : 'flow -> ('edn, 'flow) snd [@@warning "-37"]
type _ pack =
| Protocol :
'edn Hmap0.key
* 'flow Implicit0.witness
* (module Mirage_protocol.S
with type flow = 'flow
and type endpoint = 'edn)
-> ('edn, 'flow) snd pack
module Implicit1 = Implicit.Make (struct type 'v t = 'v pack end)
type ('edn, 'flow) protocol = {
flow : 'flow Implicit0.witness;
protocol : ('edn, 'flow) snd Implicit1.witness;
}
let register :
type edn flow.
?priority:int ->
name:string ->
(module Mirage_protocol.S with type flow = flow and type endpoint = edn) ->
edn value * (edn, flow) protocol =
fun ?priority ~name (module Protocol) ->
let value = Hmap0.Key.create { name; root = Root priority } in
let flow = Implicit0.inj (module Protocol) in
let protocol = Implicit1.inj (Protocol (value, flow, (module Protocol))) in
value, { flow; protocol }
module type REPR = sig
type t type flow += T of t
end
let repr :
type edn flow. (edn, flow) protocol -> (module REPR with type t = flow) =
fun { flow; _ } ->
let (module Witness) = flow in
let module M = struct
include Witness
type t = a
end in
(module M)
let rec apply :
type k res. ctx -> (k, res option Lwt.t) Fun.args -> k -> res option Lwt.t =
fun ctx args f ->
let open Lwt.Infix in
let rec go : type k res. ctx -> (k, res) Fun.args -> k -> res Lwt.t =
fun ctx -> function
| [] -> fun x -> Lwt.return x
| Map (args', f') :: tl ->
fun f -> go ctx args' f' >>= fun v -> go ctx tl (f v)
| Opt value :: tl -> fun f -> find value ctx >>= fun v -> go ctx tl (f v)
| Dft (v, value) :: tl -> (
fun f ->
find value ctx >>= function
| Some v' ->
Log.debug (fun m ->
m "Found a value for the default argument: %a." pp_value value);
go ctx tl (f v')
| None -> go ctx tl (f v))
| Req value :: tl -> (
fun f ->
find value ctx >>= function
| Some v -> go ctx tl (f v)
| None -> Lwt.fail Not_found)
in
Lwt.catch (fun () -> go ctx args f >>= fun fiber -> fiber) @@ function
| Not_found -> Lwt.return_none
| exn -> Lwt.fail exn
and find : type a. a value -> ctx -> a option Lwt.t =
fun value ctx ->
match Hmap.find value ctx with
| None | Some [] -> Lwt.return_none
| Some lst ->
let rec go fold lst =
match fold, lst with
| None, [] -> Lwt.return_none
| Some (Value.Fun (args, f)), [] -> apply ctx args f
| Some (Value.Val _), [] -> assert false
| None, (Value.Fun _ as x) :: r -> go (Some x) r
| _, Val v :: _ -> Lwt.return_some v
| Some _, Fun _ :: r -> go fold r
in
go None (List.rev lst)
type edn = Edn : 'edn value * 'edn -> edn
type fnu = Fun : 'edn value * ('k, 'edn option Lwt.t) Fun.args * 'k -> fnu
type dep = Dep : 'edn value -> dep
let pp_fnu ppf (Fun (dep, _, _)) =
Format.fprintf ppf "%a" pp_info (Hmap0.Key.info dep)
module Sort = struct
type t =
| Val : 'edn value * 'edn -> t
| Fun : 'edn value * ('k, 'edn option Lwt.t) Fun.args * 'k -> t
let pp ppf = function
| Val (k, _) -> pp_info ppf (Hmap0.Key.info k)
| Fun (k, _, _) -> pp_info ppf (Hmap0.Key.info k)
end
let partition bindings =
let rec go leafs nodes = function
| [] -> List.rev leafs, List.rev nodes
| Hmap.B (_, []) :: r -> go leafs nodes r
| Hmap.B (k, Val v :: tl) :: r ->
go (Sort.Val (k, v) :: leafs) nodes (Hmap.B (k, tl) :: r)
| Hmap.B (k, Fun (args, f) :: tl) :: r ->
go leafs (Fun (k, args, f) :: nodes) (Hmap.B (k, tl) :: r)
in
go [] [] bindings
let exists k bindings =
let rec go k = function
| [] -> false
| Hmap.B (k', _) :: r -> (
match Hmap0.Key.proof k k' with Some _ -> true | None -> go k r)
in
go k bindings
let dependencies (Fun (_, args, _)) bindings =
let rec go : type k r. _ -> (k, r) Fun.args -> _ =
fun acc -> function
| Fun.Req dep :: r -> go (Dep dep :: acc) r
| Fun.Opt dep :: r when exists dep bindings -> go (Dep dep :: acc) r
| Fun.Dft (_, dep) :: r when exists dep bindings -> go (Dep dep :: acc) r
| _ :: r -> go acc r
| [] -> List.rev acc
in
go [] args
let exists leafs (Dep k) =
let rec go = function
| [] -> false
| Sort.Val (k', _) :: r -> (
match Hmap0.Key.proof k k' with Some _ -> true | None -> go r)
| Sort.Fun (k', _, _) :: r -> (
match Hmap0.Key.proof k k' with Some _ -> true | None -> go r)
in
go leafs
let pp_list pp ppf lst =
let rec go = function
| [] -> ()
| [ x ] -> Format.fprintf ppf "%a" pp x
| x :: r ->
Format.fprintf ppf "%a;@ " pp x;
go r
in
Format.fprintf ppf "@[<1>[";
go lst;
Format.fprintf ppf "]@]"
let sort bindings =
let rec go acc later todo progress =
match todo, later with
| [], [] -> List.rev acc
| [], _ when progress -> go acc [] later false
| [], later ->
Log.debug (fun m ->
m "Found a solution only for: @[<hov>%a@]." (pp_list Sort.pp) acc);
Log.debug (fun m ->
m "Unsolvable values: @[<hov>%a@]." (pp_list pp_fnu) later);
List.rev acc
| (Fun (k, args, f) as x) :: xs, _ ->
let deps = dependencies x bindings in
let available = List.for_all (exists acc) deps in
if available then go (Sort.Fun (k, args, f) :: acc) later xs true
else go acc (x :: later) xs progress
in
let leafs, nodes = partition bindings in
Log.debug (fun m -> m "Partition done.");
Log.debug (fun m -> m "Nodes: @[<hov>%a@]." (pp_list pp_fnu) nodes);
go leafs [] nodes false
let inf = -1 and sup = 1
let priority_compare (Edn (k0, _)) (Edn (k1, _)) =
match (Hmap0.Key.info k0).root, (Hmap0.Key.info k1).root with
| Root (Some p0), Root (Some p1) -> p0 - p1
| (Root None | Value), Root (Some _) -> sup
| Root (Some _), (Root None | Value) -> inf
| Value, Value -> 0
| Root None, Root None -> 0
| Value, Root None -> sup
| Root None, Value -> inf
let unfold : ctx -> (edn list, [> `Cycle ]) result Lwt.t =
fun ctx ->
let open Lwt.Infix in
let rec go ctx acc : Sort.t list -> _ = function
| [] ->
let acc = List.stable_sort priority_compare (List.rev acc) in
Lwt.return_ok acc
| Sort.Val (k, v) :: r ->
Log.debug (fun m -> m "Return a value %a." pp_value k);
go ctx (Edn (k, v) :: acc) r
| Sort.Fun (k, args, f) :: r -> (
Log.debug (fun m -> m "Apply a function %a." pp_value k);
apply ctx args f >>= function
| Some v -> go (add k v ctx) (Edn (k, v) :: acc) r
| None -> go ctx acc r)
in
let ordered_bindings = sort (Hmap.bindings ctx) in
go ctx [] ordered_bindings
let flow_of_value :
type edn. edn value -> edn -> (flow, [> error ]) result Lwt.t =
fun k v ->
let open Lwt.Infix in
let rec go : Implicit1.pack list -> _ = function
| [] -> Lwt.return_error `Not_found
| Implicit1.Key (Protocol (k', (module Witness), (module Protocol))) :: r
-> (
match Hmap0.Key.proof k k' with
| None -> go r
| Some Teq -> (
Protocol.connect v >>= function
| Ok flow -> Lwt.return_ok (Witness.T flow)
| Error _err -> go r))
in
go (Implicit1.bindings ())
type ('a, 'b) refl = Refl : ('a, 'a) refl
let equal : type a b. a value -> b value -> (a, b) refl option =
fun a b ->
match Hmap0.Key.proof a b with Some Teq -> Some Refl | None -> None
let rec connect : edn list -> (flow, [> error ]) result Lwt.t = function
| [] -> Lwt.return_error `Not_found
| Edn (k, v) :: r -> (
let open Lwt.Infix in
Log.debug (fun m -> m "Try to instantiate %a." pp_value k);
flow_of_value k v >>= function
| Ok _ as v -> Lwt.return v
| Error _err -> connect r)
let resolve : ctx -> (flow, [> error ]) result Lwt.t =
fun ctx ->
let open Lwt.Infix in
unfold ctx >>= function
| Ok lst ->
Log.debug (fun m ->
m "List of endpoints: @[<hov>%a@]"
(pp_list (fun ppf (Edn (k, _)) -> pp_value ppf k))
lst);
connect lst
| Error _ as err -> Lwt.return err
let make ~name = Hmap0.Key.create { name; root = Value }
let empty = Hmap.empty
let get value ctx =
match Hmap.find value ctx with
| Some lst ->
let rec first = function
| [] -> None
| Value.Val v :: _ -> Some v
| _ :: r -> first r
in
first lst
| None -> None