hscuid-1.2.0.1: lib/Web/Cuid.hs
{-# LANGUAGE CPP #-}
{-|
Stability: stable
Portability: portable
You can generate a new CUID or slug inside any IO-enabled monad using 'newCuid'
and 'newSlug'.
-}
module Web.Cuid (
Cuid, newCuid,
Slug, newSlug
) where
import Control.Monad (liftM)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.String (fromString)
import Data.Text (Text)
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid (Monoid, mconcat)
#endif
import Web.Cuid.Internal
-- | Convenience type so that you don't have to import Text downstream. Note that
-- this is strict Text.
type Cuid = Text
-- | Generate a new random CUID.
newCuid :: MonadIO m => m Cuid
newCuid = concatResults [c, time, count, fingerprint, random, random] where
-- The CUID starts with a letter so it's usable in HTML element IDs.
c = return (fromString "c")
-- The second chunk is the timestamp. Note that this means it is possible
-- to determine the time a particular CUID was created.
time = liftM formatNumber getTimestamp
-- To avoid collisions in the same process, add a global counter to each ID.
count = liftM formatPadded getNextCount
-- To avoid collisions between separate machines, generate a 'fingerprint'
-- from details which are hopefully unique to this machine - PID and hostname.
fingerprint = return myFingerprint
-- And some actual randomness for good measure.
random = liftM formatPadded getRandomValue
-- | A Slug is not a Cuid. But it is also a strict Text.
type Slug = Text
-- | A slug is a shorter piece of text generated using some of the same
-- techniques as CUIDs.
newSlug :: MonadIO m => m Slug
newSlug = concatResults [time, count, fingerprint, random] where
time = liftM formatShort getTimestamp
count = liftM formatPadded getNextCount
random = liftM formatShort getRandomValue
fingerprint = return myFingerprint
-- Evaluate IO actions and concatenate their results.
concatResults :: (MonadIO m, Monoid a) => [IO a] -> m a
concatResults actions = liftM mconcat (liftIO $ sequence actions)