136 lines
4.3 KiB
OCaml
136 lines
4.3 KiB
OCaml
|
|
module Mirage_protocol = Mirage_protocol
|
||
|
|
|
||
|
|
type flow = private ..
|
||
|
|
(** The type for flows. A flow represents the state of a single reliable stream
|
||
|
|
stream that is connected to an {i endpoint}. *)
|
||
|
|
|
||
|
|
include
|
||
|
|
Mirage_flow.S
|
||
|
|
with type flow := flow
|
||
|
|
and type error = [ `Msg of string | `Not_found | `Cycle ]
|
||
|
|
|
||
|
|
type ctx
|
||
|
|
(** The type for contexts. It's a {i heterogeneous map} of values to help mimic
|
||
|
|
to instantiate a new {!type:flow} {i via} {!val:resolve}. *)
|
||
|
|
|
||
|
|
type 'edn value
|
||
|
|
(** The type for {i witnesses} whose lookup value is of type ['edn]. *)
|
||
|
|
|
||
|
|
module Fun : sig
|
||
|
|
type ('k, 'res) args =
|
||
|
|
| [] : ('res, 'res) args
|
||
|
|
| ( :: ) : 'a arg * ('k, 'res) args -> ('a -> 'k, 'res) args
|
||
|
|
|
||
|
|
and 'v arg
|
||
|
|
|
||
|
|
val req : 'a value -> 'a arg
|
||
|
|
val opt : 'a value -> 'a option arg
|
||
|
|
val dft : 'a value -> 'a -> 'a arg
|
||
|
|
val map : ('k, 'a) args -> 'k -> 'a arg
|
||
|
|
end
|
||
|
|
|
||
|
|
val make : name:string -> 'edn value
|
||
|
|
(** [make ~name] is a new witness. *)
|
||
|
|
|
||
|
|
val add : 'edn value -> 'edn -> ctx -> ctx
|
||
|
|
(** [add w v ctx] is [ctx] with [w] bound to [v]. *)
|
||
|
|
|
||
|
|
val get : 'edn value -> ctx -> 'edn option
|
||
|
|
(** [get w ctx] is the value of [w]'s binding in [ctx], if any. *)
|
||
|
|
|
||
|
|
val replace : 'edn value -> 'edn -> ctx -> ctx
|
||
|
|
(** [replace w v ctx] replaces the value of [w] by [v] if it exists
|
||
|
|
or bound [w] to [v]. *)
|
||
|
|
|
||
|
|
val fold : 'edn value -> ('k, 'edn option Lwt.t) Fun.args -> k:'k -> ctx -> ctx
|
||
|
|
val merge : ctx -> ctx -> ctx
|
||
|
|
|
||
|
|
val empty : ctx
|
||
|
|
(** [empty] is the empty context. *)
|
||
|
|
|
||
|
|
type ('edn, 'flow) protocol
|
||
|
|
|
||
|
|
val register :
|
||
|
|
?priority:int ->
|
||
|
|
name:string ->
|
||
|
|
(module Mirage_protocol.S with type flow = 'flow and type endpoint = 'edn) ->
|
||
|
|
'edn value * ('edn, 'flow) protocol
|
||
|
|
(** [register ?priority ~name (module Protocol)] registers the given [Protocol]
|
||
|
|
into the internal global Mimic's state as a possible transmission protocol
|
||
|
|
available {i via} {!val:resolve}.
|
||
|
|
|
||
|
|
[?priority] is used to help mimic to choose between multiple solutions
|
||
|
|
according to the given context. Mimic will choose the lower-priority
|
||
|
|
solution.
|
||
|
|
|
||
|
|
[name] helps the end-user to know which solution mimic will dynamically
|
||
|
|
{i via} log outputs.
|
||
|
|
|
||
|
|
[register] returns 2 values:
|
||
|
|
- a {i witness} as the required value to initiate a transmission {i via}
|
||
|
|
the given [Protocol] implementation
|
||
|
|
- a {!type:protocol} which can help the end-user to destruct a {!type:flow}
|
||
|
|
to its structural type {i via} {!val:repr}. *)
|
||
|
|
|
||
|
|
module type REPR = sig
|
||
|
|
type t type flow += (* XXX(dinosaure): private? *) T of t
|
||
|
|
end
|
||
|
|
|
||
|
|
val repr : ('edn, 'flow) protocol -> (module REPR with type t = 'flow)
|
||
|
|
(** [repr protocol] gives a module definition with an OCaml constructor to help
|
||
|
|
the end-user to destruct the structural type of a given {!type:flow}:
|
||
|
|
|
||
|
|
{[
|
||
|
|
module Protocol
|
||
|
|
: Mirage_protocol.S with type flow = Lwt_unix.file_descr
|
||
|
|
|
||
|
|
let edn, protocol = Mimic.register ~name:"protocol" (module Protocol)
|
||
|
|
module R = (val (Mimic.repr protocol))
|
||
|
|
|
||
|
|
let () = Mimic.resolve ~ctx >>= function
|
||
|
|
| Ok (R.T lwt_unix_file_descr) -> ...
|
||
|
|
| ...
|
||
|
|
]} *)
|
||
|
|
|
||
|
|
val resolve : ctx -> (flow, [> error ]) result Lwt.t
|
||
|
|
(** [resolve ctx] tries to instantiate a {!type:flow} from the given [ctx]. *)
|
||
|
|
|
||
|
|
type edn =
|
||
|
|
| Edn : 'edn value * 'edn -> edn (** The type of a value and its witness. *)
|
||
|
|
|
||
|
|
type (_, _) refl = Refl : ('a, 'a) refl
|
||
|
|
|
||
|
|
val equal : 'a value -> 'b value -> ('a, 'b) refl option
|
||
|
|
(** [equal a b] returns a proof that [a] and [b] are
|
||
|
|
{i structurally} equal. *)
|
||
|
|
|
||
|
|
val unfold : ctx -> (edn list, [> `Cycle ]) result Lwt.t
|
||
|
|
(** [unfold ctx] applies any functions available into the given [ctx] and
|
||
|
|
and possible to compute according to available values and return a list
|
||
|
|
of what these functions return.
|
||
|
|
|
||
|
|
It's useful to do an introspection of what [mimic] does when it
|
||
|
|
{!val:resolve}s the given [ctx]. From that and {!val:equal}, the user is
|
||
|
|
able to introspect what [mimic] generated and which protocol it is able
|
||
|
|
to instantiate then.
|
||
|
|
|
||
|
|
{val:resolve} is:
|
||
|
|
{[
|
||
|
|
let resolve ctx =
|
||
|
|
unfold ctx >>= function
|
||
|
|
| Ok lst -> connect lst
|
||
|
|
| Error _ as err -> Lwt.return err
|
||
|
|
]} *)
|
||
|
|
|
||
|
|
val connect : edn list -> (flow, [> error ]) result Lwt.t
|
||
|
|
(** [connect values] tries to instantiate a {!type:flow} from given [values]
|
||
|
|
and registered protocols (see {!val:register}). *)
|
||
|
|
|
||
|
|
module Merge (A : sig
|
||
|
|
val ctx : ctx
|
||
|
|
end) (B : sig
|
||
|
|
val ctx : ctx
|
||
|
|
end) : sig
|
||
|
|
val ctx : ctx
|
||
|
|
end
|