Library zoo_std.xdlchain

Require Import zoo.prelude.
Require Import zoo.common.list.
Require Import zoo.base.
Require Export zoo_std.xdlchain__code.
Require Import zoo_std.xdlchain__types.
Require Import zoo.options.

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

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

  Fixpoint xdlchain src nodes dst : iProp Σ :=
    match nodes with
    | []
        True
    | node :: nodes
        node.[prev] src
        match nodes with
        | []
            node.[next] dst
        | node' :: _
            node.[next] #node'
            xdlchain #node nodes dst
        end
    end.
  #[global] Arguments xdlchain _ !_ _ / : assert.

  #[global] Instance xdlchaintimeless src nodes dst :
    Timeless (xdlchain src nodes dst).

  Lemma xdlchainnil src dst :
     xdlchain src [] dst.

  Lemma xdlchainsingleton src node dst :
    xdlchain src [node] dst ⊣⊢
      node.[prev] src
      node.[next] dst.
  Lemma xdlchainsingleton₁ src node dst :
    xdlchain src [node] dst
      node.[prev] src
      node.[next] dst.
  Lemma xdlchainsingleton₂ src node dst :
    node.[prev] src -∗
    node.[next] dst -∗
    xdlchain src [node] dst.

  #[local] Lemma xdlchainconsunfold {src} node nodes dst :
    xdlchain src (node :: nodes) dst ⊣⊢
      node.[prev] src
      match nodes with
      | []
          node.[next] dst
      | node' :: _
          node.[next] #node'
          xdlchain #node nodes dst
      end.

  Lemma xdlchaincons {src} nodes node nodes' dst :
    nodes = node :: nodes'
    xdlchain src nodes dst ⊣⊢
      node.[prev] src
      node.[next] from_option #@{location} dst (head nodes')
      xdlchain #node nodes' dst.
  Lemma xdlchaincons₁ {src} nodes node nodes' dst :
    nodes = node :: nodes'
    xdlchain src nodes dst
      node.[prev] src
      node.[next] from_option #@{location} dst (head nodes')
      xdlchain #node nodes' dst.
  Lemma xdlchaincons₂ src node nodes dst :
    node.[prev] src -∗
    node.[next] from_option #@{location} dst (head nodes) -∗
    xdlchain #node nodes dst -∗
    xdlchain src (node :: nodes) dst.

  Lemma xdlchainapp {src} nodes nodes1 nodes2 dst :
    nodes = nodes1 ++ nodes2
    xdlchain src nodes dst ⊣⊢
      xdlchain src nodes1 (from_option #@{location} dst (head nodes2))
      xdlchain (from_option #@{location} src (last nodes1)) nodes2 dst.
  Lemma xdlchainapp₁ {src} nodes nodes1 nodes2 dst :
    nodes = nodes1 ++ nodes2
    xdlchain src nodes dst
      xdlchain src nodes1 (from_option #@{location} dst (head nodes2))
      xdlchain (from_option #@{location} src (last nodes1)) nodes2 dst.
  Lemma xdlchainapp₂ src nodes1 nodes2 dst :
    xdlchain src nodes1 (from_option #@{location} dst (head nodes2)) -∗
    xdlchain (from_option #@{location} src (last nodes1)) nodes2 dst -∗
    xdlchain src (nodes1 ++ nodes2) dst.

  Lemma xdlchainsnoc {src} nodes nodes' node dst :
    nodes = nodes' ++ [node]
    xdlchain src nodes dst ⊣⊢
      xdlchain src nodes' #node
      node.[prev] from_option #@{location} src (last nodes')
      node.[next] dst.
  Lemma xdlchainsnoc₁ {src} nodes nodes' node dst :
    nodes = nodes' ++ [node]
    xdlchain src nodes dst
      xdlchain src nodes' #node
      node.[prev] from_option #@{location} src (last nodes')
      node.[next] dst.
  Lemma xdlchainsnoc₂ src nodes node dst :
    xdlchain src nodes #node -∗
    node.[prev] from_option #@{location} src (last nodes) -∗
    node.[next] dst -∗
    xdlchain src (nodes ++ [node]) dst.

  Lemma xdlchainlast {src nodes} node dst :
    last nodes = Some node
    xdlchain src nodes dst
       nodes',
      nodes = nodes' ++ [node]
      xdlchain src nodes' #node
      node.[prev] from_option #@{location} src (last nodes')
      node.[next] dst.

  Lemma xdlchainlookup {src nodes} i node dst :
    nodes !! i = Some node
    xdlchain src nodes dst ⊣⊢
      xdlchain src (take i nodes) #node
      node.[prev] from_option #@{location} src (last $ take i nodes)
      node.[next] from_option #@{location} dst (head $ drop ˖i nodes)
      xdlchain #node (drop ˖i nodes) dst.
  Lemma xdlchainlookup₁ {src nodes} i node dst :
    nodes !! i = Some node
    xdlchain src nodes dst
      xdlchain src (take i nodes) #node
      node.[prev] from_option #@{location} src (last $ take i nodes)
      node.[next] from_option #@{location} dst (head $ drop ˖i nodes)
      xdlchain #node (drop ˖i nodes) dst.
  Lemma xdlchainlookup₂ {src nodes} i node prev next dst :
    nodes !! i = Some node
    prev = from_option #@{location} src (last $ take i nodes)
    next = from_option #@{location} dst (head $ drop ˖i nodes)
    xdlchain src (take i nodes) #node -∗
    node.[prev] prev -∗
    node.[next] next -∗
    xdlchain #node (drop ˖i nodes) dst -∗
    xdlchain src nodes dst.

  Lemma xdlchainlookupacc {src nodes} i node dst :
    nodes !! i = Some node
    xdlchain src nodes dst
      node.[prev] from_option #@{location} src (last $ take i nodes)
      node.[next] from_option #@{location} dst (head $ drop ˖i nodes)
      ( node.[prev] from_option #@{location} src (last $ take i nodes) -∗
        node.[next] from_option #@{location} dst (head $ drop ˖i nodes) -∗
        xdlchain src nodes dst
      ).

  Lemma xdlchainexclusive src1 src2 nodes dst1 dst2 :
    0 < length nodes
    xdlchain src1 nodes dst1 -∗
    xdlchain src2 nodes dst2 -∗
    False.

  Lemma xdlchainNoDup src nodes dst :
    xdlchain src nodes dst
    NoDup nodes.

  Lemma xdlchain٠prevspec {src nodes node} nodes' dst E :
    nodes = node :: nodes'
    {{{
      xdlchain src nodes dst
    }}}
      (#node).{prev} @ E
    {{{
      RET src;
      xdlchain src nodes dst
    }}}.
  Lemma xdlchain٠prevspeclookup {src nodes} i node dst E :
    nodes !! i = Some node
    {{{
      xdlchain src nodes dst
    }}}
      (#node).{prev} @ E
    {{{
      RET from_option #@{location} src (last $ take i nodes);
      xdlchain src nodes dst
    }}}.
  Lemma xdlchain٠prevspechead {src nodes} node dst E :
    head nodes = Some node
    {{{
      xdlchain src nodes dst
    }}}
      (#node).{prev} @ E
    {{{
      RET src;
      xdlchain src nodes dst
    }}}.

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

  Lemma xdlchain٠set_prevspec {src nodes node} nodes' dst v E :
    nodes = node :: nodes'
    {{{
      xdlchain src nodes dst
    }}}
      #node <-{prev} v @ E
    {{{
      RET ();
      xdlchain v nodes dst
    }}}.
  Lemma xdlchain٠set_prevspeclookup {src nodes} i node dst v E :
    nodes !! i = Some node
    {{{
      xdlchain src nodes dst
    }}}
      #node <-{prev} v @ E
    {{{
      RET ();
      xdlchain src (take i nodes) #node
      xdlchain v (drop i nodes) dst
    }}}.
  Lemma xdlchain٠set_prevspechead {src nodes} node dst v E :
    head nodes = Some node
    {{{
      xdlchain src nodes dst
    }}}
      #node <-{prev} v @ E
    {{{
      RET ();
      xdlchain v nodes dst
    }}}.

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

Require zoo_std.xdlchain__opaque.

#[global] Opaque xdlchain.