type error = | Unexpected of { machine : string; state : string; event : string } | Not_implemented of { machine : string; what : string } | Unanswered of { machine : string; seconds : int; awaits : string } let pp_error ppf = function | Unexpected { machine; state; event } -> Fmt.pf ppf "the %s machine cannot take %s in state %s" machine event state | Not_implemented { machine; what } -> Fmt.pf ppf "not implemented yet: %s (the %s machine)" what machine | Unanswered { machine; seconds; awaits } -> Fmt.pf ppf "the %s machine had no answer for %ds, past every bound it waits on, \ while it awaited %s" machine seconds awaits let unexpected machine ~state ~event = Error (Unexpected { machine; state; event }) let not_implemented machine what = Error (Not_implemented { machine; what }) module Task = struct type id = string list let v name = [ name ] let within prefix id = prefix :: id let equal = List.equal String.equal let compare = List.compare String.compare let pp ppf id = Fmt.(list ~sep:(any "/") string) ppf id type t = | Now | Record | Start of id | Cancel of id | Stop of id * string | Abandon of id exception Stopped of string let under prefix = function | Now -> Now | Record -> Record | Start id -> Start (within prefix id) | Cancel id -> Cancel (within prefix id) | Stop (id, why) -> Stop (within prefix id, why) | Abandon id -> Abandon (within prefix id) end type unanswered = Cancelled | Failed of string let pp_unanswered ppf = function | Cancelled -> Fmt.string ppf "cancelled" | Failed why -> Fmt.string ppf why module type S = sig type t type event type action type ending val incoming : t -> now:Ptime.t -> event -> (t * action list, error) result val timer : t -> now:Ptime.t -> (t * action list, error) result val next_timeout : t -> Ptime.t option val ending : t -> ending option val task : action -> Task.t val unanswered : action -> unanswered -> event val pp : t Fmt.t val pp_event : event Fmt.t val pp_action : action Fmt.t end module type TOP = sig include S val signal : Signal.t -> event end