{-# Language CPP #-}
module Basement.Numerical.Number
    ( IsIntegral(..)
    , IsNatural(..)
    ) where

import           Basement.Compat.Base
import           Basement.Compat.C.Types
import           Basement.Compat.Natural
import           Data.Bits
import qualified Prelude

-- | Number literals, convertible through the generic Integer type.
--
-- all number are Enum'erable, meaning that you can move to
-- next element
class (Enum a, Eq a, Ord a, Integral a) => IsIntegral a where
    {-# MINIMAL toInteger #-}
    toInteger :: a -> Integer

-- | Non Negative Number literals, convertible through the generic Natural type
class (Enum a, Eq a, Ord a, Integral a, IsIntegral a) => IsNatural a where
    {-# MINIMAL toNatural #-}
    toNatural :: a -> Natural

instance IsIntegral Integer where
    toInteger i = i
instance IsIntegral Int where
    toInteger i = Prelude.toInteger i
instance IsIntegral Int8 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Int16 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Int32 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Int64 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Natural where
    toInteger i = Prelude.toInteger i
instance IsIntegral Word where
    toInteger i = Prelude.toInteger i
instance IsIntegral Word8 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Word16 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Word32 where
    toInteger i = Prelude.toInteger i
instance IsIntegral Word64 where
    toInteger i = Prelude.toInteger i

instance IsIntegral CChar where
    toInteger i = Prelude.toInteger i
instance IsIntegral CSChar where
    toInteger i = Prelude.toInteger i
instance IsIntegral CUChar where
    toInteger i = Prelude.toInteger i
instance IsIntegral CShort where
    toInteger i = Prelude.toInteger i
instance IsIntegral CUShort where
    toInteger i = Prelude.toInteger i
instance IsIntegral CInt where
    toInteger i = Prelude.toInteger i
instance IsIntegral CUInt where
    toInteger i = Prelude.toInteger i
instance IsIntegral CLong where
    toInteger i = Prelude.toInteger i
instance IsIntegral CULong where
    toInteger i = Prelude.toInteger i
instance IsIntegral CPtrdiff where
    toInteger i = Prelude.toInteger i
instance IsIntegral CSize where
    toInteger i = Prelude.toInteger i
instance IsIntegral CWchar where
    toInteger i = Prelude.toInteger i
instance IsIntegral CSigAtomic where
    toInteger i = Prelude.toInteger i
instance IsIntegral CLLong where
    toInteger i = Prelude.toInteger i
instance IsIntegral CULLong where
    toInteger i = Prelude.toInteger i
#if MIN_VERSION_base(4,10,0)
instance IsIntegral CBool where
    toInteger i = Prelude.toInteger i
#endif
instance IsIntegral CIntPtr where
    toInteger i = Prelude.toInteger i
instance IsIntegral CUIntPtr where
    toInteger i = Prelude.toInteger i
instance IsIntegral CIntMax where
    toInteger i = Prelude.toInteger i
instance IsIntegral CUIntMax where
    toInteger i = Prelude.toInteger i

instance IsNatural Natural where
    toNatural i = i
instance IsNatural Word where
    toNatural i = Prelude.fromIntegral i
instance IsNatural Word8 where
    toNatural i = Prelude.fromIntegral i
instance IsNatural Word16 where
    toNatural i = Prelude.fromIntegral i
instance IsNatural Word32 where
    toNatural i = Prelude.fromIntegral i
instance IsNatural Word64 where
    toNatural i = Prelude.fromIntegral i

instance IsNatural CUChar where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CUShort where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CUInt where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CULong where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CSize where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CULLong where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CUIntPtr where
    toNatural i = Prelude.fromIntegral i
instance IsNatural CUIntMax where
    toNatural i = Prelude.fromIntegral i