packages feed

columbia-0.1.0.1: src/Data/Columbia/MyEndianness.hs

{-# LANGUAGE Trustworthy, ScopedTypeVariables #-}

-- | Read and write data in little-endian format.
module Data.Columbia.MyEndianness (bigEndian, swapEndian') where

import System.IO.Unsafe
import Foreign.Marshal.Alloc
import qualified Foreign.Storable as S
import Data.Endian
import Control.Exception
import Foreign.Ptr
import Data.Bits
import Data.Word
import Data.Int

----------------------------------------------
-- Endianness

-- | Determine whether running on a big-endian system.
bigEndian :: IO Bool
bigEndian = do
	p <- malloc
	finally
		(do
		S.poke p (bit 24 :: Word32)
		n :: Word8 <- S.peek (castPtr p)
		return (n == 1))
		(free p)

{-# NOINLINE _bigEndian #-}
_bigEndian :: Bool
_bigEndian = unsafePerformIO bigEndian

instance (EndianSensitive t, EndianSensitive u, EndianSensitive v, EndianSensitive w) => EndianSensitive (t, u, v, w) where
	swapEndian (a, b, c, d) = (swapEndian a, swapEndian b, swapEndian c, swapEndian d)

instance EndianSensitive Int8 where
	swapEndian = id

instance EndianSensitive Word8 where
	swapEndian = id

byteSwapped x = unsafePerformIO $ do
	p <- malloc
	finally
		(do
		S.poke p x
		b1 :: Word8 <- S.peekByteOff p 0
		b2 :: Word8 <- S.peekByteOff p 1
		b3 :: Word8 <- S.peekByteOff p 2
		b4 :: Word8 <- S.peekByteOff p 3
		S.pokeByteOff p 3 b1
		S.pokeByteOff p 2 b2
		S.pokeByteOff p 1 b3
		S.pokeByteOff p 0 b4
		S.peek p)
		(free p)

instance EndianSensitive Float where
	swapEndian = byteSwapped

instance EndianSensitive Char where
	swapEndian = byteSwapped

instance (EndianSensitive t, EndianSensitive u) => EndianSensitive (t, u) where
	swapEndian (x, y) = (swapEndian x, swapEndian y)

instance (EndianSensitive t, EndianSensitive u) => EndianSensitive (Either t u) where
	swapEndian = either (Left . swapEndian) (Right . swapEndian)

instance EndianSensitive () where
	swapEndian () = ()

swapEndian' :: (EndianSensitive e) => e->e
swapEndian' = if _bigEndian then swapEndian else id