module posts.agda.typed-protocols where
open import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Relation.Nullary using (¬_)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List
open import Data.Nat
open import Data.Unit using (⊤; tt)
open import Function.Base using (_$_; _|>_)
data PeerRole : Set where
ClientRole : PeerRole
ServerRole : PeerRole
dual-role : PeerRole → PeerRole
dual-role ClientRole = ServerRole
dual-role ServerRole = ClientRole
data Agency : Set where
ClientAgency : Agency
ServerAgency : Agency
NobodyAgency : Agency
data RelativeAgency : Set where
WeHaveAgency : RelativeAgency
TheyHaveAgency : RelativeAgency
NobodyHasAgency : RelativeAgency
relative : PeerRole → Agency → RelativeAgency
relative ClientRole ClientAgency = WeHaveAgency
relative ClientRole ServerAgency = TheyHaveAgency
relative ClientRole NobodyAgency = NobodyHasAgency
relative ServerRole ClientAgency = TheyHaveAgency
relative ServerRole ServerAgency = WeHaveAgency
relative ServerRole NobodyAgency = NobodyHasAgency
exclusion-lemma-client-and-server-have-agency₁
: ∀ {agency : Agency}
{pr : PeerRole}
→ WeHaveAgency ≡ relative pr agency
→ WeHaveAgency ≡ relative (dual-role pr) agency
→ ⊥
exclusion-lemma-client-and-server-have-agency₁
{ClientAgency}
{ClientRole}
refl ()
exclusion-lemma-client-and-server-have-agency₁
{ServerAgency}
{ServerRole}
refl ()
exclusion-lemma-client-and-server-have-agency₂
: ∀ {agency : Agency}
{pr : PeerRole}
→ TheyHaveAgency ≡ relative pr agency
→ TheyHaveAgency ≡ relative (dual-role pr) agency
→ ⊥
exclusion-lemma-client-and-server-have-agency₂
{ServerAgency}
{ClientRole}
refl ()
exclusion-lemma-client-and-server-have-agency₂
{ClientAgency}
{ServerRole}
refl ()
exclusion-lemma-we-have-agency-and-nobody-has-agency
: ∀ {agency : Agency}
{pr : PeerRole}
{pr' : PeerRole}
→ WeHaveAgency ≡ relative pr agency
→ NobodyHasAgency ≡ relative pr' agency
→ ⊥
exclusion-lemma-we-have-agency-and-nobody-has-agency
{ClientAgency}
{ClientRole}
{ServerRole}
refl ()
exclusion-lemma-we-have-agency-and-nobody-has-agency
{ServerAgency}
{ServerRole}
{ClientRole}
refl ()
exclusion-lemma-they-have-agency-and-nobody-has-agency
: ∀ {agency : Agency}
{pr : PeerRole}
{pr' : PeerRole}
→ TheyHaveAgency ≡ relative pr agency
→ NobodyHasAgency ≡ relative pr' agency
→ ⊥
exclusion-lemma-they-have-agency-and-nobody-has-agency
{ServerAgency}
{ClientRole}
{ServerRole}
refl ()
exclusion-lemma-they-have-agency-and-nobody-has-agency
{ClientAgency}
{ServerRole}
{ClientRole}
refl ()
data IsPipelined : Set where
Pipelined : IsPipelined
NonPipelined : IsPipelined
data Trans (ps : Set) : Set where
Tr : ps → ps → Trans ps
data Peer {ps : Set}
(msg : ps → ps → Set)
(agency : ps → Agency)
(pr : PeerRole)
(a : Set)
: IsPipelined
→ List (Trans ps)
→ ps
→ Set where
Yield : ∀ {st st' : ps}
{pl : IsPipelined}
→ WeHaveAgency ≡ relative pr (agency st)
→ msg st st'
→ Peer msg agency pr a pl [] st'
→ Peer msg agency pr a pl [] st
Await : ∀ {st : ps}
{pl : IsPipelined}
→ TheyHaveAgency ≡ relative pr (agency st)
→ (∀ {st' : ps}
→ msg st st'
→ Peer msg agency pr a pl [] st'
)
→ Peer msg agency pr a pl [] st
Done : ∀ {st : ps}
{pl : IsPipelined}
→ NobodyHasAgency ≡ relative pr (agency st)
→ a
→ Peer msg agency pr a pl [] st
YieldPipelined
: ∀ {st st' st'' : ps}
{q : List (Trans ps)}
→ WeHaveAgency ≡ relative pr (agency st)
→ msg st st'
→ Peer msg agency pr a Pipelined (q ∷ʳ Tr st' st'') st''
→ Peer msg agency pr a Pipelined q st
Collect
: ∀ {st st' st'' : ps}
{q : List (Trans ps)}
→ TheyHaveAgency ≡ relative pr (agency st')
→ (∀ {stNext : ps}
→ msg st' stNext
→ Peer msg agency pr a Pipelined (Tr stNext st'' ∷ q) st
)
→ Peer msg agency pr a Pipelined (Tr st' st'' ∷ q) st
CollectDone
: ∀ {st : ps}
{q : List (Trans ps)}
→ Peer msg agency pr a Pipelined q st
→ Peer msg agency pr a Pipelined (Tr st st ∷ q) st
data PingPong : Set where
StIdle : PingPong
StBusy : PingPong
StDone : PingPong
pingPongAgency : PingPong → Agency
pingPongAgency StIdle = ClientAgency
pingPongAgency StBusy = ServerAgency
pingPongAgency StDone = NobodyAgency
data PingPongMsg : ∀ (st st' : PingPong) → Set where
MsgPing : PingPongMsg StIdle StBusy
MsgPong : PingPongMsg StBusy StIdle
MsgDone : PingPongMsg StIdle StDone
ping : Peer PingPongMsg pingPongAgency ClientRole ⊤ NonPipelined [] StIdle
ping =
Yield refl MsgPing
$ await
$ Yield refl MsgPing
$ await
$ Yield refl MsgDone
$ Done refl tt
where
await : Peer PingPongMsg pingPongAgency ClientRole ⊤ NonPipelined [] StIdle
→ Peer PingPongMsg pingPongAgency ClientRole ⊤ NonPipelined [] StBusy
await k = Await refl λ {MsgPong → k}
pipelinedPing
: Peer PingPongMsg pingPongAgency ClientRole ⊤ Pipelined [] StIdle
pipelinedPing =
YieldPipelined refl MsgPing
$ YieldPipelined refl MsgPing
$ YieldPipelined refl MsgPing
$ collect
$ collect
$ collect
$ Yield refl MsgDone
$ Done refl tt
where
collect : ∀ {q : List (Trans PingPong)}
→ Peer PingPongMsg pingPongAgency ClientRole ⊤ Pipelined q StIdle
→ Peer PingPongMsg pingPongAgency ClientRole ⊤ Pipelined
(Tr StBusy StIdle ∷ q) StIdle
collect k =
Collect refl λ {MsgPong → CollectDone k}
data PingPongMsg2 : ∀ (st st' : PingPong) → Set where
MsgPingPong : ∀ {st st' : PingPong}
→ PingPongMsg st st' → PingPongMsg2 st st'
MsgBusy : PingPongMsg2 StBusy StBusy
{-# NON_TERMINATING #-}
pipelinedPing2
: Peer PingPongMsg2 pingPongAgency ClientRole ℕ Pipelined [] StIdle
pipelinedPing2 =
YieldPipelined refl (MsgPingPong MsgPing)
$ YieldPipelined refl (MsgPingPong MsgPing)
$ YieldPipelined refl (MsgPingPong MsgPing)
$ collect 0
$ λ { n1 → collect n1
λ { n2 → collect n2
λ { n3 → Yield refl (MsgPingPong MsgDone)
$ Done refl n3 }}}
where
collect : ∀ {q : List (Trans PingPong)}
→ ℕ
→ (ℕ → Peer PingPongMsg2 pingPongAgency ClientRole ℕ Pipelined q StIdle)
→ Peer PingPongMsg2 pingPongAgency ClientRole ℕ Pipelined
(Tr StBusy StIdle ∷ q) StIdle
collect n k =
Collect refl
λ { MsgBusy → collect (n + 1) k
; (MsgPingPong MsgPong) → CollectDone (k n)
}
data Termination (ps : Set)
(agency : ps → Agency)
(a : Set)
(b : Set)
: Set where
Terminated : ∀ {st : ps} {pr : PeerRole}
→ a
→ b
→ NobodyHasAgency ≡ relative pr (agency st)
→ NobodyHasAgency ≡ relative (dual-role pr) (agency st)
→ Termination ps agency a b
theorem-non-pipelined-duality
: ∀ {ps : Set}
{msg : ps → ps → Set}
{agency : ps → Agency}
{pr : PeerRole}
{a : Set}
{b : Set}
{st : ps}
→ Peer msg agency pr a NonPipelined [] st
→ Peer msg agency (dual-role pr) b NonPipelined [] st
→ Termination ps agency a b
theorem-non-pipelined-duality (Yield _ msg k) (Await _ k') =
theorem-non-pipelined-duality k (k' msg)
theorem-non-pipelined-duality (Await _ k) (Yield _ msg k') =
theorem-non-pipelined-duality (k msg) k'
theorem-non-pipelined-duality (Done termA a) (Done termB b) =
Terminated a b termA termB
theorem-non-pipelined-duality (Yield weHaveAgency _ _)
(Yield theyHaveAgency _ _) =
⊥-elim (exclusion-lemma-client-and-server-have-agency₁ weHaveAgency theyHaveAgency)
theorem-non-pipelined-duality (Await theyHaveAgency _)
(Await weHaveAgency _) =
⊥-elim (exclusion-lemma-client-and-server-have-agency₂ theyHaveAgency weHaveAgency)
theorem-non-pipelined-duality (Yield weHaveAgency _ _)
(Done nobodyHasAgency _) =
⊥-elim (exclusion-lemma-we-have-agency-and-nobody-has-agency
weHaveAgency
nobodyHasAgency)
theorem-non-pipelined-duality (Done nobodyHasAgency _)
(Yield weHaveAgency _ _) =
⊥-elim (exclusion-lemma-we-have-agency-and-nobody-has-agency
weHaveAgency
nobodyHasAgency)
theorem-non-pipelined-duality (Await theyHaveAgency _)
(Done nobodyHasAgency _) =
⊥-elim (exclusion-lemma-they-have-agency-and-nobody-has-agency
theyHaveAgency
nobodyHasAgency)
theorem-non-pipelined-duality (Done nobodyHasAgency _)
(Await theyHaveAgency _) =
⊥-elim (exclusion-lemma-they-have-agency-and-nobody-has-agency
theyHaveAgency
nobodyHasAgency)
data PrQueue {ps : Set}
(msg : ps → ps → Set)
(agency : ps -> Agency)
(pr : PeerRole)
: ps
→ List (Trans ps)
→ ps
→ Set where
ConsMsgQ : ∀ {st st' st'' : ps}
{q : List (Trans ps)}
→ WeHaveAgency ≡ relative pr (agency st)
→ msg st st'
→ PrQueue msg agency pr st' q st''
→ PrQueue msg agency pr st q st''
ConsTrQ : ∀ {st st' st'' : ps}
{q : List (Trans ps)}
→ PrQueue msg agency pr st' q st''
→ PrQueue msg agency pr st (Tr st st' ∷ q) st''
EmptyQ : ∀ {st : ps}
→ PrQueue msg agency pr st [] st
snockMsgQ : ∀ {ps : Set}
{msg : ps → ps → Set}
{agency : ps → Agency}
{pr : PeerRole}
{st st' st'' : ps}
{q : List (Trans ps)}
→ WeHaveAgency ≡ relative pr (agency st')
→ msg st' st''
→ PrQueue msg agency pr st q st'
→ PrQueue msg agency pr st q st''
snockMsgQ tok msg (ConsMsgQ tok' msg' q) = ConsMsgQ tok' msg' (snockMsgQ tok msg q)
snockMsgQ tok msg (ConsTrQ q) = ConsTrQ (snockMsgQ tok msg q)
snockMsgQ tok msg EmptyQ = ConsMsgQ tok msg EmptyQ
snockTrQ : ∀ {ps : Set}
{msg : ps → ps → Set}
{agency : ps → Agency}
{pr : PeerRole}
{st st' st'' : ps}
{q : List (Trans ps)}
→ PrQueue msg agency pr st q st'
→ PrQueue msg agency pr st (q ∷ʳ Tr st' st'') st''
snockTrQ (ConsMsgQ tok msg q) = ConsMsgQ tok msg (snockTrQ q)
snockTrQ (ConsTrQ q) = ConsTrQ (snockTrQ q)
snockTrQ EmptyQ = ConsTrQ EmptyQ
theorem-unpipeline
: ∀ {ps : Set}
{msg : ps → ps → Set}
{agency : ps → Agency}
{pr : PeerRole}
{pl : IsPipelined}
{a : Set}
{stInit : ps}
→ Peer msg agency pr a pl [] stInit
→ Peer msg agency pr a NonPipelined [] stInit
theorem-unpipeline = go EmptyQ
where
go : ∀ {ps : Set}
{msg : ps → ps → Set}
{agency : ps → Agency}
{pr : PeerRole}
{pl : IsPipelined}
{a : Set}
{q : List (Trans ps)}
{st st' : ps}
→ PrQueue msg agency pr st q st'
→ Peer msg agency pr a pl q st'
→ Peer msg agency pr a NonPipelined [] st
go EmptyQ (Done tok a) = Done tok a
go EmptyQ (Yield tok msg k) = Yield tok msg (go EmptyQ k)
go EmptyQ (Await tok k) = Await tok λ {msg → go EmptyQ (k msg)}
go q (YieldPipelined tok msg k) =
go ( q
|> snockMsgQ tok msg
|> snockTrQ
)
k
go (ConsMsgQ tok msg q) k =
Yield tok msg (go q k)
go (ConsTrQ q) (Collect tok k) =
Await tok λ {msg → go (ConsTrQ q) (k msg)}
go (ConsTrQ q) (CollectDone k) =
go q k
theorem-pipelined-duality
: ∀ {ps : Set}
{msg : ps → ps → Set}
{agency : ps → Agency}
{pr : PeerRole}
{pl : IsPipelined}
{a : Set}
{b : Set}
{st : ps}
→ Peer msg agency pr a pl [] st
→ Peer msg agency (dual-role pr) b pl [] st
→ Termination ps agency a b
theorem-pipelined-duality a b =
theorem-non-pipelined-duality (theorem-unpipeline a)
(theorem-unpipeline b)