module Ecluse.Core.Server.Admission.Budget (
scaleCharge,
roundUpToStep,
MeterView (..),
EntryGate (..),
entryDecision,
entryReady,
GrowthGate (..),
growthDecision,
) where
import Data.IntSet qualified as IntSet
scaleCharge :: Int -> Int -> Int
scaleCharge :: Int -> Int -> Int
scaleCharge Int
permille Int
bytes
| Int
bytes Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 Bool -> Bool -> Bool
|| Int
permille Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = Int
0
| Bool
otherwise = (Int
bytes Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
permille Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
999) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
1000
roundUpToStep :: Int -> Int -> Int
roundUpToStep :: Int -> Int -> Int
roundUpToStep Int
step Int
shortfall
| Int
shortfall Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = Int
0
| Bool
otherwise = ((Int
shortfall Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
size) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
size
where
size :: Int
size = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 Int
step
data MeterView = MeterView
{ MeterView -> Int
mvBudget :: Int
, MeterView -> Int
mvCharged :: Int
, MeterView -> Maybe Int
mvToken :: Maybe Int
, MeterView -> Maybe Int
mvOldestWaiter :: Maybe Int
}
deriving stock (MeterView -> MeterView -> Bool
(MeterView -> MeterView -> Bool)
-> (MeterView -> MeterView -> Bool) -> Eq MeterView
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MeterView -> MeterView -> Bool
== :: MeterView -> MeterView -> Bool
$c/= :: MeterView -> MeterView -> Bool
/= :: MeterView -> MeterView -> Bool
Eq, Int -> MeterView -> ShowS
[MeterView] -> ShowS
MeterView -> String
(Int -> MeterView -> ShowS)
-> (MeterView -> String)
-> ([MeterView] -> ShowS)
-> Show MeterView
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MeterView -> ShowS
showsPrec :: Int -> MeterView -> ShowS
$cshow :: MeterView -> String
show :: MeterView -> String
$cshowList :: [MeterView] -> ShowS
showList :: [MeterView] -> ShowS
Show)
data EntryGate
=
EntryAdmit
|
EntryQueue
|
EntryRefuse
deriving stock (EntryGate -> EntryGate -> Bool
(EntryGate -> EntryGate -> Bool)
-> (EntryGate -> EntryGate -> Bool) -> Eq EntryGate
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EntryGate -> EntryGate -> Bool
== :: EntryGate -> EntryGate -> Bool
$c/= :: EntryGate -> EntryGate -> Bool
/= :: EntryGate -> EntryGate -> Bool
Eq, Int -> EntryGate -> ShowS
[EntryGate] -> ShowS
EntryGate -> String
(Int -> EntryGate -> ShowS)
-> (EntryGate -> String)
-> ([EntryGate] -> ShowS)
-> Show EntryGate
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EntryGate -> ShowS
showsPrec :: Int -> EntryGate -> ShowS
$cshow :: EntryGate -> String
show :: EntryGate -> String
$cshowList :: [EntryGate] -> ShowS
showList :: [EntryGate] -> ShowS
Show)
entryDecision :: MeterView -> Int -> Int -> Int -> EntryGate
entryDecision :: MeterView -> Int -> Int -> Int -> EntryGate
entryDecision MeterView
view Int
waiting Int
room Int
step
| Int
waiting Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& MeterView -> Int -> Bool
entryReady MeterView
view Int
step = EntryGate
EntryAdmit
| Int
waiting Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
room = EntryGate
EntryRefuse
| Bool
otherwise = EntryGate
EntryQueue
entryReady :: MeterView -> Int -> Bool
entryReady :: MeterView -> Int -> Bool
entryReady MeterView
view Int
step = MeterView -> Int -> Bool
fits MeterView
view Int
step Bool -> Bool -> Bool
&& Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing (MeterView -> Maybe Int
mvOldestWaiter MeterView
view)
data GrowthGate
=
GrowWithin
|
GrowOnToken
|
GrowTakeToken
|
GrowWait
deriving stock (GrowthGate -> GrowthGate -> Bool
(GrowthGate -> GrowthGate -> Bool)
-> (GrowthGate -> GrowthGate -> Bool) -> Eq GrowthGate
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: GrowthGate -> GrowthGate -> Bool
== :: GrowthGate -> GrowthGate -> Bool
$c/= :: GrowthGate -> GrowthGate -> Bool
/= :: GrowthGate -> GrowthGate -> Bool
Eq, Int -> GrowthGate -> ShowS
[GrowthGate] -> ShowS
GrowthGate -> String
(Int -> GrowthGate -> ShowS)
-> (GrowthGate -> String)
-> ([GrowthGate] -> ShowS)
-> Show GrowthGate
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GrowthGate -> ShowS
showsPrec :: Int -> GrowthGate -> ShowS
$cshow :: GrowthGate -> String
show :: GrowthGate -> String
$cshowList :: [GrowthGate] -> ShowS
showList :: [GrowthGate] -> ShowS
Show)
growthDecision :: MeterView -> IntSet -> Int -> GrowthGate
growthDecision :: MeterView -> IntSet -> Int -> GrowthGate
growthDecision MeterView
view IntSet
served Int
want
| MeterView -> Int -> Bool
fits MeterView
view Int
want = GrowthGate
GrowWithin
| (Int -> Bool) -> Maybe Int -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Int -> IntSet -> Bool
`IntSet.member` IntSet
served) (MeterView -> Maybe Int
mvToken MeterView
view) = GrowthGate
GrowOnToken
| Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing (MeterView -> Maybe Int
mvToken MeterView
view) Bool -> Bool -> Bool
&& Bool
oldestServed = GrowthGate
GrowTakeToken
| Bool
otherwise = GrowthGate
GrowWait
where
oldestServed :: Bool
oldestServed = case ((Int, IntSet) -> Int
forall a b. (a, b) -> a
fst ((Int, IntSet) -> Int) -> Maybe (Int, IntSet) -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IntSet -> Maybe (Int, IntSet)
IntSet.minView IntSet
served, MeterView -> Maybe Int
mvOldestWaiter MeterView
view) of
(Just Int
ticket, Just Int
oldest) -> Int
ticket Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
oldest
(Just Int
_, Maybe Int
Nothing) -> Bool
True
(Maybe Int
Nothing, Maybe Int
_) -> Bool
False
fits :: MeterView -> Int -> Bool
fits :: MeterView -> Int -> Bool
fits MeterView
view Int
bytes = MeterView -> Int
mvCharged MeterView
view Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
bytes Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= MeterView -> Int
mvBudget MeterView
view