packages feed

hegel-0.1.0: src/Hegel/Generator/Range.hs

-- | Shared range option types and validation helpers.
module Hegel.Generator.Range
  ( RangeOpts (..)
  , defaultRangeOpts
  , validateSizeBounds
  ) where

import Data.Default (Default (def))
import Data.Maybe (fromMaybe)

-- | Configuration for lower and upper bounds used by range-limited generators.
--
-- Use 'def' for the default unbounded case, or update specific fields:
--
-- @
-- integers def { rangeMin = Just 0, rangeMax = Just 100 }
-- text def { rangeMin = Just 1, rangeMax = Just 10 }
-- @
--
-- Collection-like generators interpret these fields as @min_size@ and
-- @max_size@ bounds.
data RangeOpts a = RangeOpts
  { rangeMin :: !(Maybe a)
  -- ^ Inclusive lower bound when present.
  , rangeMax :: !(Maybe a)
  -- ^ Inclusive upper bound when present.
  } deriving (Eq, Show)

instance Default (RangeOpts a) where
  def = RangeOpts
    { rangeMin = Nothing
    , rangeMax = Nothing
    }

-- | Convenience alias for 'def'.
defaultRangeOpts :: RangeOpts a
defaultRangeOpts = def

-- | Validate non-negative size bounds and return the normalized min/max pair.
validateSizeBounds :: String -> RangeOpts Int -> (Int, Maybe Int)
validateSizeBounds label RangeOpts {rangeMin = minSize, rangeMax = maxSize} =
  (if minSize' < 0
     then error $ label ++ ": min_size=" ++ show minSize' ++ " must be non-negative"
     else ())
  `seq`
  (case maxSize of
     Just mx | mx < 0 ->
       error $ label ++ ": max_size=" ++ show mx ++ " must be non-negative"
     Just mx | minSize' > mx ->
       error $ label ++ ": max_size=" ++ show mx ++ " < min_size=" ++ show minSize'
     _ -> ())
  `seq`
  (minSize', maxSize)
  where
    minSize' = fromMaybe 0 minSize