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

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 (word8ToWord#, word2Int#, intToInt8#, int8ToInt#,
                           (==#))
import           GHC.Int (Int8(..))
import           GHC.Word (Word8(..))
#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

toWord16 :: Word8 -> Word16
toWord16 :: Word8 -> Word16
toWord16 = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toWord32 :: Word8 -> Word32
toWord32 :: Word8 -> Word32
toWord32 = Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toWord64 :: Word8 -> Word64
toWord64 :: Word8 -> Word64
toWord64 = Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toWord :: Word8 -> Word
toWord :: Word8 -> Word
toWord = Word8 -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral

toNatural :: Word8 -> Natural
toNatural :: Word8 -> Natural
toNatural = Word8 -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral

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

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

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

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

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

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

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

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

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

#ifdef __GLASGOW_HASKELL__
-- | Unsigned->signed, source fits in Int#, roundtrip at Int#
toInt8# :: Word8 -> (# Int8 | (# #) #)
toInt8# :: Word8 -> (# Int8 | (# #) #)
toInt8# (W8# Word8#
w8#) =
  let i# :: Int#
i# = Word# -> Int#
word2Int# (Word8# -> Word#
word8ToWord# Word8#
w8#)
      n# :: Int8#
n# = Int# -> Int8#
intToInt8# Int#
i#
  in case Int8# -> Int#
int8ToInt# Int8#
n# Int# -> Int# -> Int#
==# Int#
i# of
    Int#
1# -> (# Int8# -> Int8
I8# Int8#
n# | #)
    Int#
_  -> (# | (# #) #)
#endif