    {-# LANGUAGE Trustworthy #-}
    {-# LANGUAGE NoImplicitPrelude #-}
    {-# LANGUAGE MagicHash #-}
    {-# LANGUAGE PatternSynonyms #-}
    {-# LANGUAGE ViewPatterns #-}
    {-# LANGUAGE UnboxedSums #-}

    {-# OPTIONS_HADDOCK not-home #-}

    -- | Compatibility module for pre ghc-bignum code.
    module GHC.Natural
       ( Natural (NatS#, NatJ#)
       , B.BigNat (..)
       , mkNatural
       , isValidNatural
         -- * Arithmetic
       , plusNatural
       , minusNatural
       , minusNaturalMaybe
       , timesNatural
       , negateNatural
       , signumNatural
       , quotRemNatural
       , quotNatural
       , remNatural
       , gcdNatural
       , lcmNatural
         -- * Bits
       , andNatural
       , orNatural
       , xorNatural
       , bitNatural
       , testBitNatural
       , popCountNatural
       , shiftLNatural
       , shiftRNatural
         -- * Conversions
       , naturalToInteger
       , naturalToWord
       , naturalToWordMaybe
       , wordToNatural
       , wordToNatural#
       , naturalFromInteger
         -- * Modular arithmetic
       , powModNatural
       )
    where

    import GHC.Prim
    import GHC.Types
    import GHC.Maybe
    import GHC.Num.Natural (Natural)
    import GHC.Num.Integer (Integer)
    import qualified GHC.Num.BigNat  as B
    import qualified GHC.Num.Natural as N
    import qualified GHC.Num.Integer as I

    {-# COMPLETE NatS#, NatJ# #-}

    pattern NatS# :: Word# -> Natural
    pattern $mNatS# :: forall {r}. Natural -> (Word# -> r) -> ((# #) -> r) -> r
    $bNatS# :: Word# -> Natural
    NatS# w = N.NS w

    pattern NatJ# :: B.BigNat -> Natural
    pattern $mNatJ# :: forall {r}. Natural -> (BigNat -> r) -> ((# #) -> r) -> r
    $bNatJ# :: BigNat -> Natural
    NatJ# b <- N.NB (B.BN# -> b)
       where
          NatJ# BigNat
    b = ByteArray# -> Natural
    N.NB (BigNat -> ByteArray#
    B.unBigNat BigNat
    b)

    int2Word :: Int -> Word
    int2Word :: Int -> Word
    int2Word (I# Int#
    i) = Word# -> Word
    W# (Int# -> Word#
    int2Word# Int#
    i)

    word2Int :: Word -> Int
    word2Int :: Word -> Int
    word2Int (W# Word#
    w) = Int# -> Int
    I# (Word# -> Int#
    word2Int# Word#
    w)

    -- | Construct 'Natural' value from list of 'Word's.
    mkNatural :: [Word] -> Natural
    mkNatural :: [Word] -> Natural
    mkNatural = [Word] -> Natural
    N.naturalFromWordList

    -- | Test whether all internal invariants are satisfied by 'Natural' value
    --
    -- This operation is mostly useful for test-suites and/or code which
    -- constructs 'Integer' values directly.
    --
    -- @since 4.8.0.0
    isValidNatural :: Natural -> Bool
    isValidNatural :: Natural -> Bool
    isValidNatural = Natural -> Bool
    N.naturalCheck

    -- | 'Natural' Addition
    plusNatural :: Natural -> Natural -> Natural
    plusNatural :: Natural -> Natural -> Natural
    plusNatural = Natural -> Natural -> Natural
    N.naturalAdd

    -- | 'Natural' subtraction. May @'Control.Exception.throw'
    -- 'Control.Exception.Underflow'@.
    minusNatural :: Natural -> Natural -> Natural
    minusNatural :: Natural -> Natural -> Natural
    minusNatural = Natural -> Natural -> Natural
    N.naturalSubThrow

    -- | 'Natural' subtraction. Returns 'Nothing's for non-positive results.
    --
    -- @since 4.8.0.0
    minusNaturalMaybe :: Natural -> Natural -> Maybe Natural
    minusNaturalMaybe :: Natural -> Natural -> Maybe Natural
    minusNaturalMaybe Natural
    x Natural
    y = case Natural -> Natural -> (# (# #) | Natural #)
    N.naturalSub Natural
    x Natural
    y of
       (# (# #) |   #) -> forall a. Maybe a
    Nothing
       (#       | Natural
    n #) -> forall a. a -> Maybe a
    Just Natural
    n

    -- | 'Natural' multiplication
    timesNatural :: Natural -> Natural -> Natural
    timesNatural :: Natural -> Natural -> Natural
    timesNatural = Natural -> Natural -> Natural
    N.naturalMul

    negateNatural :: Natural -> Natural
    negateNatural :: Natural -> Natural
    negateNatural = Natural -> Natural
    N.naturalNegate

    signumNatural :: Natural -> Natural
    signumNatural :: Natural -> Natural
    signumNatural = Natural -> Natural
    N.naturalSignum

    quotRemNatural :: Natural -> Natural -> (Natural, Natural)
    quotRemNatural :: Natural -> Natural -> (Natural, Natural)
    quotRemNatural = Natural -> Natural -> (Natural, Natural)
    N.naturalQuotRem

    remNatural :: Natural -> Natural -> Natural
    remNatural :: Natural -> Natural -> Natural
    remNatural = Natural -> Natural -> Natural
    N.naturalRem

    quotNatural :: Natural -> Natural -> Natural
    quotNatural :: Natural -> Natural -> Natural
    quotNatural = Natural -> Natural -> Natural
    N.naturalQuot

    -- | Compute greatest common divisor.
    gcdNatural :: Natural -> Natural -> Natural
    gcdNatural :: Natural -> Natural -> Natural
    gcdNatural = Natural -> Natural -> Natural
    N.naturalGcd

    -- | Compute least common multiple.
    lcmNatural :: Natural -> Natural -> Natural
    lcmNatural :: Natural -> Natural -> Natural
    lcmNatural = Natural -> Natural -> Natural
    N.naturalLcm

    andNatural :: Natural -> Natural -> Natural
    andNatural :: Natural -> Natural -> Natural
    andNatural = Natural -> Natural -> Natural
    N.naturalAnd

    orNatural :: Natural -> Natural -> Natural
    orNatural :: Natural -> Natural -> Natural
    orNatural = Natural -> Natural -> Natural
    N.naturalOr

    xorNatural :: Natural -> Natural -> Natural
    xorNatural :: Natural -> Natural -> Natural
    xorNatural = Natural -> Natural -> Natural
    N.naturalXor

    bitNatural :: Int# -> Natural
    bitNatural :: Int# -> Natural
    bitNatural Int#
    i = Word# -> Natural
    N.naturalBit# (Int# -> Word#
    int2Word# Int#
    i)

    testBitNatural :: Natural -> Int -> Bool
    testBitNatural :: Natural -> Int -> Bool
    testBitNatural Natural
    n Int
    i = Natural -> Word -> Bool
    N.naturalTestBit Natural
    n (Int -> Word
    int2Word Int
    i)

    popCountNatural :: Natural -> Int
    popCountNatural :: Natural -> Int
    popCountNatural Natural
    n = Word -> Int
    word2Int (Natural -> Word
    N.naturalPopCount Natural
    n)

    shiftLNatural :: Natural -> Int -> Natural
    shiftLNatural :: Natural -> Int -> Natural
    shiftLNatural Natural
    n Int
    i = Natural -> Word -> Natural
    N.naturalShiftL Natural
    n (Int -> Word
    int2Word  Int
    i)

    shiftRNatural :: Natural -> Int -> Natural
    shiftRNatural :: Natural -> Int -> Natural
    shiftRNatural Natural
    n Int
    i = Natural -> Word -> Natural
    N.naturalShiftR Natural
    n (Int -> Word
    int2Word Int
    i)

    -- | @since 4.12.0.0
    naturalToInteger :: Natural -> Integer
    naturalToInteger :: Natural -> Integer
    naturalToInteger = Natural -> Integer
    I.integerFromNatural

    naturalToWord :: Natural -> Word
    naturalToWord :: Natural -> Word
    naturalToWord = Natural -> Word
    N.naturalToWord

    -- | @since 4.10.0.0
    naturalFromInteger :: Integer -> Natural
    naturalFromInteger :: Integer -> Natural
    naturalFromInteger = Integer -> Natural
    I.integerToNatural

    -- | Construct 'Natural' from 'Word' value.
    --
    -- @since 4.8.0.0
    wordToNatural :: Word -> Natural
    wordToNatural :: Word -> Natural
    wordToNatural = Word -> Natural
    N.naturalFromWord

    -- | Try downcasting 'Natural' to 'Word' value.
    -- Returns 'Nothing' if value doesn't fit in 'Word'.
    --
    -- @since 4.8.0.0
    naturalToWordMaybe :: Natural -> Maybe Word
    naturalToWordMaybe :: Natural -> Maybe Word
    naturalToWordMaybe Natural
    n = case Natural -> (# (# #) | Word# #)
    N.naturalToWordMaybe# Natural
    n of
       (#       | Word#
    w #) -> forall a. a -> Maybe a
    Just (Word# -> Word
    W# Word#
    w)
       (# (# #) |   #) -> forall a. Maybe a
    Nothing

    wordToNatural# :: Word -> Natural
    wordToNatural# :: Word -> Natural
    wordToNatural# = Word -> Natural
    N.naturalFromWord

    -- | \"@'powModNatural' /b/ /e/ /m/@\" computes base @/b/@ raised to
    -- exponent @/e/@ modulo @/m/@.
    --
    -- @since 4.8.0.0
    powModNatural :: Natural -> Natural -> Natural -> Natural
    powModNatural :: Natural -> Natural -> Natural -> Natural
    powModNatural = Natural -> Natural -> Natural -> Natural
    N.naturalPowMod