cairo-image-0.1.0.0: src/System/TargetEndian.hs
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
module System.TargetEndian (
-- * To Select According To Endian
endian ) where
import Language.Haskell.TH (ExpQ, runIO)
import Foreign.Ptr (castPtr)
import Foreign.Marshal (alloca, peekArray)
import Foreign.Storable (poke)
import Data.Word (Word8, Word32)
import System.Environment (lookupEnv)
---------------------------------------------------------------------------
endian :: ExpQ -> ExpQ -> ExpQ
endian el eb = runIO targetEndian >>= \case
Right LittleEndian -> el; Right BigEndian -> eb
Right UnknownEndian -> error "Unknown endian"; Left emsg -> error emsg
data Endian = LittleEndian | BigEndian | UnknownEndian deriving Show
targetEndian :: IO (Either String Endian)
targetEndian = lookupEnv "GHC_TARGET_ENDIAN" >>= \case
Just "little-endian" -> pure $ Right LittleEndian
Just "big-endian" -> pure $ Right BigEndian
Just edn -> pure . Left $ "no such endian: " ++ edn ++ "\n" ++
"\tGHC_TARGET_ENDIAN: little-endian or big-endian"
Nothing -> Right <$> checkEndian
checkEndian :: IO Endian
checkEndian = (<$> alloca \p -> poke p word32 >> peekArray 4 (castPtr p)) \case
[4 :: Word8, 3, 2, 1] -> LittleEndian; [1, 2, 3, 4] -> BigEndian
_ -> UnknownEndian
where word32 :: Word32; word32 = 0x01020304