{-# 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
  { forall x. Source x -> Int
sourceSize :: !Int
  -- ^ How many ids have ever been created?
  , forall x. Source x -> Int
sourceNextId :: !Int
  } deriving stock (Source x -> Source x -> Bool
forall x. Source x -> Source x -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Source x -> Source x -> Bool
$c/= :: forall x. Source x -> Source x -> Bool
== :: Source x -> Source x -> Bool
$c== :: forall x. Source x -> Source x -> Bool
Eq, Int -> Source x -> ShowS
forall x. Int -> Source x -> ShowS
forall x. [Source x] -> ShowS
forall x. Source x -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Source x] -> ShowS
$cshowList :: forall x. [Source x] -> ShowS
show :: Source x -> String
$cshow :: forall x. Source x -> String
showsPrec :: Int -> Source x -> ShowS
$cshowsPrec :: forall x. Int -> Source x -> ShowS
Show, forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall x x. Rep (Source x) x -> Source x
forall x x. Source x -> Rep (Source x) x
$cto :: forall x x. Rep (Source x) x -> Source x
$cfrom :: forall x x. Source x -> Rep (Source x) x
Generic)
    deriving anyclass (forall x. Source x -> ()
forall a. (a -> ()) -> NFData a
rnf :: Source x -> ()
$crnf :: forall x. Source x -> ()
NFData)

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

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

-- | Generates the next id from the source (statefully)
sourceAdd :: Coercible x Int => State (Source x) x
sourceAdd :: forall x. Coercible x Int => State (Source x) x
sourceAdd = forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
state forall x. Coercible x Int => Source x -> (x, Source x)
sourceAddInc

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

-- | Skips past the given id (statefully)
sourceSkip :: Coercible x Int => x -> State (Source x) ()
sourceSkip :: forall x. Coercible x Int => x -> State (Source x) ()
sourceSkip = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall x. Coercible x Int => x -> Source x -> Source x
sourceSkipInc

-- | Peek at the next id
sourcePeek :: Coercible x Int => Source x -> x
sourcePeek :: forall x. Coercible x Int => Source x -> x
sourcePeek = coerce :: forall a b. Coercible a b => a -> b
coerce forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall x. Source x -> Int
sourceNextId