-- | Conversions from 'Word16'.
module Unwitch.Convert.Word16
  ( -- * Conversions
    toWord8
  , toWord32
  , toWord64
  , toWord
  , toNatural
  , toInt8
  , toInt16
  , toInt32
  , toInt64
  , toInt
  , toInteger
  , toFloat
  , toDouble
#ifdef __GLASGOW_HASKELL__
  , toCInt
#endif
#ifdef __GLASGOW_HASKELL__
  -- * Unboxed conversions
  -- $unboxed
  , toWord8#
  , toInt8#
  , toInt16#
#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 (word16ToWord#, word2Int#,
                           wordToWord8#, word8ToWord#,
                           intToInt8#, int8ToInt#,
                           intToInt16#, int16ToInt#,
                           eqWord#, (==#))
import           GHC.Int (Int8(..), Int16(..))
import           GHC.Word (Word8(..), Word16(..))
#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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ifdef __GLASGOW_HASKELL__
-- | Unsigned narrowing, roundtrip at Word#
toWord8# :: Word16 -> (# Word8 | (# #) #)
toWord8# :: Word16 -> (# Word8 | (# #) #)
toWord8# (W16# Word16#
w16#) =
  let w# :: Word#
w# = Word16# -> Word#
word16ToWord# Word16#
w16#
      n# :: Word8#
n# = Word# -> Word8#
wordToWord8# Word#
w#
  in case Word8# -> Word#
word8ToWord# Word8#
n# Word# -> Word# -> Int#
`eqWord#` Word#
w# of
    Int#
1# -> (# Word8# -> Word8
W8# Word8#
n# | #)
    Int#
_  -> (# | (# #) #)

-- | Unsigned->signed, source fits in Int#, roundtrip at Int#
toInt8# :: Word16 -> (# Int8 | (# #) #)
toInt8# :: Word16 -> (# Int8 | (# #) #)
toInt8# (W16# Word16#
w16#) =
  let i# :: Int#
i# = Word# -> Int#
word2Int# (Word16# -> Word#
word16ToWord# Word16#
w16#)
      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#
_  -> (# | (# #) #)

-- | Unsigned->signed, source fits in Int#, roundtrip at Int#
toInt16# :: Word16 -> (# Int16 | (# #) #)
toInt16# :: Word16 -> (# Int16 | (# #) #)
toInt16# (W16# Word16#
w16#) =
  let i# :: Int#
i# = Word# -> Int#
word2Int# (Word16# -> Word#
word16ToWord# Word16#
w16#)
      n# :: Int16#
n# = Int# -> Int16#
intToInt16# Int#
i#
  in case Int16# -> Int#
int16ToInt# Int16#
n# Int# -> Int# -> Int#
==# Int#
i# of
    Int#
1# -> (# Int16# -> Int16
I16# Int16#
n# | #)
    Int#
_  -> (# | (# #) #)
#endif