{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash             #-}
{-# LANGUAGE DefaultSignatures     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE UnboxedTuples         #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE TypeOperators         #-}
module Basement.IntegralConv
    ( IntegralDownsize(..)
    , IntegralUpsize(..)
    , intToInt64
    , int64ToInt
    , wordToWord64
    , word64ToWord32s
    , Word32x2(..)
    , word64ToWord
    , wordToChar
    , wordToInt
    , charToInt
    ) where

import GHC.Types
import GHC.Prim hiding (word64ToWord#)
import qualified GHC.Prim
import GHC.Int
import GHC.Word
import Prelude (Integer, fromIntegral)
import Basement.Compat.Base
import Basement.Compat.Natural
import Basement.Compat.Primitive
import Basement.Numerical.Number
import Basement.Numerical.Conversion

-- | Downsize an integral value
class IntegralDownsize a b where
    integralDownsize :: a -> b
    default integralDownsize :: a ~ b => a -> b
    integralDownsize = forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id

    integralDownsizeCheck :: a -> Maybe b

-- | Upsize an integral value
--
-- The destination type 'b' size need to be greater or equal
-- than the size type of 'a'
class IntegralUpsize a b where
    integralUpsize      :: a -> b

integralDownsizeBounded :: forall a b . (Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a)
                        => (a -> b)
                        -> a
                        -> Maybe b
integralDownsizeBounded :: forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded a -> b
aToB a
x
    | a
x forall a. Ord a => a -> a -> Bool
< forall a b. IntegralUpsize a b => a -> b
integralUpsize (forall a. Bounded a => a
minBound :: b) Bool -> Bool -> Bool
&& a
x forall a. Ord a => a -> a -> Bool
> forall a b. IntegralUpsize a b => a -> b
integralUpsize (forall a. Bounded a => a
maxBound :: b) = forall a. Maybe a
Nothing
    | Bool
otherwise                                                                = forall a. a -> Maybe a
Just (a -> b
aToB a
x)

instance IsIntegral a => IntegralUpsize a Integer where
    integralUpsize :: a -> Integer
integralUpsize = forall a. IsIntegral a => a -> Integer
toInteger
instance IsNatural a => IntegralUpsize a Natural where
    integralUpsize :: a -> Natural
integralUpsize = forall a. IsNatural a => a -> Natural
toNatural

instance IntegralUpsize Int8 Int16 where
    integralUpsize :: Int8 -> Int16
integralUpsize (I8# Int8#
i) = Int16# -> Int16
I16# (Int8# -> Int16#
int8ToInt16# Int8#
i)
instance IntegralUpsize Int8 Int32 where
    integralUpsize :: Int8 -> Int32
integralUpsize (I8# Int8#
i) = Int32# -> Int32
I32# (Int8# -> Int32#
int8ToInt32# Int8#
i)
instance IntegralUpsize Int8 Int64 where
    integralUpsize :: Int8 -> Int64
integralUpsize (I8# Int8#
i) = Int -> Int64
intToInt64 (Int# -> Int
I# (Int8# -> Int#
int8ToInt# Int8#
i))
instance IntegralUpsize Int8 Int where
    integralUpsize :: Int8 -> Int
integralUpsize (I8# Int8#
i) = Int# -> Int
I# (Int8# -> Int#
int8ToInt# Int8#
i)

instance IntegralUpsize Int16 Int32 where
    integralUpsize :: Int16 -> Int32
integralUpsize (I16# Int16#
i) = Int32# -> Int32
I32# (Int16# -> Int32#
int16ToInt32# Int16#
i)
instance IntegralUpsize Int16 Int64 where
    integralUpsize :: Int16 -> Int64
integralUpsize (I16# Int16#
i) = Int -> Int64
intToInt64 (Int# -> Int
I# (Int16# -> Int#
int16ToInt# Int16#
i))
instance IntegralUpsize Int16 Int where
    integralUpsize :: Int16 -> Int
integralUpsize (I16# Int16#
i) = Int# -> Int
I# (Int16# -> Int#
int16ToInt# Int16#
i)

instance IntegralUpsize Int32 Int64 where
    integralUpsize :: Int32 -> Int64
integralUpsize (I32# Int32#
i) = Int -> Int64
intToInt64 (Int# -> Int
I# (Int32# -> Int#
int32ToInt# Int32#
i))
instance IntegralUpsize Int32 Int where
    integralUpsize :: Int32 -> Int
integralUpsize (I32# Int32#
i) = Int# -> Int
I# (Int32# -> Int#
int32ToInt# Int32#
i)

instance IntegralUpsize Int Int64 where
    integralUpsize :: Int -> Int64
integralUpsize = Int -> Int64
intToInt64

instance IntegralUpsize Word8 Word16 where
    integralUpsize :: Word8 -> Word16
integralUpsize (W8# Word8#
i) = Word16# -> Word16
W16# (Word8# -> Word16#
word8ToWord16# Word8#
i)
instance IntegralUpsize Word8 Word32 where
    integralUpsize :: Word8 -> Word32
integralUpsize (W8# Word8#
i) = Word32# -> Word32
W32# (Word8# -> Word32#
word8ToWord32# Word8#
i)
instance IntegralUpsize Word8 Word64 where
    integralUpsize :: Word8 -> Word64
integralUpsize (W8# Word8#
i) = Word -> Word64
wordToWord64 (Word# -> Word
W# (Word8# -> Word#
word8ToWord# Word8#
i))
instance IntegralUpsize Word8 Word where
    integralUpsize :: Word8 -> Word
integralUpsize (W8# Word8#
i) = Word# -> Word
W# (Word8# -> Word#
word8ToWord# Word8#
i)
instance IntegralUpsize Word8 Int16 where
    integralUpsize :: Word8 -> Int16
integralUpsize (W8# Word8#
w) = Int16# -> Int16
I16# (Word8# -> Int16#
word8ToInt16# Word8#
w)
instance IntegralUpsize Word8 Int32 where
    integralUpsize :: Word8 -> Int32
integralUpsize (W8# Word8#
w) = Int32# -> Int32
I32# (Word8# -> Int32#
word8ToInt32# Word8#
w)
instance IntegralUpsize Word8 Int64 where
    integralUpsize :: Word8 -> Int64
integralUpsize (W8# Word8#
w) = Int -> Int64
intToInt64 (Int# -> Int
I# (Word# -> Int#
word2Int# (Word8# -> Word#
word8ToWord# Word8#
w)))
instance IntegralUpsize Word8 Int where
    integralUpsize :: Word8 -> Int
integralUpsize (W8# Word8#
w) = Int# -> Int
I# (Word# -> Int#
word2Int# (Word8# -> Word#
word8ToWord# Word8#
w))

instance IntegralUpsize Word16 Word32 where
    integralUpsize :: Word16 -> Word32
integralUpsize (W16# Word16#
i) = Word32# -> Word32
W32# (Word16# -> Word32#
word16ToWord32# Word16#
i)
instance IntegralUpsize Word16 Word64 where
    integralUpsize :: Word16 -> Word64
integralUpsize (W16# Word16#
i) = Word -> Word64
wordToWord64 (Word# -> Word
W# (Word16# -> Word#
word16ToWord# Word16#
i))
instance IntegralUpsize Word16 Word where
    integralUpsize :: Word16 -> Word
integralUpsize (W16# Word16#
i) = Word# -> Word
W# (Word16# -> Word#
word16ToWord# Word16#
i)

instance IntegralUpsize Word32 Word64 where
    integralUpsize :: Word32 -> Word64
integralUpsize (W32# Word32#
i) = Word -> Word64
wordToWord64 (Word# -> Word
W# (Word32# -> Word#
word32ToWord# Word32#
i))
instance IntegralUpsize Word32 Word where
    integralUpsize :: Word32 -> Word
integralUpsize (W32# Word32#
i) = Word# -> Word
W# (Word32# -> Word#
word32ToWord# Word32#
i)

instance IntegralUpsize Word Word64 where
    integralUpsize :: Word -> Word64
integralUpsize = Word -> Word64
wordToWord64

instance IntegralDownsize Int Int8 where
    integralDownsize :: Int -> Int8
integralDownsize      (I# Int#
i) = Int8# -> Int8
I8# (Int# -> Int8#
intToInt8# Int#
i)
    integralDownsizeCheck :: Int -> Maybe Int8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Int Int16 where
    integralDownsize :: Int -> Int16
integralDownsize      (I# Int#
i) = Int16# -> Int16
I16# (Int# -> Int16#
intToInt16# Int#
i)
    integralDownsizeCheck :: Int -> Maybe Int16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Int Int32 where
    integralDownsize :: Int -> Int32
integralDownsize      (I# Int#
i) = Int32# -> Int32
I32# (Int# -> Int32#
intToInt32# Int#
i)
    integralDownsizeCheck :: Int -> Maybe Int32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Int64 Int8 where
    integralDownsize :: Int64 -> Int8
integralDownsize      Int64
i = forall a b. IntegralDownsize a b => a -> b
integralDownsize (Int64 -> Int
int64ToInt Int64
i)
    integralDownsizeCheck :: Int64 -> Maybe Int8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Int64 Int16 where
    integralDownsize :: Int64 -> Int16
integralDownsize      Int64
i = forall a b. IntegralDownsize a b => a -> b
integralDownsize (Int64 -> Int
int64ToInt Int64
i)
    integralDownsizeCheck :: Int64 -> Maybe Int16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Int64 Int32 where
    integralDownsize :: Int64 -> Int32
integralDownsize      Int64
i = forall a b. IntegralDownsize a b => a -> b
integralDownsize (Int64 -> Int
int64ToInt Int64
i)
    integralDownsizeCheck :: Int64 -> Maybe Int32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Int64 Int where
    integralDownsize :: Int64 -> Int
integralDownsize      Int64
i = Int64 -> Int
int64ToInt Int64
i
    integralDownsizeCheck :: Int64 -> Maybe Int
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Word64 Word8 where
#if __GLASGOW_HASKELL__ >= 904
    integralDownsize      (W64# i) = W8# (wordToWord8# (GHC.Prim.word64ToWord# i))
#else
    integralDownsize :: Word64 -> Word8
integralDownsize      (W64# Word#
i) = Word8# -> Word8
W8# (Word# -> Word8#
wordToWord8# (Word# -> Word#
word64ToWord# Word#
i))
#endif
    integralDownsizeCheck :: Word64 -> Maybe Word8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Word64 Word16 where
#if __GLASGOW_HASKELL__ >= 904
    integralDownsize      (W64# i) = W16# (wordToWord16# (GHC.Prim.word64ToWord# i))
#else
    integralDownsize :: Word64 -> Word16
integralDownsize      (W64# Word#
i) = Word16# -> Word16
W16# (Word# -> Word16#
wordToWord16# (Word# -> Word#
word64ToWord# Word#
i))
#endif
    integralDownsizeCheck :: Word64 -> Maybe Word16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Word64 Word32 where
#if __GLASGOW_HASKELL__ >= 904
    integralDownsize      (W64# i) = W32# (wordToWord32# (GHC.Prim.word64ToWord# i))
#else
    integralDownsize :: Word64 -> Word32
integralDownsize      (W64# Word#
i) = Word32# -> Word32
W32# (Word# -> Word32#
wordToWord32# (Word# -> Word#
word64ToWord# Word#
i))
#endif
    integralDownsizeCheck :: Word64 -> Maybe Word32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Word Word8 where
    integralDownsize :: Word -> Word8
integralDownsize (W# Word#
w) = Word8# -> Word8
W8# (Word# -> Word8#
wordToWord8# Word#
w)
    integralDownsizeCheck :: Word -> Maybe Word8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Word Word16 where
    integralDownsize :: Word -> Word16
integralDownsize (W# Word#
w) = Word16# -> Word16
W16# (Word# -> Word16#
wordToWord16# Word#
w)
    integralDownsizeCheck :: Word -> Maybe Word16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Word Word32 where
    integralDownsize :: Word -> Word32
integralDownsize (W# Word#
w) = Word32# -> Word32
W32# (Word# -> Word32#
wordToWord32# Word#
w)
    integralDownsizeCheck :: Word -> Maybe Word32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Word32 Word8 where
    integralDownsize :: Word32 -> Word8
integralDownsize      (W32# Word32#
i) = Word8# -> Word8
W8# (Word32# -> Word8#
word32ToWord8# Word32#
i)
    integralDownsizeCheck :: Word32 -> Maybe Word8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Word32 Word16 where
    integralDownsize :: Word32 -> Word16
integralDownsize      (W32# Word32#
i) = Word16# -> Word16
W16# (Word32# -> Word16#
word32ToWord16# Word32#
i)
    integralDownsizeCheck :: Word32 -> Maybe Word16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Word16 Word8 where
    integralDownsize :: Word16 -> Word8
integralDownsize      (W16# Word16#
i) = Word8# -> Word8
W8# (Word16# -> Word8#
word16ToWord8# Word16#
i)
    integralDownsizeCheck :: Word16 -> Maybe Word8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Integer Int8 where
    integralDownsize :: Integer -> Int8
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Int8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Int16 where
    integralDownsize :: Integer -> Int16
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Int16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Int32 where
    integralDownsize :: Integer -> Int32
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Int32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Int64 where
    integralDownsize :: Integer -> Int64
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Int64
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize

instance IntegralDownsize Integer Word8 where
    integralDownsize :: Integer -> Word8
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Word8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Word16 where
    integralDownsize :: Integer -> Word16
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Word16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Word32 where
    integralDownsize :: Integer -> Word32
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Word32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Word64 where
    integralDownsize :: Integer -> Word64
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Integer -> Maybe Word64
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Integer Natural where
    integralDownsize :: Integer -> Natural
integralDownsize Integer
i
        | Integer
i forall a. Ord a => a -> a -> Bool
>= Integer
0    = forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
i
        | Bool
otherwise = Natural
0
    integralDownsizeCheck :: Integer -> Maybe Natural
integralDownsizeCheck Integer
i
        | Integer
i forall a. Ord a => a -> a -> Bool
>= Integer
0    = forall a. a -> Maybe a
Just (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
i)
        | Bool
otherwise = forall a. Maybe a
Nothing

instance IntegralDownsize Natural Word8 where
    integralDownsize :: Natural -> Word8
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Natural -> Maybe Word8
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Natural Word16 where
    integralDownsize :: Natural -> Word16
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Natural -> Maybe Word16
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Natural Word32 where
    integralDownsize :: Natural -> Word32
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Natural -> Maybe Word32
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize
instance IntegralDownsize Natural Word64 where
    integralDownsize :: Natural -> Word64
integralDownsize = forall a b. (Integral a, Num b) => a -> b
fromIntegral
    integralDownsizeCheck :: Natural -> Maybe Word64
integralDownsizeCheck = forall a b.
(Ord a, Bounded b, IntegralDownsize a b, IntegralUpsize b a) =>
(a -> b) -> a -> Maybe b
integralDownsizeBounded forall a b. IntegralDownsize a b => a -> b
integralDownsize