Skip to content
Snippets Groups Projects
rpc.v 4.27 KiB
Newer Older
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.