packages feed

moonlight-planar-1.2.0.0: src-dcel/Moonlight/Planar/Internal/CurveBudget.hs

-- | The finite budget of an exact subdivision, admitted once, and the
-- obligation a subdivision reports when it spends it. Arc measurement,
-- proximity and topology certification share the one budget and its
-- refusals; what each does beyond subdivision stays with its own owner.
module Moonlight.Planar.Internal.CurveBudget
  ( SubdivisionBudget
  , SubdivisionBudgetError (..)
  , subdivisionBudget
  , budgetDepth
  , budgetLeaves
  , budgetBits
  , BudgetObligation (..)
  ) where

import Control.DeepSeq (NFData (..))

-- | Subdivision depth below any source step, the number of leaves in all,
-- and the largest admitted bit width of any retained exact value.
data SubdivisionBudget = SubdivisionBudget !Int !Int !Int
  deriving stock (Eq, Show)

instance NFData SubdivisionBudget where
  rnf (SubdivisionBudget depth leaves bits) = rnf depth `seq` rnf leaves `seq` rnf bits

data SubdivisionBudgetError
  = InvalidBudgetDepth !Int
  | InvalidBudgetLeaves !Int
  | InvalidBudgetBits !Int
  deriving stock (Eq, Show)

subdivisionBudget :: Int -> Int -> Int -> Either SubdivisionBudgetError SubdivisionBudget
subdivisionBudget depth leaves bits
  | depth < 0 = Left (InvalidBudgetDepth depth)
  | leaves <= 0 = Left (InvalidBudgetLeaves leaves)
  | bits <= 0 = Left (InvalidBudgetBits bits)
  | otherwise = Right (SubdivisionBudget depth leaves bits)

budgetDepth :: SubdivisionBudget -> Int
budgetDepth (SubdivisionBudget depth _ _) = depth

budgetLeaves :: SubdivisionBudget -> Int
budgetLeaves (SubdivisionBudget _ leaves _) = leaves

budgetBits :: SubdivisionBudget -> Int
budgetBits (SubdivisionBudget _ _ bits) = bits

-- | The budget a subdivision could not stay within. A bit refusal carries the
-- offending width; it is raised before the value is compared or retained.
data BudgetObligation
  = LeavesExhausted
  | DepthExhausted
  | BitsExhausted !Int
  deriving stock (Eq, Show)

instance NFData BudgetObligation where
  rnf obligation = obligation `seq` ()