{-# LANGUAGE KindSignatures      #-}
{-# LANGUAGE NamedFieldPuns      #-}
{-# LANGUAGE PatternSynonyms     #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns        #-}

-- | Inbound protocol governor state.
--
-- The module should be imported qualified.
--
module Ouroboros.Network.InboundGovernor.State
  ( PublicState (..)
    -- * Internals
  , mkPublicState
  , State (..)
  , ConnectionState (..)
  , Counters (..)
  , counters
  , unregisterConnection
  , updateMiniProtocol
  , RemoteState (.., RemoteEstablished)
  , RemoteSt (..)
  , mkRemoteSt
  , updateRemoteState
  , mapRemoteState
  , MiniProtocolData (..)
  ) where

import Control.Concurrent.Class.MonadSTM.Strict
import Control.Exception (assert)
import Control.Monad.Class.MonadThrow hiding (handle)
import Control.Monad.Class.MonadTime.SI

import Data.ByteString.Lazy (ByteString)
import Data.Cache (Cache)
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.OrdPSQ as OrdPSQ

import Network.Mux qualified as Mux

import Ouroboros.Network.Context
import Ouroboros.Network.Mux


-- | Public inbound governor state.
--
data PublicState peerAddr versionData = PublicState {
      -- | A map of mature inbound duplex connections. These peers are used for
      -- light peer sharing (e.g. bootstrapping peer sharing).
      --
      forall peerAddr versionData.
PublicState peerAddr versionData -> Map peerAddr versionData
inboundDuplexPeers :: !(Map peerAddr versionData),

      -- | Map of `RemoteSt`.
      --
      -- It is lazy on purpose.  It is created from `igsConnections`, so it
      -- should not point to any thunks that should be GC-ed leading to a memory
      -- leak.
      --
      forall peerAddr versionData.
PublicState peerAddr versionData
-> Map (ConnectionId peerAddr) RemoteSt
remoteStateMap     :: Map (ConnectionId peerAddr) RemoteSt

    }


-- | Smart constructor for `PublicState`.
--
-- NOTE: we assume that all inbound connections share the same address.  This
-- is true in P2P mode since all outbound connections (which also can end up in
-- the `State`) bind the server address.  This allows us to use
-- `Map.mapKeysMonotonic`.
--
mkPublicState
  :: forall muxMode initatorCtx versionData peerAddr m a b.
     State muxMode initatorCtx peerAddr versionData m a b
  -> PublicState peerAddr versionData
mkPublicState :: forall (muxMode :: MuxMode) initatorCtx versionData peerAddr
       (m :: * -> *) a b.
State muxMode initatorCtx peerAddr versionData m a b
-> PublicState peerAddr versionData
mkPublicState
    State { Map
  (ConnectionId peerAddr)
  (ConnectionState muxMode initatorCtx peerAddr versionData m a b)
connections :: Map
  (ConnectionId peerAddr)
  (ConnectionState muxMode initatorCtx peerAddr versionData m a b)
connections :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> Map
     (ConnectionId peerAddr)
     (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
connections, Map peerAddr versionData
matureDuplexPeers :: Map peerAddr versionData
matureDuplexPeers :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> Map peerAddr versionData
matureDuplexPeers }
    =
    PublicState {
      inboundDuplexPeers :: Map peerAddr versionData
inboundDuplexPeers = Map peerAddr versionData
matureDuplexPeers,
      remoteStateMap :: Map (ConnectionId peerAddr) RemoteSt
remoteStateMap     = (ConnectionState muxMode initatorCtx peerAddr versionData m a b
 -> RemoteSt)
-> Map
     (ConnectionId peerAddr)
     (ConnectionState muxMode initatorCtx peerAddr versionData m a b)
-> Map (ConnectionId peerAddr) RemoteSt
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map (RemoteState m -> RemoteSt
forall (m :: * -> *). RemoteState m -> RemoteSt
mkRemoteSt (RemoteState m -> RemoteSt)
-> (ConnectionState muxMode initatorCtx peerAddr versionData m a b
    -> RemoteState m)
-> ConnectionState muxMode initatorCtx peerAddr versionData m a b
-> RemoteSt
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionState muxMode initatorCtx peerAddr versionData m a b
-> RemoteState m
forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> RemoteState m
csRemoteState) Map
  (ConnectionId peerAddr)
  (ConnectionState muxMode initatorCtx peerAddr versionData m a b)
connections
    }

-- | 'State', which consist of pure part, and a mutable part. The mutable part
-- can be observable from outside.  Future version could
-- contain additional statistics on the peers.
--
data State muxMode initiatorCtx peerAddr versionData m a b =
    State {
        -- | Map of connections state.  Modifying 'igsConnections' outside of
        -- 'inboundGovernorLoop' is not safe.
        --
        forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> Map
     (ConnectionId peerAddr)
     (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
connections   :: !(Map (ConnectionId peerAddr)
                                  (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)),

        -- | Map of mature duplex peers.
        --
        -- We don't add new duplex connections immediately, but only after
        -- a 15mins delay (defined in `inboundMaturePeerDelay`.
        --
        forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> Map peerAddr versionData
matureDuplexPeers :: !(Map peerAddr versionData),

        -- | Queue of fresh duplex connections ordered by time of arrival.  Only
        -- connections younger than than 15mins are kept in this data structure.
        --
        forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> OrdPSQ peerAddr Time versionData
freshDuplexPeers :: !(OrdPSQ peerAddr Time versionData),

        -- | 'Counters' counters cache. Allows to only trace values when
        -- necessary.
        forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> Cache Counters
countersCache :: !(Cache Counters)
      }

-- | Counters for tracing and analysis purposes
--
data Counters = Counters {
      Counters -> Int
coldPeersRemote :: !Int,
      -- ^ the number of remote peers which are in 'RemoteCold' state
      Counters -> Int
idlePeersRemote :: !Int,
      -- ^ the number of remote peers which are in 'RemoteIdle' state
      Counters -> Int
warmPeersRemote :: !Int,
      -- ^ the number of remote peers which are in 'RemoteWarm' state (a close
      -- approximation of peers that have the node as a warm peer)
      Counters -> Int
hotPeersRemote  :: !Int
      -- ^ the number of remote peers which are in 'RemoteHot' state (a close
      -- approximation of peers that have the node as a hot peer)
    }
  deriving (Counters -> Counters -> Bool
(Counters -> Counters -> Bool)
-> (Counters -> Counters -> Bool) -> Eq Counters
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Counters -> Counters -> Bool
== :: Counters -> Counters -> Bool
$c/= :: Counters -> Counters -> Bool
/= :: Counters -> Counters -> Bool
Eq, Eq Counters
Eq Counters =>
(Counters -> Counters -> Ordering)
-> (Counters -> Counters -> Bool)
-> (Counters -> Counters -> Bool)
-> (Counters -> Counters -> Bool)
-> (Counters -> Counters -> Bool)
-> (Counters -> Counters -> Counters)
-> (Counters -> Counters -> Counters)
-> Ord Counters
Counters -> Counters -> Bool
Counters -> Counters -> Ordering
Counters -> Counters -> Counters
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 :: Counters -> Counters -> Ordering
compare :: Counters -> Counters -> Ordering
$c< :: Counters -> Counters -> Bool
< :: Counters -> Counters -> Bool
$c<= :: Counters -> Counters -> Bool
<= :: Counters -> Counters -> Bool
$c> :: Counters -> Counters -> Bool
> :: Counters -> Counters -> Bool
$c>= :: Counters -> Counters -> Bool
>= :: Counters -> Counters -> Bool
$cmax :: Counters -> Counters -> Counters
max :: Counters -> Counters -> Counters
$cmin :: Counters -> Counters -> Counters
min :: Counters -> Counters -> Counters
Ord, Int -> Counters -> ShowS
[Counters] -> ShowS
Counters -> String
(Int -> Counters -> ShowS)
-> (Counters -> String) -> ([Counters] -> ShowS) -> Show Counters
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Counters -> ShowS
showsPrec :: Int -> Counters -> ShowS
$cshow :: Counters -> String
show :: Counters -> String
$cshowList :: [Counters] -> ShowS
showList :: [Counters] -> ShowS
Show)

instance Semigroup Counters where
    Counters Int
c Int
i Int
w Int
h <> :: Counters -> Counters -> Counters
<> Counters Int
c' Int
i' Int
w' Int
h' =
      Int -> Int -> Int -> Int -> Counters
Counters (Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
c') (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i') (Int
w Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
w') (Int
h Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
h')

instance Monoid Counters where
    mempty :: Counters
mempty = Int -> Int -> Int -> Int -> Counters
Counters Int
0 Int
0 Int
0 Int
0


counters :: State muxMode initiatorCtx peerAddr versionData m a b
         -> Counters
counters :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b -> Counters
counters State { Map
  (ConnectionId peerAddr)
  (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
connections :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
State muxMode initiatorCtx peerAddr versionData m a b
-> Map
     (ConnectionId peerAddr)
     (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
connections :: Map
  (ConnectionId peerAddr)
  (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
connections } =
    (ConnectionState muxMode initiatorCtx peerAddr versionData m a b
 -> Counters)
-> Map
     (ConnectionId peerAddr)
     (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
-> Counters
forall m a.
Monoid m =>
(a -> m) -> Map (ConnectionId peerAddr) a -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (\ConnectionState { RemoteState m
csRemoteState :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> RemoteState m
csRemoteState :: RemoteState m
csRemoteState } ->
              case RemoteState m
csRemoteState of
                RemoteState m
RemoteCold    -> Int -> Int -> Int -> Int -> Counters
Counters Int
1 Int
0 Int
0 Int
0
                RemoteIdle {} -> Int -> Int -> Int -> Int -> Counters
Counters Int
0 Int
1 Int
0 Int
0
                RemoteState m
RemoteWarm    -> Int -> Int -> Int -> Int -> Counters
Counters Int
0 Int
0 Int
1 Int
0
                RemoteState m
RemoteHot     -> Int -> Int -> Int -> Int -> Counters
Counters Int
0 Int
0 Int
0 Int
1
            )
            Map
  (ConnectionId peerAddr)
  (ConnectionState muxMode initiatorCtx peerAddr versionData m a b)
connections


data MiniProtocolData muxMode initiatorCtx peerAddr m a b = MiniProtocolData {
    -- | Static 'MiniProtocol' description.
    --
    forall (muxMode :: MuxMode) initiatorCtx peerAddr (m :: * -> *) a
       b.
MiniProtocolData muxMode initiatorCtx peerAddr m a b
-> MiniProtocol
     muxMode initiatorCtx (ResponderContext peerAddr) ByteString m a b
mpdMiniProtocol     :: !(MiniProtocol muxMode initiatorCtx (ResponderContext peerAddr) ByteString m a b),

    forall (muxMode :: MuxMode) initiatorCtx peerAddr (m :: * -> *) a
       b.
MiniProtocolData muxMode initiatorCtx peerAddr m a b
-> ResponderContext peerAddr
mpdResponderContext :: !(ResponderContext peerAddr),

    -- | Static mini-protocol temperature.
    --
    forall (muxMode :: MuxMode) initiatorCtx peerAddr (m :: * -> *) a
       b.
MiniProtocolData muxMode initiatorCtx peerAddr m a b
-> ProtocolTemperature
mpdMiniProtocolTemp :: !ProtocolTemperature
  }


-- | Per connection state tracked by /inbound protocol governor/.
--
data ConnectionState muxMode initiatorCtx peerAddr versionData m a b = ConnectionState {
      -- | Mux interface.
      --
      forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> Mux muxMode m
csMux             :: !(Mux.Mux muxMode m),

      -- | version data negotiated on the connection.
      --
      forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> versionData
csVersionData     :: !versionData,

      -- | All supported mini-protocols and respective
      -- 'ProtocolTemperature'
      --
      forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> Map
     MiniProtocolNum
     (MiniProtocolData muxMode initiatorCtx peerAddr m a b)
csMiniProtocolMap :: !(Map MiniProtocolNum
                                 (MiniProtocolData muxMode initiatorCtx peerAddr m a b)),

      -- | Map of all running mini-protocol completion STM actions.
      --
      forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> Map MiniProtocolNum (STM m (Either SomeException b))
csCompletionMap   :: !(Map MiniProtocolNum
                                 (STM m (Either SomeException b))),

      -- | State of the connection.
      --
      forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> RemoteState m
csRemoteState     :: !(RemoteState m)

    }


--
-- State management functions
--


-- | Remove connection from 'State'.
--
unregisterConnection :: Ord peerAddr
                     => ConnectionId peerAddr
                     -> State muxMode initiatorCtx peerAddr versionData m a b
                     -> State muxMode initiatorCtx peerAddr versionData m a b
unregisterConnection :: forall peerAddr (muxMode :: MuxMode) initiatorCtx versionData
       (m :: * -> *) a b.
Ord peerAddr =>
ConnectionId peerAddr
-> State muxMode initiatorCtx peerAddr versionData m a b
-> State muxMode initiatorCtx peerAddr versionData m a b
unregisterConnection ConnectionId peerAddr
connId State muxMode initiatorCtx peerAddr versionData m a b
state =
    State muxMode initiatorCtx peerAddr versionData m a b
state { connections =
              assert (connId `Map.member` connections state) $
              Map.delete connId (connections state),

            matureDuplexPeers =
              Map.delete (remoteAddress connId) (matureDuplexPeers state),

            freshDuplexPeers =
              OrdPSQ.delete (remoteAddress connId) (freshDuplexPeers state)
          }


-- | Update a mini-protocol in 'ConnectionState'.  Once a mini-protocol was
-- restarted we put the new completion action into 'csCompletionMap'.
--
updateMiniProtocol :: Ord peerAddr
                   => ConnectionId peerAddr
                   -> MiniProtocolNum
                   -> STM m (Either SomeException b)
                   -> State muxMode initiatorCtx peerAddr versionData m a b
                   -> State muxMode initiatorCtx peerAddr versionData m a b
updateMiniProtocol :: forall peerAddr (m :: * -> *) b (muxMode :: MuxMode) initiatorCtx
       versionData a.
Ord peerAddr =>
ConnectionId peerAddr
-> MiniProtocolNum
-> STM m (Either SomeException b)
-> State muxMode initiatorCtx peerAddr versionData m a b
-> State muxMode initiatorCtx peerAddr versionData m a b
updateMiniProtocol ConnectionId peerAddr
connId MiniProtocolNum
miniProtocolNum STM m (Either SomeException b)
completionAction State muxMode initiatorCtx peerAddr versionData m a b
state =
    State muxMode initiatorCtx peerAddr versionData m a b
state { connections =
              Map.adjust (\connState :: ConnectionState muxMode initiatorCtx peerAddr versionData m a b
connState@ConnectionState { Map MiniProtocolNum (STM m (Either SomeException b))
csCompletionMap :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> Map MiniProtocolNum (STM m (Either SomeException b))
csCompletionMap :: Map MiniProtocolNum (STM m (Either SomeException b))
csCompletionMap } ->
                           ConnectionState muxMode initiatorCtx peerAddr versionData m a b
connState {
                             csCompletionMap =
                               assert (miniProtocolNum `Map.member` csCompletionMap) $
                               Map.insert miniProtocolNum
                                          completionAction
                                          csCompletionMap
                            }
                         )
                         connId
                         (connections state)
          }


-- | Each inbound connection is either in 'RemoteIdle', 'RemoteCold' or
-- 'RemoteEstablished' state.  We only need to support
-- @PromotedToWarm^{Duplex}_{Remote}@,
-- @DemotedToCold^{Duplex}_{Remote}@ and
-- @DemotedToCold^{Unidirectional}_{Remote}@ transitions.
--
data RemoteState m
    -- | After @PromotedToWarm^{dataFlow}_{Remote}@ a connection is in
    -- 'RemoteWarm' state.
    --
    = RemoteWarm

    -- | In this state all established and hot mini-protocols are running and
    -- none of the warm mini-protocols is running.
    --
    | RemoteHot

    -- | After @DemotedToCold^{dataFlow}_{Remote}@ is detected.  This state
    -- corresponds to 'InboundIdleState'. In this state we are checking
    -- if the responder protocols are idle during protocol idle timeout
    -- (represented by an 'STM' action)
    --
    -- 'RemoteIdle' is the initial state of an accepted a connection.
    --
    | RemoteIdle !(STM m ())

    -- | The 'RemoteCold' state for 'Duplex' connections allows us to have
    -- responders started using the on-demand strategy.  This assures that once
    -- the remote peer start using the connection the local side will be ready
    -- to serve it.
    --
    -- For a 'Duplex' connection: a 'RemoteIdle' connection transitions to
    -- 'RemoteCold' state after all responders being idle for
    -- @protocolIdleTimeout@. This triggers 'unregisterInboundConnection'.
    --
    -- For a 'Unidreictional' connection: after all responders terminated.
    --
    | RemoteCold


remoteEstablished :: RemoteState m -> Maybe (RemoteState m)
remoteEstablished :: forall (m :: * -> *). RemoteState m -> Maybe (RemoteState m)
remoteEstablished a :: RemoteState m
a@RemoteState m
RemoteWarm = RemoteState m -> Maybe (RemoteState m)
forall a. a -> Maybe a
Just RemoteState m
a
remoteEstablished a :: RemoteState m
a@RemoteState m
RemoteHot  = RemoteState m -> Maybe (RemoteState m)
forall a. a -> Maybe a
Just RemoteState m
a
remoteEstablished RemoteState m
_            = Maybe (RemoteState m)
forall a. Maybe a
Nothing

pattern RemoteEstablished :: RemoteState m
pattern $mRemoteEstablished :: forall {r} {m :: * -> *}.
RemoteState m -> ((# #) -> r) -> ((# #) -> r) -> r
RemoteEstablished <- (remoteEstablished -> Just _)

{-# COMPLETE RemoteEstablished, RemoteIdle, RemoteCold #-}


-- | Set 'csRemoteState' for a given connection.
--
updateRemoteState :: Ord peerAddr
                  => ConnectionId peerAddr
                  -> RemoteState m
                  -> State muxMode initiatorCtx peerAddr versionData m a b
                  -> State muxMode initiatorCtx peerAddr versionData m a b
updateRemoteState :: forall peerAddr (m :: * -> *) (muxMode :: MuxMode) initiatorCtx
       versionData a b.
Ord peerAddr =>
ConnectionId peerAddr
-> RemoteState m
-> State muxMode initiatorCtx peerAddr versionData m a b
-> State muxMode initiatorCtx peerAddr versionData m a b
updateRemoteState ConnectionId peerAddr
connId RemoteState m
csRemoteState State muxMode initiatorCtx peerAddr versionData m a b
state =
    State muxMode initiatorCtx peerAddr versionData m a b
state {
      connections =
        Map.adjust
          (\ConnectionState muxMode initiatorCtx peerAddr versionData m a b
connState -> ConnectionState muxMode initiatorCtx peerAddr versionData m a b
connState { csRemoteState })
          connId
          (connections state)
    }

mapRemoteState :: Ord peerAddr
               => ConnectionId peerAddr
               -> (RemoteState m -> RemoteState m)
               -> State muxMode initiatorCtx peerAddr versionData m a b
               -> State muxMode initiatorCtx peerAddr versionData m a b
mapRemoteState :: forall peerAddr (m :: * -> *) (muxMode :: MuxMode) initiatorCtx
       versionData a b.
Ord peerAddr =>
ConnectionId peerAddr
-> (RemoteState m -> RemoteState m)
-> State muxMode initiatorCtx peerAddr versionData m a b
-> State muxMode initiatorCtx peerAddr versionData m a b
mapRemoteState ConnectionId peerAddr
connId RemoteState m -> RemoteState m
fn State muxMode initiatorCtx peerAddr versionData m a b
state =
    State muxMode initiatorCtx peerAddr versionData m a b
state {
      connections =
        Map.adjust
          (\connState :: ConnectionState muxMode initiatorCtx peerAddr versionData m a b
connState@ConnectionState { RemoteState m
csRemoteState :: forall (muxMode :: MuxMode) initiatorCtx peerAddr versionData
       (m :: * -> *) a b.
ConnectionState muxMode initiatorCtx peerAddr versionData m a b
-> RemoteState m
csRemoteState :: RemoteState m
csRemoteState } ->
            ConnectionState muxMode initiatorCtx peerAddr versionData m a b
connState { csRemoteState = fn csRemoteState })
          connId
          (connections state)
    }


-- | Remote connection state tracked by inbound protocol governor.
--
-- This type is used for tracing.
--
data RemoteSt = RemoteWarmSt
              | RemoteHotSt
              | RemoteIdleSt
              | RemoteColdSt
  deriving (RemoteSt -> RemoteSt -> Bool
(RemoteSt -> RemoteSt -> Bool)
-> (RemoteSt -> RemoteSt -> Bool) -> Eq RemoteSt
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RemoteSt -> RemoteSt -> Bool
== :: RemoteSt -> RemoteSt -> Bool
$c/= :: RemoteSt -> RemoteSt -> Bool
/= :: RemoteSt -> RemoteSt -> Bool
Eq, Int -> RemoteSt -> ShowS
[RemoteSt] -> ShowS
RemoteSt -> String
(Int -> RemoteSt -> ShowS)
-> (RemoteSt -> String) -> ([RemoteSt] -> ShowS) -> Show RemoteSt
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RemoteSt -> ShowS
showsPrec :: Int -> RemoteSt -> ShowS
$cshow :: RemoteSt -> String
show :: RemoteSt -> String
$cshowList :: [RemoteSt] -> ShowS
showList :: [RemoteSt] -> ShowS
Show)


mkRemoteSt :: RemoteState m -> RemoteSt
mkRemoteSt :: forall (m :: * -> *). RemoteState m -> RemoteSt
mkRemoteSt  RemoteState m
RemoteWarm    = RemoteSt
RemoteWarmSt
mkRemoteSt  RemoteState m
RemoteHot     = RemoteSt
RemoteHotSt
mkRemoteSt (RemoteIdle STM m ()
_) = RemoteSt
RemoteIdleSt
mkRemoteSt  RemoteState m
RemoteCold    = RemoteSt
RemoteColdSt