module Hans.Ports (
PortManager
, emptyPortManager
, isUsed
, reserve
, unreserve
, nextPort
) where
import Control.Monad (guard)
import qualified Data.Set as Set
data PortManager i = PortManager
{ portNext :: [i]
, portReserved :: Set.Set i
, portActive :: Set.Set i
}
instance Show i => Show (PortManager i) where
show pm = "<Active ports: " ++ show (portActive pm) ++ ">"
emptyPortManager :: [i] -> PortManager i
emptyPortManager range = PortManager
{ portNext = range
, portReserved = Set.empty
, portActive = Set.empty
}
isUsed :: (Eq i, Ord i) => i -> PortManager i -> Bool
isUsed i PortManager { .. } = i `Set.member` portActive
|| i `Set.member` portReserved
reserve :: (Eq i, Ord i, Show i) => i -> PortManager i -> Maybe (PortManager i)
reserve i pm = do
guard (not (isUsed i pm))
return $! pm
{ portReserved = Set.insert i (portReserved pm)
}
unreserve :: (Eq i, Ord i, Show i) => i -> PortManager i -> Maybe (PortManager i)
unreserve i pm @ PortManager { .. }
| Set.member i portReserved = Just pm { portReserved = Set.delete i portReserved }
| Set.member i portActive = Just pm' { portActive = Set.delete i portActive }
| otherwise = Nothing
where
pm' = pm { portNext = i : portNext }
nextPort :: (Eq i, Ord i, Show i) => PortManager i -> Maybe (i, PortManager i)
nextPort pm = case span (`isUsed` pm) (portNext pm) of
(_,i:rest) -> return (i, pm { portNext = rest
, portActive = Set.insert i (portActive pm) })
_ -> Nothing