module TimerWheel.Internal.Entries ( Entries, empty, TimerWheel.Internal.Entries.null, size, insert, delete, partition, ) where import Data.Coerce import Data.IntPSQ (IntPSQ) import qualified Data.IntPSQ as IntPSQ import Data.Word (Word64) newtype Entries = Entries (IntPSQ Word64 (IO ())) -- | An empty collection. empty :: Entries empty = Entries IntPSQ.empty {-# INLINEABLE empty #-} null :: Entries -> Bool null = coerce (IntPSQ.null @Word64 @(IO ())) {-# INLINEABLE null #-} -- | The number of timers in the collection. size :: Entries -> Int size = coerce (IntPSQ.size @Word64 @(IO ())) {-# INLINEABLE size #-} -- | @insert i n m x@ inserts callback @m@ into collection @x@ with unique -- identifier @i@ and "count" @n@. The insert :: Int -> Word64 -> IO () -> Entries -> Entries insert i n m = coerce (IntPSQ.unsafeInsertNew i n m) {-# INLINEABLE insert #-} -- | Delete a timer by id. Returns 'Nothing' if the timer was not found. delete :: Int -> Entries -> Maybe Entries delete = coerce delete_ {-# INLINEABLE delete #-} delete_ :: Int -> IntPSQ Word64 (IO ()) -> Maybe (IntPSQ Word64 (IO ())) delete_ i xs = (\(_, _, ys) -> ys) <$> IntPSQ.deleteView i xs -- | Extract expired timers. partition :: Entries -> ([IO ()], Entries) partition (Entries entries) = case IntPSQ.atMostView 0 entries of (expired, alive) -> (map f expired, Entries (IntPSQ.unsafeMapMonotonic g alive)) where f :: (Int, Word64, IO ()) -> IO () f (_, _, m) = m g :: Int -> Word64 -> IO () -> (Word64, IO ()) g _ n m = (n -1, m) {-# INLINEABLE partition #-}