-- |
-- Module      : Relay.ReceiverHalf
-- Description : Receiver half of the sequencing protocol.
module Relay.ReceiverHalf
  ( ReceiverHalf (..),
    emptyReceiver,
    receive,
  )
where

import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Relay.Session (Nat)

-- | Local state for one session's in-order delivery.
data ReceiverHalf a = ReceiverHalf
  { forall a. ReceiverHalf a -> Nat
expected :: Nat,
    forall a. ReceiverHalf a -> Map Nat a
pending :: Map Nat a
  }
  deriving (Int -> ReceiverHalf a -> ShowS
[ReceiverHalf a] -> ShowS
ReceiverHalf a -> String
(Int -> ReceiverHalf a -> ShowS)
-> (ReceiverHalf a -> String)
-> ([ReceiverHalf a] -> ShowS)
-> Show (ReceiverHalf a)
forall a. Show a => Int -> ReceiverHalf a -> ShowS
forall a. Show a => [ReceiverHalf a] -> ShowS
forall a. Show a => ReceiverHalf a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> ReceiverHalf a -> ShowS
showsPrec :: Int -> ReceiverHalf a -> ShowS
$cshow :: forall a. Show a => ReceiverHalf a -> String
show :: ReceiverHalf a -> String
$cshowList :: forall a. Show a => [ReceiverHalf a] -> ShowS
showList :: [ReceiverHalf a] -> ShowS
Show, ReceiverHalf a -> ReceiverHalf a -> Bool
(ReceiverHalf a -> ReceiverHalf a -> Bool)
-> (ReceiverHalf a -> ReceiverHalf a -> Bool)
-> Eq (ReceiverHalf a)
forall a. Eq a => ReceiverHalf a -> ReceiverHalf a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => ReceiverHalf a -> ReceiverHalf a -> Bool
== :: ReceiverHalf a -> ReceiverHalf a -> Bool
$c/= :: forall a. Eq a => ReceiverHalf a -> ReceiverHalf a -> Bool
/= :: ReceiverHalf a -> ReceiverHalf a -> Bool
Eq)

-- | Initial receiver state. The first expected sequence number is 1.
emptyReceiver :: ReceiverHalf a
emptyReceiver :: forall a. ReceiverHalf a
emptyReceiver = ReceiverHalf {expected :: Nat
expected = Nat
1, pending :: Map Nat a
pending = Map Nat a
forall k a. Map k a
Map.empty}

-- | Process one arriving frame and return the updated state and any
-- newly deliverable payloads.
--
-- * Duplicate (@n < expected@): dropped silently, no state change.
-- * Out-of-order (@n > expected@): buffered in @pending@, no output.
-- * In-order (@n == expected@): delivered, then consecutive entries
--   flushed from @pending@.
receive :: Nat -> a -> ReceiverHalf a -> (ReceiverHalf a, [a])
receive :: forall a. Nat -> a -> ReceiverHalf a -> (ReceiverHalf a, [a])
receive Nat
n a
v ReceiverHalf a
rh
  | Nat
n Nat -> Nat -> Bool
forall a. Ord a => a -> a -> Bool
< ReceiverHalf a -> Nat
forall a. ReceiverHalf a -> Nat
expected ReceiverHalf a
rh = (ReceiverHalf a
rh, [])
  | Nat
n Nat -> Nat -> Bool
forall a. Ord a => a -> a -> Bool
> ReceiverHalf a -> Nat
forall a. ReceiverHalf a -> Nat
expected ReceiverHalf a
rh = (ReceiverHalf a
rh {pending = Map.insert n v (pending rh)}, [])
  | Bool
otherwise = ReceiverHalf a -> [a] -> (ReceiverHalf a, [a])
forall {a}. ReceiverHalf a -> [a] -> (ReceiverHalf a, [a])
flush ReceiverHalf a
rh {expected = expected rh + 1} [a
v]
  where
    flush :: ReceiverHalf a -> [a] -> (ReceiverHalf a, [a])
flush ReceiverHalf a
rh' [a]
acc =
      case Map Nat a -> Maybe ((Nat, a), Map Nat a)
forall k a. Map k a -> Maybe ((k, a), Map k a)
Map.minViewWithKey (ReceiverHalf a -> Map Nat a
forall a. ReceiverHalf a -> Map Nat a
pending ReceiverHalf a
rh') of
        Just ((Nat
k, a
a), Map Nat a
rest)
          | Nat
k Nat -> Nat -> Bool
forall a. Eq a => a -> a -> Bool
== ReceiverHalf a -> Nat
forall a. ReceiverHalf a -> Nat
expected ReceiverHalf a
rh' ->
              ReceiverHalf a -> [a] -> (ReceiverHalf a, [a])
flush ReceiverHalf a
rh' {expected = k + 1, pending = rest} ([a]
acc [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
a])
        Maybe ((Nat, a), Map Nat a)
_ -> (ReceiverHalf a
rh', [a]
acc)