Definition iname := nat.
Class invG := { g_inv : gname; g_en : gname; g_dis : gname }.
Context {inv_names : invG}.
Definition master_list {A} g (l : list (option A)) := ghost_master1(ORD := list_order A) l g.
(* up *)
Instance Inhabitant_option {A} : Inhabitant (option A) := None.
(* Our ghost state construction makes it awkward to put agree inside other ghost state constructions. As a workaround, instead of having one ghost location with a map from indices to agrees, we have a map from indices to ghost locations, each with an agree. *)
Instance token_PCM : Ghost := exclusive_PCM unit.
Definition wsat : mpred := EX I : list mpred, EX lg : list gname, EX lb : list (option bool),
!!(length lg = length I /\ length lb = length I) &&
master_list g_inv (map (fun i => match Znth i lb with Some _ => Some (Znth i lg)
| None => None end) (upto (length I))) *
ghost_list g_dis (map (fun o => match o with Some true => Some (Some tt) | _ => None end) lb) *
ghost_set g_en (fun i : iname => nth i lb None = Some false) *
iter_sepcon (fun i => match Znth i lb with
| Some true => agree (Znth i lg) (Znth i I) * |> Znth i I
| Some false => agree (Znth i lg) (Znth i I)
| _ => emp end) (upto (length I)).
(* This is what's called ownI in Iris; we could build another layer with namespaces. *)
Definition invariant (i : iname) P : mpred := EX g : gname,
ghost_snap(ORD := list_order _) (list_singleton i g) g_inv * agree g P.

Lemma list_join_singleton_inv : forall {P : Ghost} n a b l,
list_join (list_singleton n a) (list_singleton n b) l ->
exists c, join a b c /\ l = list_singleton n c.