    {-|
    Copyright  :  (C) 2013-2016, University of Twente
                      2024,      Google LLC
    License    :  BSD2 (see the file LICENSE)
    Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
    -}

    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
    {-# LANGUAGE TypeFamilies #-}

    {-# LANGUAGE Safe #-}

    {-# OPTIONS_HADDOCK show-extensions #-}

    module Clash.Class.Num
      ( -- * Arithmetic functions for arguments and results of different precision
        ExtendingNum (..)
        -- * Saturating arithmetic functions
      , SaturationMode (..)
      , SaturatingNum (..)
      , boundedAdd
      , boundedSub
      , boundedMul
      )
    where

    -- * Arithmetic functions for arguments and results of different precision

    -- | Adding, subtracting, and multiplying values of two different (sub-)types.
    class ExtendingNum a b where
      -- | Type of the result of the addition or subtraction
      type AResult a b
      -- | Add values of different (sub-)types, return a value of a (sub-)type
      -- that is potentially different from either argument.
      add  :: a -> b -> AResult a b
      -- | Subtract values of different (sub-)types, return a value of a (sub-)type
      -- that is potentially different from either argument.
      sub :: a -> b -> AResult a b
      -- | Type of the result of the multiplication
      type MResult a b
      -- | Multiply values of different (sub-)types, return a value of a (sub-)type
      -- that is potentially different from either argument.
      mul :: a -> b -> MResult a b

    infixl 7  `mul`
    infixl 6  `add`, `sub`

    -- * Saturating arithmetic functions

    -- | Determine how overflow and underflow are handled by the functions in
    -- 'SaturatingNum'
    data SaturationMode
      = SatWrap  -- ^ Wrap around on overflow and underflow
      | SatBound -- ^ Become 'maxBound' on overflow, and 'minBound' on underflow
      | SatZero  -- ^ Become @0@ on overflow and underflow
      | SatSymmetric -- ^ Become 'maxBound' on overflow, and (@'minBound' + 1@) on
                     -- underflow for signed numbers, and 'minBound' for unsigned
                     -- numbers.
      | SatError -- ^ Become an XException on overflow and underflow
      deriving (Int -> SaturationMode -> ShowS
    [SaturationMode] -> ShowS
    SaturationMode -> String
    (Int -> SaturationMode -> ShowS)
    -> (SaturationMode -> String)
    -> ([SaturationMode] -> ShowS)
    -> Show SaturationMode
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SaturationMode -> ShowS
    showsPrec :: Int -> SaturationMode -> ShowS
    $cshow :: SaturationMode -> String
    show :: SaturationMode -> String
    $cshowList :: [SaturationMode] -> ShowS
    showList :: [SaturationMode] -> ShowS
    Show, SaturationMode -> SaturationMode -> Bool
    (SaturationMode -> SaturationMode -> Bool)
    -> (SaturationMode -> SaturationMode -> Bool) -> Eq SaturationMode
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: SaturationMode -> SaturationMode -> Bool
    == :: SaturationMode -> SaturationMode -> Bool
    $c/= :: SaturationMode -> SaturationMode -> Bool
    /= :: SaturationMode -> SaturationMode -> Bool
    Eq, Int -> SaturationMode
    SaturationMode -> Int
    SaturationMode -> [SaturationMode]
    SaturationMode -> SaturationMode
    SaturationMode -> SaturationMode -> [SaturationMode]
    SaturationMode
    -> SaturationMode -> SaturationMode -> [SaturationMode]
    (SaturationMode -> SaturationMode)
    -> (SaturationMode -> SaturationMode)
    -> (Int -> SaturationMode)
    -> (SaturationMode -> Int)
    -> (SaturationMode -> [SaturationMode])
    -> (SaturationMode -> SaturationMode -> [SaturationMode])
    -> (SaturationMode -> SaturationMode -> [SaturationMode])
    -> (SaturationMode
        -> SaturationMode -> SaturationMode -> [SaturationMode])
    -> Enum SaturationMode
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: SaturationMode -> SaturationMode
    succ :: SaturationMode -> SaturationMode
    $cpred :: SaturationMode -> SaturationMode
    pred :: SaturationMode -> SaturationMode
    $ctoEnum :: Int -> SaturationMode
    toEnum :: Int -> SaturationMode
    $cfromEnum :: SaturationMode -> Int
    fromEnum :: SaturationMode -> Int
    $cenumFrom :: SaturationMode -> [SaturationMode]
    enumFrom :: SaturationMode -> [SaturationMode]
    $cenumFromThen :: SaturationMode -> SaturationMode -> [SaturationMode]
    enumFromThen :: SaturationMode -> SaturationMode -> [SaturationMode]
    $cenumFromTo :: SaturationMode -> SaturationMode -> [SaturationMode]
    enumFromTo :: SaturationMode -> SaturationMode -> [SaturationMode]
    $cenumFromThenTo :: SaturationMode
    -> SaturationMode -> SaturationMode -> [SaturationMode]
    enumFromThenTo :: SaturationMode
    -> SaturationMode -> SaturationMode -> [SaturationMode]
    Enum, SaturationMode
    SaturationMode -> SaturationMode -> Bounded SaturationMode
    forall a. a -> a -> Bounded a
    $cminBound :: SaturationMode
    minBound :: SaturationMode
    $cmaxBound :: SaturationMode
    maxBound :: SaturationMode
    Bounded)

    -- | 'Num' operators in which overflow and underflow behavior can be specified
    -- using 'SaturationMode'.
    class (Bounded a, Num a) => SaturatingNum a where
      -- | Addition with parameterizable over- and underflow behavior
      satAdd :: SaturationMode -> a -> a -> a
      -- | Subtraction with parameterizable over- and underflow behavior
      satSub  :: SaturationMode -> a -> a -> a
      -- | Multiplication with parameterizable over- and underflow behavior
      satMul :: SaturationMode -> a -> a -> a
      -- | Get successor of (or in other words, add 1 to) given number
      satSucc :: SaturationMode -> a -> a
      -- Default method suitable for types that can represent the number 1
      satSucc SaturationMode
    s a
    n = SaturationMode -> a -> a -> a
    forall a. SaturatingNum a => SaturationMode -> a -> a -> a
    satAdd SaturationMode
    s a
    n a
    1
      {-# INLINE satSucc #-}
      -- | Get predecessor of (or in other words, subtract 1 from) given number
      satPred :: SaturationMode -> a -> a
      -- Default method suitable for types that can represent the number 1
      satPred SaturationMode
    s a
    n = SaturationMode -> a -> a -> a
    forall a. SaturatingNum a => SaturationMode -> a -> a -> a
    satSub SaturationMode
    s a
    n a
    1
      {-# INLINE satPred #-}

    infixl 7  `satMul`
    infixl 6  `satAdd`, `satSub`

    -- | Addition that clips to 'maxBound' on overflow, and 'minBound' on underflow
    boundedAdd :: SaturatingNum a => a -> a -> a
    boundedAdd :: forall a. SaturatingNum a => a -> a -> a
    boundedAdd = SaturationMode -> a -> a -> a
    forall a. SaturatingNum a => SaturationMode -> a -> a -> a
    satAdd SaturationMode
    SatBound
    {-# INLINE boundedAdd #-}
    infixl 6  `boundedAdd`

    -- | Subtraction that clips to 'maxBound' on overflow, and 'minBound' on
    -- underflow
    boundedSub  :: SaturatingNum a => a -> a -> a
    boundedSub :: forall a. SaturatingNum a => a -> a -> a
    boundedSub = SaturationMode -> a -> a -> a
    forall a. SaturatingNum a => SaturationMode -> a -> a -> a
    satSub SaturationMode
    SatBound
    {-# INLINE boundedSub #-}
    infixl 6 `boundedSub`

    -- | Multiplication that clips to 'maxBound' on overflow, and 'minBound' on
    -- underflow
    boundedMul :: SaturatingNum a => a -> a -> a
    boundedMul :: forall a. SaturatingNum a => a -> a -> a
    boundedMul = SaturationMode -> a -> a -> a
    forall a. SaturatingNum a => SaturationMode -> a -> a -> a
    satMul SaturationMode
    SatBound
    {-# INLINE boundedMul #-}
    infixl 7  `boundedMul`