Library zoo_std.xchain

Require Import zoo.prelude.
Require Import zoo.common.list.
Require Import zoo.base.
Require Export zoo_std.xchain__code.
Require Import zoo_std.xchain__types.
Require Import zoo.options.

Implicit Type node : location.
Implicit Type nodes : list location.
Implicit Type v next dst : val.

Section zoo۰G.
  Context `{zoo۰G : !ZooG Σ}.

  Fixpoint xchain dq nodes dst : iProp Σ :=
    match nodes with
    | []
        True
    | node :: nodes
        match nodes with
        | []
            node.[next] {dq} dst
        | node' :: _
            node.[next] {dq} #node'
            xchain dq nodes dst
        end
    end.
  #[global] Arguments xchain _ !_ _ / : assert.

  #[global] Instance xchaintimeless dq nodes dst :
    Timeless (xchain dq nodes dst).

  #[global] Instance xchainpersistent nodes dst :
    Persistent (xchain DfracDiscarded nodes dst).

  Lemma xchainnil dst :
     xchain (DfracOwn 1) [] dst.

  Lemma xchainsingleton dq node dst :
    xchain dq [node] dst ⊣⊢
    node.[next] {dq} dst.
  Lemma xchainsingleton₁ dq node dst :
    xchain dq [node] dst
    node.[next] {dq} dst.
  Lemma xchainsingleton₂ dq node dst :
    node.[next] {dq} dst
    xchain dq [node] dst.

  Lemma xchaincons {dq} nodes node nodes' dst :
    nodes = node :: nodes'
    xchain dq nodes dst ⊣⊢
      node.[next] {dq} from_option #@{location} dst (head nodes')
      xchain dq nodes' dst.
  Lemma xchaincons' {dq} node nodes dst :
    xchain dq (node :: nodes) dst ⊣⊢
      node.[next] {dq} from_option #@{location} dst (head nodes)
      xchain dq nodes dst.
  Lemma xchaincons₁ {dq} nodes node nodes' dst :
    nodes = node :: nodes'
    xchain dq nodes dst
      node.[next] {dq} from_option #@{location} dst (head nodes')
      xchain dq nodes' dst.
  Lemma xchaincons₁' {dq} node nodes dst :
    xchain dq (node :: nodes) dst
      node.[next] {dq} from_option #@{location} dst (head nodes)
      xchain dq nodes dst.
  Lemma xchaincons₂ dq node nodes dst :
    node.[next] {dq} from_option #@{location} dst (head nodes) -∗
    xchain dq nodes dst -∗
    xchain dq (node :: nodes) dst.

  Lemma xchainapp {dq} nodes nodes1 nodes2 dst :
    nodes = nodes1 ++ nodes2
    xchain dq nodes dst ⊣⊢
      xchain dq nodes1 (from_option #@{location} dst (head nodes2))
      xchain dq nodes2 dst.
  Lemma xchainapp' {dq} nodes1 nodes2 dst :
    xchain dq (nodes1 ++ nodes2) dst ⊣⊢
      xchain dq nodes1 (from_option #@{location} dst (head nodes2))
      xchain dq nodes2 dst.
  Lemma xchainapp₁ {dq} nodes nodes1 nodes2 dst :
    nodes = nodes1 ++ nodes2
    xchain dq nodes dst
      xchain dq nodes1 (from_option #@{location} dst (head nodes2))
      xchain dq nodes2 dst.
  Lemma xchainapp₁' {dq} nodes1 nodes2 dst :
    xchain dq (nodes1 ++ nodes2) dst
      xchain dq nodes1 (from_option #@{location} dst (head nodes2))
      xchain dq nodes2 dst.
  Lemma xchainapp₂ dq nodes1 nodes2 dst :
    xchain dq nodes1 (from_option #@{location} dst (head nodes2)) -∗
    xchain dq nodes2 dst -∗
    xchain dq (nodes1 ++ nodes2) dst.

  Lemma xchainsnoc {dq} nodes nodes' node dst :
    nodes = nodes' ++ [node]
    xchain dq nodes dst ⊣⊢
      xchain dq nodes' #node
      node.[next] {dq} dst.
  Lemma xchainsnoc' {dq} nodes node dst :
    xchain dq (nodes ++ [node]) dst ⊣⊢
      xchain dq nodes #node
      node.[next] {dq} dst.
  Lemma xchainsnoc₁ {dq} nodes nodes' node dst :
    nodes = nodes' ++ [node]
    xchain dq nodes dst
      xchain dq nodes' #node
      node.[next] {dq} dst.
  Lemma xchainsnoc₁' {dq} nodes node dst :
    xchain dq (nodes ++ [node]) dst
      xchain dq nodes #node
      node.[next] {dq} dst.
  Lemma xchainsnoc₂ dq nodes node dst :
    xchain dq nodes #node -∗
    node.[next] {dq} dst -∗
    xchain dq (nodes ++ [node]) dst.

  Lemma xchainlookup {dq nodes} i node dst :
    nodes !! i = Some node
    xchain dq nodes dst ⊣⊢
      xchain dq (take i nodes) #node
      node.[next] {dq} from_option #@{location} dst (nodes !! ˖i)
      xchain dq (drop ˖i nodes) dst.
  Lemma xchainlookup₁ {dq nodes} i node dst :
    nodes !! i = Some node
    xchain dq nodes dst
      xchain dq (take i nodes) #node
      node.[next] {dq} from_option #@{location} dst (nodes !! ˖i)
      xchain dq (drop ˖i nodes) dst.
  Lemma xchainlookup₂ {dq nodes} i node next dst :
    nodes !! i = Some node
    next = from_option #@{location} dst (nodes !! ˖i)
    xchain dq (take i nodes) #node -∗
    node.[next] {dq} next -∗
    xchain dq (drop ˖i nodes) dst -∗
    xchain dq nodes dst.
  Lemma xchainlookupacc {dq nodes} i node dst :
    nodes !! i = Some node
    xchain dq nodes dst
      node.[next] {dq} from_option #@{location} dst (nodes !! ˖i)
      ( node.[next] {dq} from_option #@{location} dst (nodes !! ˖i) -∗
        xchain dq nodes dst
      ).

  Lemma xchainlast {dq nodes dst} node :
    last nodes = Some node
    xchain dq nodes dst ⊣⊢
      xchain dq (removelast nodes) #node
      node.[next] {dq} dst.
  Lemma xchainlastacc {dq nodes dst} node :
    last nodes = Some node
    xchain dq nodes dst
      node.[next] {dq} dst
      ( dst,
        node.[next] {dq} dst -∗
        xchain dq nodes dst
      ).

  Lemma xchainvalid dq nodes dst :
    0 < length nodes
    xchain dq nodes dst
     dq.
  Lemma xchaincombine nodes dq1 dst1 dq2 dst2 :
    0 < length nodes
    xchain dq1 nodes dst1 -∗
    xchain dq2 nodes dst2 -∗
      dst1 = dst2
      xchain (dq1 dq2) nodes dst1.
  Lemma xchainvalidー2 nodes dq1 dst1 dq2 dst2 :
    0 < length nodes
    xchain dq1 nodes dst1 -∗
    xchain dq2 nodes dst2 -∗
       (dq1 dq2)
      dst1 = dst2.
  Lemma xchainagree nodes dq1 dst1 dq2 dst2 :
    0 < length nodes
    xchain dq1 nodes dst1 -∗
    xchain dq2 nodes dst2 -∗
    dst1 = dst2.
  Lemma xchaindfracne dq1 nodes1 dst1 dq2 nodes2 dst2 :
    0 < length nodes1
    ¬ (dq1 dq2)
    xchain dq1 nodes1 dst1 -∗
    xchain dq2 nodes2 dst2 -∗
    nodes1 nodes2.
  Lemma xchainne nodes1 dst1 dq2 nodes2 dst2 :
    0 < length nodes1
    xchain (DfracOwn 1) nodes1 dst1 -∗
    xchain dq2 nodes2 dst2 -∗
    nodes1 nodes2.
  Lemma xchainexclusive nodes dst1 dq2 dst2 :
    0 < length nodes
    xchain (DfracOwn 1) nodes dst1 -∗
    xchain dq2 nodes dst2 -∗
    False.
  Lemma xchainpersist dq nodes dst :
    xchain dq nodes dst |==>
    xchain DfracDiscarded nodes dst.

  Lemma xchainNoDup nodes dst :
    xchain (DfracOwn 1) nodes dst
    NoDup nodes.

  Lemma xchain٠nextspec {dq nodes dst node} nodes' E :
    nodes = node :: nodes'
    {{{
      xchain dq nodes dst
    }}}
      (#node).{next} @ E
    {{{
      RET from_option #@{location} dst (head nodes');
      xchain dq nodes dst
    }}}.
  Lemma xchain٠nextspeclookup {dq nodes dst} i node E :
    nodes !! i = Some node
    {{{
      xchain dq nodes dst
    }}}
      (#node).{next} @ E
    {{{
      RET from_option #@{location} dst (nodes !! ˖i);
      xchain dq nodes dst
    }}}.
  Lemma xchain٠nextspeclast dq nodes dst node E :
    last nodes = Some node
    {{{
      xchain dq nodes dst
    }}}
      (#node).{next} @ E
    {{{
      RET dst;
      xchain dq nodes dst
    }}}.

  Lemma xchain٠set_nextspec {nodes dst node} nodes' v E :
    nodes = node :: nodes'
    {{{
      xchain (DfracOwn 1) nodes dst
    }}}
      (#node) <-{next} v @ E
    {{{
      RET ();
      xchain (DfracOwn 1) [node] v
      xchain (DfracOwn 1) nodes' dst
    }}}.
  Lemma xchain٠set_nextspeclookup {nodes dst} i node v E :
    nodes !! i = Some node
    {{{
      xchain (DfracOwn 1) nodes dst
    }}}
      #node <-{next} v @ E
    {{{
      RET ();
      xchain (DfracOwn 1) (take ˖i nodes) v
      xchain (DfracOwn 1) (drop ˖i nodes) dst
    }}}.
  Lemma xchain٠set_nextspeclast nodes dst node v E :
    last nodes = Some node
    {{{
      xchain (DfracOwn 1) nodes dst
    }}}
      #node <-{next} v @ E
    {{{
      RET ();
      xchain (DfracOwn 1) nodes v
    }}}.
  Lemma xchain٠set_nextspeclast' {nodes dst node} node' dst' E :
    last nodes = Some node
    {{{
      xchain (DfracOwn 1) nodes dst
      node'.[next] dst'
    }}}
      #node <-{next} #node' @ E
    {{{
      RET ();
      xchain (DfracOwn 1) (nodes ++ [node']) dst'
    }}}.
End zoo۰G.

Require zoo_std.xchain__opaque.

#[global] Opaque xchain.