Module permissions
Require Import Qcanon.
Require Export orders separation_instances.
Local Open Scope Qc_scope.
Definition perm := (
lockable (
counter Qcanon.Qc) + 
Qcanon.Qc)%
type.
Instance perm_sep_ops : 
SeparationOps perm := 
_.
Instance perm_sep : 
Separation perm := 
_.
Typeclasses Opaque perm.
Hint Extern 0 (
Separation _) => 
apply (
_ : 
Separation perm).
Definition perm_readonly : 
perm := 
inr 1.
Definition perm_full : 
perm := 
inl (
LUnlocked (
Counter 0 1)).
Definition perm_token : 
perm := 
inl (
LUnlocked (
Counter (-1) ∅)).
Inductive pkind :=
  
Writable | 
Readable | 
Locked | 
Existing.
Instance pkind_dec (
k1 k2 : 
pkind) : 
Decision (
k1 = 
k2).
Proof.
 solve_decision. Defined.
Instance pkind_subseteq : 
SubsetEq pkind := λ 
k1 k2,
  
match k1, 
k2 with
  | 
_, 
Writable => 
True
  | (
Existing | 
Readable), 
Readable => 
True
  | 
Existing, 
Existing => 
True
  | (
Existing | 
Locked), 
Locked => 
True
  | 
_, 
_ => 
False
  end.
Instance pkind_subseteq_dec : ∀ 
k1 k2 : 
pkind, 
Decision (
k1 ⊆ 
k2).
Proof.
 intros [] []; apply _. Defined.
Instance: 
PartialOrder (@
subseteq pkind _).
Proof.
 by repeat split; repeat intros []. Qed.
Instance option_pkind_subseteq : 
SubsetEq (
option pkind) := λ 
k1 k2,
  
match k1, 
k2 with
  | 
Some k1, 
Some k2 => 
k1 ⊆ 
k2 | 
None, 
_ => 
True | 
Some _, 
None => 
False
  end.
Instance option_pkind_subseteq_dec : ∀ 
k1 k2 : 
option pkind, 
Decision (
k1 ⊆ 
k2).
Proof.
 intros [] []; apply _. Defined.
Instance: 
PartialOrder (@
subseteq (
option pkind) 
_).
Proof.
 by repeat split; repeat intros []. Qed.
Definition perm_kind (γ : 
perm) : 
option pkind :=
  
match γ 
with
  | 
inl (
LUnlocked (
Counter x' 
y')) =>
     
if decide (
y' = ∅) 
then
       if decide (
x' = 0) 
then None else Some Existing
     else if decide (
y' = 1) 
then Some Writable else Some Readable
  | 
inl (
LLocked _) => 
Some Locked
  | 
inr x' => 
Some Readable
  end.
Definition perm_locked (γ : 
perm) : 
bool :=
  
match γ 
with inl (
LLocked _) => 
true | 
_ => 
false end.
Definition perm_lock (γ : 
perm) : 
perm :=
  
match γ 
with inl (
LUnlocked x') => 
inl (
LLocked x') | 
_ => γ 
end.
Definition perm_unlock (γ : 
perm) : 
perm :=
  
match γ 
with inl (
LLocked x') => 
inl (
LUnlocked x') | 
_ => γ 
end.
Inductive perm_kind_view : 
perm → 
option pkind → 
Prop :=
  | 
perm_kind_None : 
perm_kind_view (
inl (
LUnlocked (
Counter ∅ 0))) 
None
  | 
perm_kind_Locked x' : 
perm_kind_view (
inl (
LLocked x')) (
Some Locked)
  | 
perm_kind_Existing x' :
     
x' ≠ 0 → 
perm_kind_view (
inl (
LUnlocked (
Counter x' ∅))) (
Some Existing)
  | 
perm_kind_Readable x' 
y' :
     
y' ≠ ∅ → 
y' ≠ 1 →
     
perm_kind_view (
inl (
LUnlocked (
Counter x' 
y'))) (
Some Readable)
  | 
perm_kind_Writable x' :
     
perm_kind_view (
inl (
LUnlocked (
Counter x' 1))) (
Some Writable)
  | 
perm_kind_Writable' 
x' :
     
x' ≠ 0 → 
perm_kind_view (
inl (
LUnlocked (
Counter x' 1))) (
Some Writable)
  | 
perm_kind_ro_Readable x' : 
perm_kind_view (
inr x') (
Some Readable).
Lemma perm_kind_spec γ : 
perm_kind_view γ (
perm_kind γ).
Proof.
  destruct γ as [[[]|[]]|]; simpl; repeat case_decide;
    intuition; simplify_equality'; constructor; auto.
Qed.
Arguments perm_kind _ : 
simpl never.
Lemma perm_full_valid : 
sep_valid perm_full.
Proof.
 done. Qed.
Lemma perm_full_mapped : ¬
sep_unmapped perm_full.
Proof.
 by apply (bool_decide_unpack _). Qed.
Lemma perm_full_unshared : 
sep_unshared perm_full.
Proof.
 by apply (bool_decide_unpack _). Qed.
Lemma perm_subseteq_full γ1 γ2 : γ1 = 
perm_full → γ1 ⊆ γ2 → γ2 = 
perm_full.
Proof.
  intros ->; destruct γ2 as [[[??]|[c x]]|?];
    repeat sep_unfold; unfold perm_full; intuition; simplify_equality.
  assert (x = 1) as -> by eauto using Qcle_antisym.
  by assert (c = 0) as -> by eauto using Qcle_antisym.
Qed.
Lemma perm_readonly_valid : 
sep_valid perm_readonly.
Proof.
 done. Qed.
Lemma perm_readonly_mapped : ¬
sep_unmapped perm_readonly.
Proof.
 by apply (bool_decide_unpack _). Qed.
Lemma perm_token_valid : 
sep_valid perm_token.
Proof.
 done. Qed.
Lemma perm_locked_mapped γ : 
perm_locked γ = 
true → ¬
sep_unmapped γ.
Proof.
 destruct γ as [[[]|]|[]]; repeat sep_unfold; naive_solver. Qed.
Lemma perm_Readable_locked γ :
  
Some Readable ⊆ 
perm_kind γ → 
perm_locked γ = 
false.
Proof.
 by destruct (perm_kind_spec γ). Qed.
Lemma perm_locked_lock γ :
  
Some Writable ⊆ 
perm_kind γ → 
perm_locked (
perm_lock γ) = 
true.
Proof.
 by destruct (perm_kind_spec γ). Qed.
Lemma perm_locked_unlock γ : 
perm_locked (
perm_unlock γ) = 
false.
Proof.
 by destruct γ as [[]|[]]. Qed.
Lemma perm_lock_valid γ :
  
sep_valid γ → 
Some Writable ⊆ 
perm_kind γ → 
sep_valid (
perm_lock γ).
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; intuition. Qed.
Lemma perm_lock_empty γ : 
perm_lock γ = ∅ → γ = ∅.
Proof.
 by destruct γ as [[]|?]. Qed.
Lemma perm_lock_unmapped γ :
  
Some Writable ⊆ 
perm_kind γ → 
sep_unmapped γ → 
sep_unmapped (
perm_lock γ).
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; naive_solver. Qed.
Lemma perm_lock_mapped γ : 
sep_unmapped (
perm_lock γ) → 
sep_unmapped γ.
Proof.
 destruct γ as [[]|[]]; repeat sep_unfold; intuition. Qed.
Lemma perm_lock_unshared γ : 
sep_unshared γ → 
sep_unshared (
perm_lock γ).
Proof.
 destruct γ as [[]|[]]; repeat sep_unfold; intuition. Qed.
Lemma perm_unlock_lock γ :
  
sep_valid γ → 
Some Writable ⊆ 
perm_kind γ → 
perm_unlock (
perm_lock γ) = γ.
Proof.
 by destruct (perm_kind_spec γ). Qed.
Lemma perm_unlock_unlock γ : 
perm_unlock (
perm_unlock γ) = 
perm_unlock γ.
Proof.
 by destruct γ as [[]|]. Qed.
Lemma perm_unlock_valid γ : 
sep_valid γ → 
sep_valid (
perm_unlock γ).
Proof.
 destruct γ as [[[]|[]]|]; repeat sep_unfold; naive_solver. Qed.
Lemma perm_unlock_empty γ : 
sep_valid γ → 
perm_unlock γ = ∅ → γ = ∅.
Proof.
 destruct γ as [[]|?]; repeat sep_unfold; naive_solver. Qed.
Lemma perm_unlock_unmapped γ : 
sep_unmapped γ → 
sep_unmapped (
perm_unlock γ).
Proof.
 destruct γ as [[[]|[]]|]; repeat sep_unfold; intuition. Qed.
Lemma perm_unlock_mapped γ :
  
sep_valid γ → 
sep_unmapped (
perm_unlock γ) → 
sep_unmapped γ.
Proof.
 destruct γ as [[[]|[]]|[]]; repeat sep_unfold; naive_solver. Qed.
Lemma perm_unlock_unshared γ : 
sep_unshared γ → 
sep_unshared (
perm_unlock γ).
Proof.
 destruct γ as [[]|[]]; repeat sep_unfold; intuition. Qed.
Lemma perm_unlock_shared γ :
  
sep_valid γ → 
sep_unshared (
perm_unlock γ) → 
sep_unshared γ.
Proof.
 destruct γ as [[]|[]]; repeat sep_unfold; intuition. Qed.
Lemma perm_unshared γ :
  
sep_valid γ → 
Some Locked ⊆ 
perm_kind γ → 
sep_unshared γ.
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; intuition. Qed.
Lemma perm_mapped γ : 
Some Readable ⊆ 
perm_kind γ → ¬
sep_unmapped γ.
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; naive_solver. Qed.
Lemma perm_unmapped γ :
  
sep_valid γ → 
perm_kind γ = 
Some Existing → 
sep_unmapped γ.
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; naive_solver. Qed.
Lemma perm_None_unmapped γ : 
sep_valid γ → 
perm_kind γ = 
None → 
sep_unmapped γ.
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; naive_solver. Qed.
Lemma perm_token_subseteq γ :
  
sep_valid γ → 
Some Writable ⊆ 
perm_kind γ → 
perm_token ⊂ γ.
Proof.
  assert (∀ x', x' - 0 = 0 → x' = 0).
  { intros x'. change (x' - 0) with (x' + 0). by rewrite Qcplus_0_r. }
  rewrite strict_spec_alt. unfold perm_token.
  destruct (perm_kind_spec γ); repeat sep_unfold; (split; [|intro]);
    simplify_equality'; intuition; exfalso; auto.
Qed.
Lemma perm_splittable γ :
  
sep_valid γ → 
Some Readable ⊆ 
perm_kind γ → 
sep_splittable γ.
Proof.
 destruct (perm_kind_spec γ); repeat sep_unfold; intuition. Qed.
Lemma perm_splittable_existing γ :
  
sep_valid γ → 
perm_kind γ = 
Some Existing → 
sep_splittable γ.
Proof.
 by destruct (perm_kind_spec γ); repeat sep_unfold. Qed.
Lemma perm_kind_full : 
perm_kind perm_full = 
Some Writable.
Proof.
 done. Qed.
Lemma perm_kind_lock γ :
  
Some Writable ⊆ 
perm_kind γ → 
perm_kind (
perm_lock γ) = 
Some Locked.
Proof.
 by destruct (perm_kind_spec γ). Qed.
Lemma perm_kind_half γ :
  
sep_valid γ → 
perm_kind (½ γ) =
    
match perm_kind γ 
with 
    | 
Some Writable => 
Some Readable | 
_ => 
perm_kind γ
    
end.
Proof.
  assert (∀ x', x' / 2 = 0 → x' = 0).
  { intros. by apply Qcmult_integral_l with (/2); rewrite 1?Qcmult_comm. }
  assert (∀ x', x' / 2 = 1 → x' ≤ 1 → False).
  { intros x'. rewrite (Qcmult_le_mono_pos_r _ _ (/2)) by done.
    by intros -> []. }
  repeat sep_unfold; destruct (perm_kind_spec γ); unfold perm_kind; simpl;
    intros; by rewrite ?decide_False by intuition eauto.
Qed.
Lemma perm_kind_token : 
perm_kind perm_token = 
Some Existing.
Proof.
 done. Qed.
Lemma perm_kind_difference_token γ :
  
perm_token ⊂ γ → 
perm_kind (γ ∖ 
perm_token) = 
perm_kind γ.
Proof.
  rewrite strict_spec_alt.
  destruct (perm_kind_spec γ) as [| |y| | |y|]; repeat sep_unfold;
    unfold perm_kind; simpl; intros [? Hneq]; auto.
  * assert (¬0 ≤ -1) by (by intros []); intuition.
  * assert (y ≤ -1 → y ≤ 0) by (by intros; transitivity (-1)).
    assert (y --1 ≠ 0).
    { change 0 with (-1 + 1); rewrite Qcopp_involutive,
        (injective_iff (λ x, x + 1)); contradict Hneq.
      symmetry. unfold perm_token; repeat f_equal; intuition. }
    by rewrite decide_False by done.
  * by change (-0) with 0; rewrite Qcplus_0_r, !decide_False by done.
Qed.
Lemma perm_kind_subseteq γ1 γ2 : γ1 ⊆ γ2 → 
perm_kind γ1 ⊆ 
perm_kind γ2.
Proof.
  destruct γ1 as [[[x1 y1]|[x1 y1]]|x1], γ2 as [[[x2 y2]|[x2 y2]]|x2];
    unfold perm_kind; repeat sep_unfold;
    repeat case_decide; naive_solver eauto using Qcle_antisym.
Qed.
Lemma perm_lock_disjoint γ1 γ2 :
  
Some Writable ⊆ 
perm_kind γ1 → γ1 ⊥ γ2 → 
perm_lock γ1 ⊥ γ2.
Proof.
  assert (¬2 ≤ 1) by (by intros []).
  assert (∀ x, 0 ≤ x → 1 + x ≤ 1 → x = 0).
  { intros x ? Hx. apply (Qcplus_le_mono_l x 0 1) in Hx.
    auto using Qcle_antisym. }
  destruct (perm_kind_spec γ1), γ2 as [[[x2 y2]|[x2 y2]]|];
    repeat sep_unfold; intuition; simplify_equality'; try done.
  * assert (y2 = 0) as -> by auto.
    rewrite (Qcplus_le_mono_r _ _ x2), Qcplus_0_l. eauto using Qcle_trans.
  * assert (y2 = 0) as -> by auto.
    rewrite (Qcplus_le_mono_r _ _ x2), Qcplus_0_l. eauto using Qcle_trans.
Qed.
Lemma perm_lock_union γ1 γ2 : 
perm_lock (γ1 ∪ γ2) = 
perm_lock γ1 ∪ γ2.
Proof.
 by destruct γ1 as [[]|], γ2 as [[]|]. Qed.
Lemma perm_unlock_disjoint γ1 γ2 : γ1 ⊥ γ2 → 
perm_unlock γ1 ⊥ γ2.
Proof.
 destruct γ1 as [[]|], γ2 as [[]|]; repeat sep_unfold; naive_solver. Qed.
Lemma perm_unlock_union γ1 γ2 :
  γ1 ⊥ γ2 → 
perm_locked γ1 → 
perm_unlock (γ1 ∪ γ2) = 
perm_unlock γ1 ∪ γ2.
Proof.
 by destruct γ1 as [[]|], γ2 as [[]|]. Qed.
Lemma perm_disjoint_full γ : 
perm_full ⊥ γ → γ = ∅.
Proof.
  destruct γ as [[[x y]|[x y]]|];
    repeat sep_unfold; intuition; simplify_equality'.
  assert (y = 0) as ->.
  { apply Qcle_antisym; auto. by apply (Qcplus_le_mono_l y 0 1). }
  repeat f_equal; apply Qcle_antisym; auto; rewrite <-(Qcplus_0_l x); auto.
Qed.