-- | Conversions from 'Int8'.
module Unwitch.Convert.Int8
  ( -- * Conversions
    toInt16
  , toInt32
  , toInt64
  , toInt
  , toInteger
  , toWord8
  , toWord16
  , toWord32
  , toWord64
  , toWord
  , toNatural
  , toFloat
  , toDouble
#ifdef __GLASGOW_HASKELL__
  , toCInt
#endif
#ifdef __GLASGOW_HASKELL__
  -- * Unboxed conversions
  -- $unboxed
  , toWord8#
  , toWord16#
  , toWord32#
  , toWord64#
  , toWord#
  , toNatural#
#endif
  )
where

import           Unwitch.Errors
import qualified Data.Bits as Bits
import           Data.Word
import           Data.Int
import           Numeric.Natural (Natural)
import           Prelude hiding (toInteger)
#ifdef __GLASGOW_HASKELL__
import           Foreign.C.Types (CInt(CInt))
import           GHC.Exts (Word(..), int8ToInt#, int2Word#,
                           wordToWord8#, wordToWord16#, wordToWord32#,
                           wordToWord64#, (>=#))
import           GHC.Int (Int8(..))
import           GHC.Word (Word8(..), Word16(..), Word32(..), Word64(..))
import           GHC.Num.Natural (Natural(NS))
#endif

#ifdef __GLASGOW_HASKELL__
-- $unboxed
-- These use GHC unboxed types and unboxed sums for zero-allocation
-- failure handling. Requires the @MagicHash@, @UnboxedSums@ and
-- @UnboxedTuples@ language extensions.
-- See the <https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/primitives.html GHC manual on unboxed types>.
#endif

toInt16 :: Int8 -> Int16
toInt16 :: Int8 -> Int16
toInt16 = Int8 -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toInt32 :: Int8 -> Int32
toInt32 :: Int8 -> Int32
toInt32 = Int8 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toInt64 :: Int8 -> Int64
toInt64 :: Int8 -> Int64
toInt64 = Int8 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toInt :: Int8 -> Int
toInt :: Int8 -> Int
toInt = Int8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toInteger :: Int8 -> Integer
toInteger :: Int8 -> Integer
toInteger = Int8 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toWord8 :: Int8 -> Maybe Word8
toWord8 :: Int8 -> Maybe Word8
toWord8 = Int8 -> Maybe Word8
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
Bits.toIntegralSized

toWord16 :: Int8 -> Maybe Word16
toWord16 :: Int8 -> Maybe Word16
toWord16 = Int8 -> Maybe Word16
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
Bits.toIntegralSized

toWord32 :: Int8 -> Maybe Word32
toWord32 :: Int8 -> Maybe Word32
toWord32 = Int8 -> Maybe Word32
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
Bits.toIntegralSized

toWord64 :: Int8 -> Maybe Word64
toWord64 :: Int8 -> Maybe Word64
toWord64 = Int8 -> Maybe Word64
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
Bits.toIntegralSized

toWord :: Int8 -> Maybe Word
toWord :: Int8 -> Maybe Word
toWord = Int8 -> Maybe Word
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
Bits.toIntegralSized

-- | Signed-to-unsigned conversion, returns 'Left' 'Underflow' for negative values.
toNatural :: Int8 -> Either Overflows Natural
toNatural :: Int8 -> Either Overflows Natural
toNatural Int8
x = if
  | Int8
x Int8 -> Int8 -> Bool
forall a. Ord a => a -> a -> Bool
< Int8
0     -> Overflows -> Either Overflows Natural
forall a b. a -> Either a b
Left Overflows
Underflow
  | Bool
otherwise  -> Natural -> Either Overflows Natural
forall a b. b -> Either a b
Right (Natural -> Either Overflows Natural)
-> Natural -> Either Overflows Natural
forall a b. (a -> b) -> a -> b
$ Int8 -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int8
x

#ifdef __GLASGOW_HASKELL__
-- | Widening conversion via Int32, always succeeds.
toCInt :: Int8 -> CInt
toCInt :: Int8 -> CInt
toCInt Int8
x = Int32 -> CInt
CInt (Int32 -> CInt) -> Int32 -> CInt
forall a b. (a -> b) -> a -> b
$ Int8 -> Int32
toInt32 Int8
x
#endif

toFloat :: Int8 -> Float
toFloat :: Int8 -> Float
toFloat = Int8 -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toDouble :: Int8 -> Double
toDouble :: Int8 -> Double
toDouble = Int8 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral

#ifdef __GLASGOW_HASKELL__
-- | Signed->unsigned, check non-negative
toWord8# :: Int8 -> (# Word8 | (# #) #)
toWord8# :: Int8 -> (# Word8 | (# #) #)
toWord8# (I8# Int8#
x8#) = case Int8# -> Int#
int8ToInt# Int8#
x8# Int# -> Int# -> Int#
>=# Int#
0# of
  Int#
1# -> (# Word8# -> Word8
W8# (Word# -> Word8#
wordToWord8# (Int# -> Word#
int2Word# (Int8# -> Int#
int8ToInt# Int8#
x8#))) | #)
  Int#
_  -> (# | (# #) #)

-- | Signed->unsigned, check non-negative
toWord16# :: Int8 -> (# Word16 | (# #) #)
toWord16# :: Int8 -> (# Word16 | (# #) #)
toWord16# (I8# Int8#
x8#) = case Int8# -> Int#
int8ToInt# Int8#
x8# Int# -> Int# -> Int#
>=# Int#
0# of
  Int#
1# -> (# Word16# -> Word16
W16# (Word# -> Word16#
wordToWord16# (Int# -> Word#
int2Word# (Int8# -> Int#
int8ToInt# Int8#
x8#))) | #)
  Int#
_  -> (# | (# #) #)

-- | Signed->unsigned, check non-negative
toWord32# :: Int8 -> (# Word32 | (# #) #)
toWord32# :: Int8 -> (# Word32 | (# #) #)
toWord32# (I8# Int8#
x8#) = case Int8# -> Int#
int8ToInt# Int8#
x8# Int# -> Int# -> Int#
>=# Int#
0# of
  Int#
1# -> (# Word32# -> Word32
W32# (Word# -> Word32#
wordToWord32# (Int# -> Word#
int2Word# (Int8# -> Int#
int8ToInt# Int8#
x8#))) | #)
  Int#
_  -> (# | (# #) #)

-- | Signed->unsigned, check non-negative
toWord64# :: Int8 -> (# Word64 | (# #) #)
toWord64# :: Int8 -> (# Word64 | (# #) #)
toWord64# (I8# Int8#
x8#) = case Int8# -> Int#
int8ToInt# Int8#
x8# Int# -> Int# -> Int#
>=# Int#
0# of
  Int#
1# -> (# Word64# -> Word64
W64# (Word# -> Word64#
wordToWord64# (Int# -> Word#
int2Word# (Int8# -> Int#
int8ToInt# Int8#
x8#))) | #)
  Int#
_  -> (# | (# #) #)

-- | Signed->unsigned, check non-negative
toWord# :: Int8 -> (# Word | (# #) #)
toWord# :: Int8 -> (# Word | (# #) #)
toWord# (I8# Int8#
x8#) = case Int8# -> Int#
int8ToInt# Int8#
x8# Int# -> Int# -> Int#
>=# Int#
0# of
  Int#
1# -> (# Word# -> Word
W# (Int# -> Word#
int2Word# (Int8# -> Int#
int8ToInt# Int8#
x8#)) | #)
  Int#
_  -> (# | (# #) #)

-- | Check non-negative, construct NS directly
toNatural# :: Int8 -> (# Overflows | Natural #)
toNatural# :: Int8 -> (# Overflows | Natural #)
toNatural# (I8# Int8#
x8#) = case Int8# -> Int#
int8ToInt# Int8#
x8# Int# -> Int# -> Int#
>=# Int#
0# of
  Int#
1# -> (# | Word# -> Natural
NS (Int# -> Word#
int2Word# (Int8# -> Int#
int8ToInt# Int8#
x8#)) #)
  Int#
_  -> (# Overflows
Underflow | #)
#endif