{-# LANGUAGE TemplateHaskell #-}
module MachDeps (littleEndian) where

-- technique stolen from: http://stackoverflow.com/a/6129295/176841 and
-- https://hackage.haskell.org/package/cpu-0.1.0/docs/src/System-Endian.html#getSystemEndianness

import Language.Haskell.TH.Syntax(Lift(..))
import Foreign.Marshal.Alloc
import Foreign.Storable
import Foreign.Ptr
import System.IO.Unsafe (unsafePerformIO)
import Data.Word

-- TODO TESTING: CORRECT ON 64-BIT LE MACHINES
-- | Compile-time constant; True on LE, False on BE, and compile-time error otherwise.
littleEndian :: Bool
littleEndian = 
    $( 
      let cst :: Word32
          cst = 0x01020304
          check :: [Word8] -> Bool
          check x
              | x == [1,2,3,4] = False -- BE
              | x == [4,3,2,1] = True  -- LE
              | otherwise = error $ "Very interesting endianness! "
                        ++"(unfortunately we don't support it yet)"
       in lift $ unsafePerformIO $ alloca $ \p -> do
            poke p cst
            let wd8Ptrs = map (castPtr p `plusPtr`) [0..3]
            mapM peek wd8Ptrs >>= return . check
           
      )