{-# LANGUAGE RecordWildCards #-} module Hans.Ports ( -- * Port Management PortManager , emptyPortManager , isUsed , reserve , unreserve , nextPort ) where import Control.Monad (guard) import qualified Data.Set as Set -- Port Management ------------------------------------------------------------- data PortManager i = PortManager { portNext :: [i] , portReserved :: Set.Set i , portActive :: Set.Set i } instance Show i => Show (PortManager i) where show 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