-- | Swap between big-endian and little endian
--
-- This is adapted from the `memory` package. Once
-- <https://github.com/vincenthz/hs-memory/pull/97> is merged this should not
-- be necessary anymore.
module Codec.Borsh.Internal.Util.ByteSwap (
    ByteSwap(..)
  , LE (..)
  , fromLE
  ) where

import Data.WideWord.Int128
import Data.WideWord.Word128
import Data.Word
import Foreign (Storable)
import GHC.ByteOrder (targetByteOrder, ByteOrder (..))

-- | Little Endian value
newtype LE a = LE { forall a. LE a -> a
unLE :: a }
  deriving newtype (Int -> LE a -> ShowS
[LE a] -> ShowS
LE a -> String
forall a. Show a => Int -> LE a -> ShowS
forall a. Show a => [LE a] -> ShowS
forall a. Show a => LE a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LE a] -> ShowS
$cshowList :: forall a. Show a => [LE a] -> ShowS
show :: LE a -> String
$cshow :: forall a. Show a => LE a -> String
showsPrec :: Int -> LE a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> LE a -> ShowS
Show, LE a -> LE a -> Bool
forall a. Eq a => LE a -> LE a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LE a -> LE a -> Bool
$c/= :: forall a. Eq a => LE a -> LE a -> Bool
== :: LE a -> LE a -> Bool
$c== :: forall a. Eq a => LE a -> LE a -> Bool
Eq, Ptr (LE a) -> IO (LE a)
Ptr (LE a) -> Int -> IO (LE a)
Ptr (LE a) -> Int -> LE a -> IO ()
Ptr (LE a) -> LE a -> IO ()
LE a -> Int
forall b. Ptr b -> Int -> IO (LE a)
forall b. Ptr b -> Int -> LE a -> IO ()
forall a. Storable a => Ptr (LE a) -> IO (LE a)
forall a. Storable a => Ptr (LE a) -> Int -> IO (LE a)
forall a. Storable a => Ptr (LE a) -> Int -> LE a -> IO ()
forall a. Storable a => Ptr (LE a) -> LE a -> IO ()
forall a. Storable a => LE a -> Int
forall a b. Storable a => Ptr b -> Int -> IO (LE a)
forall a b. Storable a => Ptr b -> Int -> LE a -> IO ()
forall a.
(a -> Int)
-> (a -> Int)
-> (Ptr a -> Int -> IO a)
-> (Ptr a -> Int -> a -> IO ())
-> (forall b. Ptr b -> Int -> IO a)
-> (forall b. Ptr b -> Int -> a -> IO ())
-> (Ptr a -> IO a)
-> (Ptr a -> a -> IO ())
-> Storable a
poke :: Ptr (LE a) -> LE a -> IO ()
$cpoke :: forall a. Storable a => Ptr (LE a) -> LE a -> IO ()
peek :: Ptr (LE a) -> IO (LE a)
$cpeek :: forall a. Storable a => Ptr (LE a) -> IO (LE a)
pokeByteOff :: forall b. Ptr b -> Int -> LE a -> IO ()
$cpokeByteOff :: forall a b. Storable a => Ptr b -> Int -> LE a -> IO ()
peekByteOff :: forall b. Ptr b -> Int -> IO (LE a)
$cpeekByteOff :: forall a b. Storable a => Ptr b -> Int -> IO (LE a)
pokeElemOff :: Ptr (LE a) -> Int -> LE a -> IO ()
$cpokeElemOff :: forall a. Storable a => Ptr (LE a) -> Int -> LE a -> IO ()
peekElemOff :: Ptr (LE a) -> Int -> IO (LE a)
$cpeekElemOff :: forall a. Storable a => Ptr (LE a) -> Int -> IO (LE a)
alignment :: LE a -> Int
$calignment :: forall a. Storable a => LE a -> Int
sizeOf :: LE a -> Int
$csizeOf :: forall a. Storable a => LE a -> Int
Storable)

-- | Convert from a little endian value to the cpu endianness
fromLE :: ByteSwap a => LE a -> a
fromLE :: forall a. ByteSwap a => LE a -> a
fromLE (LE a
a) = if ByteOrder
targetByteOrder forall a. Eq a => a -> a -> Bool
== ByteOrder
LittleEndian then a
a else forall a. ByteSwap a => a -> a
byteSwap a
a

class Storable a => ByteSwap a where
  byteSwap :: a -> a

instance ByteSwap Word8   where byteSwap :: Word8 -> Word8
byteSwap = forall a. a -> a
id
instance ByteSwap Word16  where byteSwap :: Word16 -> Word16
byteSwap = Word16 -> Word16
byteSwap16
instance ByteSwap Word32  where byteSwap :: Word32 -> Word32
byteSwap = Word32 -> Word32
byteSwap32
instance ByteSwap Word64  where byteSwap :: Word64 -> Word64
byteSwap = Word64 -> Word64
byteSwap64
instance ByteSwap Word128 where byteSwap :: Word128 -> Word128
byteSwap = Word128 -> Word128
byteSwapWord128
instance ByteSwap Int128  where byteSwap :: Int128 -> Int128
byteSwap = Int128 -> Int128
byteSwapInt128