{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE DerivingVia         #-}
{-# LANGUAGE EmptyCase           #-}
{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE PolyKinds           #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving  #-}
{-# LANGUAGE TypeFamilies        #-}

module Ouroboros.Network.Protocol.PeerSharing.Type where

import Control.DeepSeq

import Codec.Serialise.Class (Serialise)
import Data.Word (Word8)
import GHC.Generics (Generic)

import Network.TypedProtocol.Core

import Ouroboros.Network.Util.ShowProxy (ShowProxy (..))

-- | PeerSharing amount new type.
--
-- We use 'Word8' to be faithful to the CDDL specification.
newtype PeerSharingAmount = PeerSharingAmount { PeerSharingAmount -> Word8
getAmount :: Word8 }
  deriving (PeerSharingAmount -> PeerSharingAmount -> Bool
(PeerSharingAmount -> PeerSharingAmount -> Bool)
-> (PeerSharingAmount -> PeerSharingAmount -> Bool)
-> Eq PeerSharingAmount
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PeerSharingAmount -> PeerSharingAmount -> Bool
== :: PeerSharingAmount -> PeerSharingAmount -> Bool
$c/= :: PeerSharingAmount -> PeerSharingAmount -> Bool
/= :: PeerSharingAmount -> PeerSharingAmount -> Bool
Eq, Int -> PeerSharingAmount -> ShowS
[PeerSharingAmount] -> ShowS
PeerSharingAmount -> String
(Int -> PeerSharingAmount -> ShowS)
-> (PeerSharingAmount -> String)
-> ([PeerSharingAmount] -> ShowS)
-> Show PeerSharingAmount
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PeerSharingAmount -> ShowS
showsPrec :: Int -> PeerSharingAmount -> ShowS
$cshow :: PeerSharingAmount -> String
show :: PeerSharingAmount -> String
$cshowList :: [PeerSharingAmount] -> ShowS
showList :: [PeerSharingAmount] -> ShowS
Show, Eq PeerSharingAmount
Eq PeerSharingAmount =>
(PeerSharingAmount -> PeerSharingAmount -> Ordering)
-> (PeerSharingAmount -> PeerSharingAmount -> Bool)
-> (PeerSharingAmount -> PeerSharingAmount -> Bool)
-> (PeerSharingAmount -> PeerSharingAmount -> Bool)
-> (PeerSharingAmount -> PeerSharingAmount -> Bool)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> Ord PeerSharingAmount
PeerSharingAmount -> PeerSharingAmount -> Bool
PeerSharingAmount -> PeerSharingAmount -> Ordering
PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: PeerSharingAmount -> PeerSharingAmount -> Ordering
compare :: PeerSharingAmount -> PeerSharingAmount -> Ordering
$c< :: PeerSharingAmount -> PeerSharingAmount -> Bool
< :: PeerSharingAmount -> PeerSharingAmount -> Bool
$c<= :: PeerSharingAmount -> PeerSharingAmount -> Bool
<= :: PeerSharingAmount -> PeerSharingAmount -> Bool
$c> :: PeerSharingAmount -> PeerSharingAmount -> Bool
> :: PeerSharingAmount -> PeerSharingAmount -> Bool
$c>= :: PeerSharingAmount -> PeerSharingAmount -> Bool
>= :: PeerSharingAmount -> PeerSharingAmount -> Bool
$cmax :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
max :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$cmin :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
min :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
Ord, (forall x. PeerSharingAmount -> Rep PeerSharingAmount x)
-> (forall x. Rep PeerSharingAmount x -> PeerSharingAmount)
-> Generic PeerSharingAmount
forall x. Rep PeerSharingAmount x -> PeerSharingAmount
forall x. PeerSharingAmount -> Rep PeerSharingAmount x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. PeerSharingAmount -> Rep PeerSharingAmount x
from :: forall x. PeerSharingAmount -> Rep PeerSharingAmount x
$cto :: forall x. Rep PeerSharingAmount x -> PeerSharingAmount
to :: forall x. Rep PeerSharingAmount x -> PeerSharingAmount
Generic)
  deriving (Int -> PeerSharingAmount
PeerSharingAmount -> Int
PeerSharingAmount -> [PeerSharingAmount]
PeerSharingAmount -> PeerSharingAmount
PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
PeerSharingAmount
-> PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
(PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount)
-> (Int -> PeerSharingAmount)
-> (PeerSharingAmount -> Int)
-> (PeerSharingAmount -> [PeerSharingAmount])
-> (PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount])
-> (PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount])
-> (PeerSharingAmount
    -> PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount])
-> Enum PeerSharingAmount
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: PeerSharingAmount -> PeerSharingAmount
succ :: PeerSharingAmount -> PeerSharingAmount
$cpred :: PeerSharingAmount -> PeerSharingAmount
pred :: PeerSharingAmount -> PeerSharingAmount
$ctoEnum :: Int -> PeerSharingAmount
toEnum :: Int -> PeerSharingAmount
$cfromEnum :: PeerSharingAmount -> Int
fromEnum :: PeerSharingAmount -> Int
$cenumFrom :: PeerSharingAmount -> [PeerSharingAmount]
enumFrom :: PeerSharingAmount -> [PeerSharingAmount]
$cenumFromThen :: PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
enumFromThen :: PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
$cenumFromTo :: PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
enumFromTo :: PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
$cenumFromThenTo :: PeerSharingAmount
-> PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
enumFromThenTo :: PeerSharingAmount
-> PeerSharingAmount -> PeerSharingAmount -> [PeerSharingAmount]
Enum, Integer -> PeerSharingAmount
PeerSharingAmount -> PeerSharingAmount
PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
(PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount)
-> (Integer -> PeerSharingAmount)
-> Num PeerSharingAmount
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
$c+ :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
+ :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$c- :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
- :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$c* :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
* :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$cnegate :: PeerSharingAmount -> PeerSharingAmount
negate :: PeerSharingAmount -> PeerSharingAmount
$cabs :: PeerSharingAmount -> PeerSharingAmount
abs :: PeerSharingAmount -> PeerSharingAmount
$csignum :: PeerSharingAmount -> PeerSharingAmount
signum :: PeerSharingAmount -> PeerSharingAmount
$cfromInteger :: Integer -> PeerSharingAmount
fromInteger :: Integer -> PeerSharingAmount
Num, Num PeerSharingAmount
Ord PeerSharingAmount
(Num PeerSharingAmount, Ord PeerSharingAmount) =>
(PeerSharingAmount -> Rational) -> Real PeerSharingAmount
PeerSharingAmount -> Rational
forall a. (Num a, Ord a) => (a -> Rational) -> Real a
$ctoRational :: PeerSharingAmount -> Rational
toRational :: PeerSharingAmount -> Rational
Real, Enum PeerSharingAmount
Real PeerSharingAmount
(Real PeerSharingAmount, Enum PeerSharingAmount) =>
(PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount)
-> (PeerSharingAmount
    -> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount))
-> (PeerSharingAmount
    -> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount))
-> (PeerSharingAmount -> Integer)
-> Integral PeerSharingAmount
PeerSharingAmount -> Integer
PeerSharingAmount
-> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount)
PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
forall a.
(Real a, Enum a) =>
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
$cquot :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
quot :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$crem :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
rem :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$cdiv :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
div :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$cmod :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
mod :: PeerSharingAmount -> PeerSharingAmount -> PeerSharingAmount
$cquotRem :: PeerSharingAmount
-> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount)
quotRem :: PeerSharingAmount
-> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount)
$cdivMod :: PeerSharingAmount
-> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount)
divMod :: PeerSharingAmount
-> PeerSharingAmount -> (PeerSharingAmount, PeerSharingAmount)
$ctoInteger :: PeerSharingAmount -> Integer
toInteger :: PeerSharingAmount -> Integer
Integral, [PeerSharingAmount] -> Encoding
PeerSharingAmount -> Encoding
(PeerSharingAmount -> Encoding)
-> (forall s. Decoder s PeerSharingAmount)
-> ([PeerSharingAmount] -> Encoding)
-> (forall s. Decoder s [PeerSharingAmount])
-> Serialise PeerSharingAmount
forall s. Decoder s [PeerSharingAmount]
forall s. Decoder s PeerSharingAmount
forall a.
(a -> Encoding)
-> (forall s. Decoder s a)
-> ([a] -> Encoding)
-> (forall s. Decoder s [a])
-> Serialise a
$cencode :: PeerSharingAmount -> Encoding
encode :: PeerSharingAmount -> Encoding
$cdecode :: forall s. Decoder s PeerSharingAmount
decode :: forall s. Decoder s PeerSharingAmount
$cencodeList :: [PeerSharingAmount] -> Encoding
encodeList :: [PeerSharingAmount] -> Encoding
$cdecodeList :: forall s. Decoder s [PeerSharingAmount]
decodeList :: forall s. Decoder s [PeerSharingAmount]
Serialise) via Word8

-- | PeerSharing Result type.
--
-- We need a constructor for the case when the Governor wins the race versus
-- the Mux (when initialising the peer sharing miniprotocol). This leads the
-- Governor to lookup a peer that hasn't been registered yet.
data PeerSharingResult peerAddress = PeerSharingResult [peerAddress]
                                   | PeerSharingNotRegisteredYet
                                   deriving (PeerSharingResult peerAddress
-> PeerSharingResult peerAddress -> Bool
(PeerSharingResult peerAddress
 -> PeerSharingResult peerAddress -> Bool)
-> (PeerSharingResult peerAddress
    -> PeerSharingResult peerAddress -> Bool)
-> Eq (PeerSharingResult peerAddress)
forall peerAddress.
Eq peerAddress =>
PeerSharingResult peerAddress
-> PeerSharingResult peerAddress -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall peerAddress.
Eq peerAddress =>
PeerSharingResult peerAddress
-> PeerSharingResult peerAddress -> Bool
== :: PeerSharingResult peerAddress
-> PeerSharingResult peerAddress -> Bool
$c/= :: forall peerAddress.
Eq peerAddress =>
PeerSharingResult peerAddress
-> PeerSharingResult peerAddress -> Bool
/= :: PeerSharingResult peerAddress
-> PeerSharingResult peerAddress -> Bool
Eq, Int -> PeerSharingResult peerAddress -> ShowS
[PeerSharingResult peerAddress] -> ShowS
PeerSharingResult peerAddress -> String
(Int -> PeerSharingResult peerAddress -> ShowS)
-> (PeerSharingResult peerAddress -> String)
-> ([PeerSharingResult peerAddress] -> ShowS)
-> Show (PeerSharingResult peerAddress)
forall peerAddress.
Show peerAddress =>
Int -> PeerSharingResult peerAddress -> ShowS
forall peerAddress.
Show peerAddress =>
[PeerSharingResult peerAddress] -> ShowS
forall peerAddress.
Show peerAddress =>
PeerSharingResult peerAddress -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall peerAddress.
Show peerAddress =>
Int -> PeerSharingResult peerAddress -> ShowS
showsPrec :: Int -> PeerSharingResult peerAddress -> ShowS
$cshow :: forall peerAddress.
Show peerAddress =>
PeerSharingResult peerAddress -> String
show :: PeerSharingResult peerAddress -> String
$cshowList :: forall peerAddress.
Show peerAddress =>
[PeerSharingResult peerAddress] -> ShowS
showList :: [PeerSharingResult peerAddress] -> ShowS
Show)

-- | A kind to identify our protocol, and the types of the states in the state
-- transition diagram of the protocol.
--
data PeerSharing peerAddress where

    -- | The client can send a request and the server is waiting for a request.
    --
    StIdle :: PeerSharing peerAddress

    -- | The server is responsible for sending response back.
    --
    StBusy :: PeerSharing peerAddress

    -- | Both the client and server are in the terminal state. They're done.
    --
    StDone :: PeerSharing peerAddress

instance ShowProxy (PeerSharing peer) where
    showProxy :: Proxy (PeerSharing peer) -> String
showProxy Proxy (PeerSharing peer)
_ = String
"PeerSharing"

data SingPeerSharing (k :: PeerSharing peerAddress) where
    SingIdle :: SingPeerSharing StIdle
    SingBusy :: SingPeerSharing StBusy
    SingDone :: SingPeerSharing StDone

deriving instance Show (SingPeerSharing peerAddress)

instance StateTokenI StIdle where stateToken :: StateToken 'StIdle
stateToken = StateToken 'StIdle
SingPeerSharing 'StIdle
forall {k} {peerAddress :: k}. SingPeerSharing 'StIdle
SingIdle
instance StateTokenI StBusy where stateToken :: StateToken 'StBusy
stateToken = StateToken 'StBusy
SingPeerSharing 'StBusy
forall {k} {peerAddress :: k}. SingPeerSharing 'StBusy
SingBusy
instance StateTokenI StDone where stateToken :: StateToken 'StDone
stateToken = StateToken 'StDone
SingPeerSharing 'StDone
forall {k} {peerAddress :: k}. SingPeerSharing 'StDone
SingDone

instance Protocol (PeerSharing peerAddress) where
  data Message (PeerSharing peerAddress) from to where
    MsgShareRequest :: PeerSharingAmount
                    -> Message (PeerSharing peerAddress) StIdle StBusy
    MsgSharePeers   :: [peerAddress]
                    -> Message (PeerSharing peerAddress) StBusy StIdle
    MsgDone         :: Message (PeerSharing peerAddress) StIdle StDone

  type StateAgency StIdle = ClientAgency
  type StateAgency StBusy = ServerAgency
  type StateAgency StDone = NobodyAgency

  type StateToken = SingPeerSharing

instance NFData peerAddress => NFData (Message (PeerSharing peerAddress) from to) where
  rnf :: Message (PeerSharing peerAddress) from to -> ()
rnf (MsgShareRequest (PeerSharingAmount Word8
m)) = Word8 -> ()
forall a. NFData a => a -> ()
rnf Word8
m
  rnf (MsgSharePeers [peerAddress]
peers)                   = [peerAddress] -> ()
forall a. NFData a => a -> ()
rnf [peerAddress]
peers
  rnf Message (PeerSharing peerAddress) from to
R:MessagePeerSharingfromto (*) peerAddress from to
MsgDone                                 = ()

instance Show peer => Show (Message (PeerSharing peer) from to) where
    show :: Message (PeerSharing peer) from to -> String
show (MsgShareRequest PeerSharingAmount
amount) = String
"MsgShareRequest " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PeerSharingAmount -> String
forall a. Show a => a -> String
show PeerSharingAmount
amount
    show (MsgSharePeers [peerAddress]
resp)     = String
"MsgSharePeers "   String -> ShowS
forall a. [a] -> [a] -> [a]
++ [peerAddress] -> String
forall a. Show a => a -> String
show [peerAddress]
resp
    show Message (PeerSharing peer) from to
R:MessagePeerSharingfromto (*) peer from to
MsgDone                  = String
"MsgDone"

deriving instance (Show peerAddress) => Show (PeerSharing peerAddress)

deriving instance (Eq peerAddress) => Eq (PeerSharing peerAddress)