From d7f2e1a05cf7cf8a7f7ec860ce1bf9d44f18e76e Mon Sep 17 00:00:00 2001
From: jihgfee <jihgfee@gmail.com>
Date: Tue, 3 Nov 2020 16:38:53 +0100
Subject: [PATCH] Added example of rpc client/service

---
 _CoqProject             |   1 +
 theories/examples/rpc.v | 139 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+)
 create mode 100644 theories/examples/rpc.v

diff --git a/_CoqProject b/_CoqProject
index dad39bb..c846664 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -25,6 +25,7 @@ theories/examples/map_reduce.v
 theories/examples/swap_mapper.v
 theories/examples/subprotocols.v
 theories/examples/list_rev.v
+theories/examples/rpc.v
 theories/logrel/model.v
 theories/logrel/telescopes.v
 theories/logrel/subtyping.v
diff --git a/theories/examples/rpc.v b/theories/examples/rpc.v
new file mode 100644
index 0000000..12b5da1
--- /dev/null
+++ b/theories/examples/rpc.v
@@ -0,0 +1,139 @@
+From iris.heap_lang Require Import proofmode.
+From actris.channel Require Import proofmode.
+
+Definition server : val :=
+  rec: "go" "dict" "c" :=
+    if: ~ (recv "c") then #()
+    else
+      let: "f" := "dict" (recv "c") in
+      let: "res" := "f" (recv "c") in
+      send "c" "res";;
+      "go" "dict" "c".
+
+Definition Left : val := #true.
+Definition Right : val := #false.
+
+Notation plus_id := 1%Z.
+Notation incr_ref_id := 2%Z.
+
+Definition client : val :=
+  λ: "c",
+    send "c" Left;;
+    send "c" #plus_id;; send "c" (#40,#2);; let: "res1" := recv "c" in
+    send "c" Left;;
+    let: "l" := ref #41 in
+    send "c" #incr_ref_id;; send "c" "l";; let: "res2" := ! (recv "c") in
+    send "c" Right;;
+    ("res1","res2").
+
+Definition program : val :=
+  λ: "dict",
+    let: "c" := new_chan #() in
+    Fork (server "dict" (Snd "c"));;
+    client (Fst "c").
+
+Section rpc_example.
+  Context `{!heapG Σ, !chanG Σ}.
+
+  Definition f_spec {T U} (IT : T → val → iProp Σ) (IU : U → val → iProp Σ)
+             (f : T → U) (fv : val) : iProp Σ :=
+    (∀ x v, {{{ IT x v }}} fv v {{{ w, RET w; IU (f x) w }}})%I.
+
+  Definition rpc_prot_aux (f_specs : gmap Z (val → iProp Σ)) (rec : iProto Σ)
+    : iProto Σ :=
+    ((<! (T U:Type) IT IU (f : T → U) (id:Z)> MSG #id
+        {{ ⌜f_specs !! id = Some (f_spec IT IU f)⌝ }};
+      <! (x:T) (v:val)> MSG v {{ IT x v }} ;
+      <? (w:val)> MSG w {{ IU (f x) w }} ; rec)
+    <+> END)%proto.
+
+  Instance rpc_prot_aux_contractive (f_specs : gmap Z (val → iProp Σ)) :
+    Contractive (rpc_prot_aux f_specs).
+  Proof. solve_proto_contractive. Qed.
+  Definition rpc_prot (f_specs : gmap Z (val → iProp Σ)) : iProto Σ :=
+    fixpoint (rpc_prot_aux f_specs).
+  Global Instance rpc_prot_unfold f_specs :
+    ProtoUnfold (rpc_prot f_specs) (rpc_prot_aux f_specs (rpc_prot f_specs)).
+  Proof. apply proto_unfold_eq, fixpoint_unfold. Qed.
+
+  Definition dict_spec (dict : val) (f_specs : gmap Z _) : iProp Σ :=
+    ∀ (T U : Type) (id : Z) (IT : T → val → iProp Σ) (IU : U → val → iProp Σ)
+      (f : T → U),
+      {{{ ⌜f_specs !! id = Some (f_spec IT IU f)⌝ }}}
+        dict #id
+      {{{ fv, RET fv; f_spec IT IU f fv }}}.
+
+  Lemma server_spec dict f_specs c prot :
+    {{{ dict_spec dict f_specs ∗
+        c ↣ (iProto_dual (rpc_prot f_specs) <++> prot)%proto }}}
+      server dict c
+    {{{ RET #(); c ↣ prot }}}.
+  Proof.
+    iIntros (Φ) "[#Hdict Hc] HΦ".
+    iLöb as "IH".
+    wp_rec.
+    wp_branch; last first.
+    { wp_pures. by iApply "HΦ". }
+    wp_recv (T U IT IU f id) as "Hlookup".
+    wp_apply ("Hdict" with "Hlookup"); iIntros (fv) "Hfv".
+    wp_recv (x v) as "HIT".
+    wp_apply ("Hfv" with "HIT"); iIntros (w) "HIU".
+    wp_send (w) with "[$HIU]".
+    wp_pures. by iApply ("IH" with "Hc").
+  Qed.
+
+  Definition plus_spec :=
+    f_spec (λ (x:Z*Z) (v:val), ⌜(#(fst x), #(snd x))%V = v⌝)%I
+           (λ y w, ⌜#y = w⌝)%I
+           (λ (x:Z*Z), (fst x) + (snd x))%Z.
+
+  Definition incr_ref_spec :=
+    f_spec (λ (x:Z) (v:val), ∃ (l : loc), ⌜v = #l⌝ ∗ l ↦ #x)%I
+           (λ (y:Z) (w:val), ∃ (l : loc), ⌜w = #l⌝ ∗ l ↦ #y)%I
+           (λ (x:Z), x+1)%Z.
+
+  Definition client_f_specs : gmap Z (val → iProp Σ) :=
+    {[ plus_id := plus_spec ]} ∪
+    {[ incr_ref_id := incr_ref_spec ]}.
+
+  Lemma client_spec c :
+    {{{ c ↣ rpc_prot client_f_specs }}}
+      client c
+    {{{ RET (#42, #42); True }}}.
+  Proof.
+    iIntros (Φ) "Hc HΦ".
+    wp_lam.
+    (** plus *)
+    wp_select.
+    wp_send with "[//]". wp_send with "[]".
+    { by instantiate (1:=(40,2)%Z). }
+    wp_recv (w) as "<-".
+    (** incr_ref *)
+    wp_select.
+    wp_alloc l as "Hl".
+    wp_send with "[//]". wp_send with "[Hl]".
+    { eauto. }
+    wp_recv (w) as (l') "[-> Hl]".
+    wp_load.
+    (** Termination *)
+    wp_select.
+    wp_pures.
+    by iApply "HΦ".
+  Qed.
+
+  Lemma program_spec dict :
+    {{{ dict_spec dict client_f_specs }}}
+      program dict
+    {{{ v, RET v; True }}}.
+  Proof.
+    iIntros (Φ) "#Hdict HΦ".
+    wp_lam.
+    wp_apply (new_chan_spec (rpc_prot client_f_specs))=> //.
+    iIntros (c1 c2) "[Hc1 Hc2]".
+    wp_apply (wp_fork with "[Hc2]").
+    - iIntros "!>". wp_apply (server_spec _ _ _ END%proto with "[Hc2]").
+      rewrite right_id. iFrame "Hdict Hc2". by iIntros "_".
+    - by wp_apply (client_spec with "Hc1").
+  Qed.
+
+End rpc_example.
-- 
GitLab