packages feed

overeasy-0.1.0: src/Overeasy/Source.hs

{-# LANGUAGE DeriveAnyClass #-}

-- | See 'Source'.
module Overeasy.Source
  ( Source
  , sourceSize
  , sourceNew
  , sourceAddInc
  , sourceAdd
  , sourceSkipInc
  , sourceSkip
  , sourcePeek
  ) where

import Control.DeepSeq (NFData)
import Control.Monad.State.Strict (State, modify', state)
import Data.Coerce (Coercible, coerce)
import GHC.Generics (Generic)

-- | A source of unique ids
data Source x = Source
  { sourceSize :: !Int
  -- ^ How many ids have ever been created?
  , sourceNextId :: !Int
  } deriving stock (Eq, Show, Generic)
    deriving anyclass (NFData)

-- | Creates a new 'Source' from a starting id
sourceNew :: Coercible x Int => x -> Source x
sourceNew = Source 0 . coerce

-- | Generates the next id from the source (purely)
sourceAddInc :: Coercible x Int => Source x -> (x, Source x)
sourceAddInc (Source s x) = (coerce x, Source (s + 1) (x + 1))

-- | Generates the next id from the source (statefully)
sourceAdd :: Coercible x Int => State (Source x) x
sourceAdd = state sourceAddInc

-- | Skips past the given id (purely)
sourceSkipInc :: Coercible x Int => x -> Source x -> Source x
sourceSkipInc y (Source s x) =
  let z = coerce y
  in Source (s + 1) (max x (z + 1))

-- | Skips past the given id (statefully)
sourceSkip :: Coercible x Int => x -> State (Source x) ()
sourceSkip = modify' . sourceSkipInc

-- | Peek at the next id
sourcePeek :: Coercible x Int => Source x -> x
sourcePeek = coerce . sourceNextId