# LANGUAGE CPP , BangPatterns #
#if __GLASGOW_HASKELL__ >= 701
# LANGUAGE Trustworthy #
#endif
  | Copyright    : ( c ) 2010 - 2011  
-- License       : BSD3-style (see LICENSE)
--
  Maintainer     :   <  >
  Portability    : GHC
--
module Data.ByteString.Builder.Prim.Binary (

  -- ** Binary encodings
    int8
  , word8

  -- *** Big-endian
  , int16BE
  , int32BE
  , int64BE

  , word16BE
  , word32BE
  , word64BE

  , floatBE
  , doubleBE

  -- *** Little-endian
  , int16LE
  , int32LE
  , int64LE

  , word16LE
  , word32LE
  , word64LE

  , floatLE
  , doubleLE

  -- *** Non-portable, host-dependent
  , intHost
  , int16Host
  , int32Host
  , int64Host

  , wordHost
  , word16Host
  , word32Host
  , word64Host

  , floatHost
  , doubleHost

  ) where

import Data.ByteString.Builder.Prim.Internal
import Data.ByteString.Builder.Prim.Internal.UncheckedShifts
import Data.ByteString.Builder.Prim.Internal.Floating

import Foreign

#include "MachDeps.h"

------------------------------------------------------------------------------
-- Binary encoding
------------------------------------------------------------------------------

-- Word encodings
-----------------

-- | Encoding single unsigned bytes as-is.
--
# INLINE word8 #
word8 :: FixedPrim Word8
word8 = storableToF

--
-- We rely on the fromIntegral to do the right masking for us.
-- The inlining here is critical, and can be worth 4x performance
--

  | Encoding ' Word16 's in big endian format .
# INLINE word16BE #
word16BE :: FixedPrim Word16
#ifdef WORDS_BIGENDIAN
word16BE = word16Host
#else
word16BE = fixedPrim 2 $ \w p -> do
    poke p               (fromIntegral (shiftr_w16 w 8) :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (w)              :: Word8)
#endif

  | Encoding ' Word16 's in little endian format .
{-# INLINE word16LE #-}
word16LE :: FixedPrim Word16
#ifdef WORDS_BIGENDIAN
word16LE = fixedPrim 2 $ \w p -> do
    poke p               (fromIntegral (w)              :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w16 w 8) :: Word8)
#else
word16LE = word16Host
#endif

  | Encoding '  's in big endian format .
# INLINE word32BE #
word32BE :: FixedPrim Word32
#ifdef WORDS_BIGENDIAN
word32BE = word32Host
#else
word32BE = fixedPrim 4 $ \w p -> do
    poke p               (fromIntegral (shiftr_w32 w 24) :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w 16) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w  8) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (w)               :: Word8)
#endif

  | Encoding '  's in little endian format .
# INLINE word32LE #
word32LE :: FixedPrim Word32
#ifdef WORDS_BIGENDIAN
word32LE = fixedPrim 4 $ \w p -> do
    poke p               (fromIntegral (w)               :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w  8) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w 16) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 w 24) :: Word8)
#else
word32LE = word32Host
#endif

  on a little endian machine :
  word32LE w32 = fixedPrim 4 ( \w p - > poke ( castPtr p ) w32 )

-- | Encoding 'Word64's in big endian format.
# INLINE word64BE #
word64BE :: FixedPrim Word64
#ifdef WORDS_BIGENDIAN
word64BE = word64Host
#else
#if WORD_SIZE_IN_BITS < 64
--
  To avoid expensive 64 bit shifts on 32 bit machines , we cast to
   , and write that
--
word64BE =
    fixedPrim 8 $ \w p -> do
        let a = fromIntegral (shiftr_w64 w 32) :: Word32
            b = fromIntegral w                 :: Word32
        poke p               (fromIntegral (shiftr_w32 a 24) :: Word8)
        poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a 16) :: Word8)
        poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a  8) :: Word8)
        poke (p `plusPtr` 3) (fromIntegral (a)               :: Word8)
        poke (p `plusPtr` 4) (fromIntegral (shiftr_w32 b 24) :: Word8)
        poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b 16) :: Word8)
        poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b  8) :: Word8)
        poke (p `plusPtr` 7) (fromIntegral (b)               :: Word8)
#else
word64BE = fixedPrim 8 $ \w p -> do
    poke p               (fromIntegral (shiftr_w64 w 56) :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w 48) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 40) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 32) :: Word8)
    poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 24) :: Word8)
    poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 16) :: Word8)
    poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w  8) :: Word8)
    poke (p `plusPtr` 7) (fromIntegral (w)               :: Word8)
#endif
#endif

  | Encoding ' Word64 's in little endian format .
# INLINE word64LE #
word64LE :: FixedPrim Word64
#ifdef WORDS_BIGENDIAN
#if WORD_SIZE_IN_BITS < 64
word64LE =
    fixedPrim 8 $ \w p -> do
        let b = fromIntegral (shiftr_w64 w 32) :: Word32
            a = fromIntegral w                 :: Word32
        poke (p)             (fromIntegral (a)               :: Word8)
        poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a  8) :: Word8)
        poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a 16) :: Word8)
        poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 a 24) :: Word8)
        poke (p `plusPtr` 4) (fromIntegral (b)               :: Word8)
        poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b  8) :: Word8)
        poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b 16) :: Word8)
        poke (p `plusPtr` 7) (fromIntegral (shiftr_w32 b 24) :: Word8)
#else
word64LE = fixedPrim 8 $ \w p -> do
    poke p               (fromIntegral (w)               :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w  8) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 16) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 24) :: Word8)
    poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 32) :: Word8)
    poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 40) :: Word8)
    poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w 48) :: Word8)
    poke (p `plusPtr` 7) (fromIntegral (shiftr_w64 w 56) :: Word8)
#endif
#else
word64LE = word64Host
#endif


  | Encode a single native machine ' Word ' . The ' Word 's is encoded in host order ,
  host endian form , for the machine you are on . On a 64 bit machine the ' Word '
  is an 8 byte value , on a 32 bit machine , 4 bytes . Values encoded this way
-- are not portable to different endian or word sized machines, without
-- conversion.
--
# INLINE wordHost #
wordHost :: FixedPrim Word
wordHost = storableToF

  | Encoding ' Word16 's in native host order and host endianness .
# INLINE word16Host #
word16Host :: FixedPrim Word16
word16Host = storableToF

  | Encoding '  's in native host order and host endianness .
# INLINE word32Host #
word32Host :: FixedPrim Word32
word32Host = storableToF

-- | Encoding 'Word64's in native host order and host endianness.
# INLINE word64Host #
word64Host :: FixedPrim Word64
word64Host = storableToF


------------------------------------------------------------------------------
-- Int encodings
------------------------------------------------------------------------------
--
-- We rely on 'fromIntegral' to do a loss-less conversion to the corresponding
-- 'Word' type
--
------------------------------------------------------------------------------

-- | Encoding single signed bytes as-is.
--
# INLINE int8 #
int8 :: FixedPrim Int8
int8 = fromIntegral >$< word8

-- | Encoding 'Int16's in big endian format.
# INLINE int16BE #
int16BE :: FixedPrim Int16
int16BE = fromIntegral >$< word16BE

  | Encoding ' Int16 's in little endian format .
# INLINE int16LE #
int16LE :: FixedPrim Int16
int16LE = fromIntegral >$< word16LE

  | Encoding ' Int32 's in big endian format .
# INLINE int32BE #
int32BE :: FixedPrim Int32
int32BE = fromIntegral >$< word32BE

  | Encoding ' Int32 's in little endian format .
# INLINE int32LE #
int32LE :: FixedPrim Int32
int32LE = fromIntegral >$< word32LE

  | Encoding ' Int64 's in big endian format .
# INLINE int64BE #
int64BE :: FixedPrim Int64
int64BE = fromIntegral >$< word64BE

  | Encoding ' Int64 's in little endian format .
# INLINE int64LE #
int64LE :: FixedPrim Int64
int64LE = fromIntegral >$< word64LE


-- TODO: Ensure that they are safe on architectures where an unaligned write is
-- an error.

-- | Encode a single native machine 'Int'. The 'Int's is encoded in host order,
  host endian form , for the machine you are on . On a 64 bit machine the ' Int '
  is an 8 byte value , on a 32 bit machine , 4 bytes . Values encoded this way
-- are not portable to different endian or integer sized machines, without
-- conversion.
--
# INLINE intHost #
intHost :: FixedPrim Int
intHost = storableToF

-- | Encoding 'Int16's in native host order and host endianness.
# INLINE int16Host #
int16Host :: FixedPrim Int16
int16Host = storableToF

  | Encoding ' Int32 's in native host order and host endianness .
# INLINE int32Host #
int32Host :: FixedPrim Int32
int32Host = storableToF

  | Encoding ' Int64 's in native host order and host endianness .
# INLINE int64Host #
int64Host :: FixedPrim Int64
int64Host = storableToF

-- IEEE Floating Point Numbers
------------------------------

-- | Encode a 'Float' in big endian format.
# INLINE floatBE #
floatBE :: FixedPrim Float
floatBE = encodeFloatViaWord32F word32BE

  | Encode a ' Float ' in little endian format .
# INLINE floatLE #
floatLE :: FixedPrim Float
floatLE = encodeFloatViaWord32F word32LE

-- | Encode a 'Double' in big endian format.
{-# INLINE doubleBE #-}
doubleBE :: FixedPrim Double
doubleBE = encodeDoubleViaWord64F word64BE

  | Encode a ' Double ' in little endian format .
# INLINE doubleLE #
doubleLE :: FixedPrim Double
doubleLE = encodeDoubleViaWord64F word64LE


-- | Encode a 'Float' in native host order and host endianness. Values written
  this way are not portable to different endian machines , without conversion .
--
# INLINE floatHost #
floatHost :: FixedPrim Float
floatHost = storableToF

-- | Encode a 'Double' in native host order and host endianness.
# INLINE doubleHost #
doubleHost :: FixedPrim Double
doubleHost = storableToF



 License       : BSD3-style (see LICENSE)


 ** Binary encodings
 *** Big-endian
 *** Little-endian
 *** Non-portable, host-dependent
----------------------------------------------------------------------------
 Binary encoding
----------------------------------------------------------------------------
 Word encodings
---------------
 | Encoding single unsigned bytes as-is.


 We rely on the fromIntegral to do the right masking for us.
 The inlining here is critical, and can be worth 4x performance

# INLINE word16LE #
 | Encoding 'Word64's in big endian format.


 are not portable to different endian or word sized machines, without
 conversion.

 | Encoding 'Word64's in native host order and host endianness.
----------------------------------------------------------------------------
 Int encodings
----------------------------------------------------------------------------

 We rely on 'fromIntegral' to do a loss-less conversion to the corresponding
 'Word' type

----------------------------------------------------------------------------
 | Encoding single signed bytes as-is.

 | Encoding 'Int16's in big endian format.
 TODO: Ensure that they are safe on architectures where an unaligned write is
 an error.
 | Encode a single native machine 'Int'. The 'Int's is encoded in host order,
 are not portable to different endian or integer sized machines, without
 conversion.

 | Encoding 'Int16's in native host order and host endianness.
 IEEE Floating Point Numbers
----------------------------
 | Encode a 'Float' in big endian format.
 | Encode a 'Double' in big endian format.
# INLINE doubleBE #
 | Encode a 'Float' in native host order and host endianness. Values written

 | Encode a 'Double' in native host order and host endianness.
# LANGUAGE CPP , BangPatterns #
#if __GLASGOW_HASKELL__ >= 701
# LANGUAGE Trustworthy #
#endif
  | Copyright    : ( c ) 2010 - 2011  
  Maintainer     :   <  >
  Portability    : GHC
module Data.ByteString.Builder.Prim.Binary (

    int8
  , word8

  , int16BE
  , int32BE
  , int64BE

  , word16BE
  , word32BE
  , word64BE

  , floatBE
  , doubleBE

  , int16LE
  , int32LE
  , int64LE

  , word16LE
  , word32LE
  , word64LE

  , floatLE
  , doubleLE

  , intHost
  , int16Host
  , int32Host
  , int64Host

  , wordHost
  , word16Host
  , word32Host
  , word64Host

  , floatHost
  , doubleHost

  ) where

import Data.ByteString.Builder.Prim.Internal
import Data.ByteString.Builder.Prim.Internal.UncheckedShifts
import Data.ByteString.Builder.Prim.Internal.Floating

import Foreign

#include "MachDeps.h"



# INLINE word8 #
word8 :: FixedPrim Word8
word8 = storableToF


  | Encoding ' Word16 's in big endian format .
# INLINE word16BE #
word16BE :: FixedPrim Word16
#ifdef WORDS_BIGENDIAN
word16BE = word16Host
#else
word16BE = fixedPrim 2 $ \w p -> do
    poke p               (fromIntegral (shiftr_w16 w 8) :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (w)              :: Word8)
#endif

  | Encoding ' Word16 's in little endian format .
word16LE :: FixedPrim Word16
#ifdef WORDS_BIGENDIAN
word16LE = fixedPrim 2 $ \w p -> do
    poke p               (fromIntegral (w)              :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w16 w 8) :: Word8)
#else
word16LE = word16Host
#endif

  | Encoding '  's in big endian format .
# INLINE word32BE #
word32BE :: FixedPrim Word32
#ifdef WORDS_BIGENDIAN
word32BE = word32Host
#else
word32BE = fixedPrim 4 $ \w p -> do
    poke p               (fromIntegral (shiftr_w32 w 24) :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w 16) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w  8) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (w)               :: Word8)
#endif

  | Encoding '  's in little endian format .
# INLINE word32LE #
word32LE :: FixedPrim Word32
#ifdef WORDS_BIGENDIAN
word32LE = fixedPrim 4 $ \w p -> do
    poke p               (fromIntegral (w)               :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 w  8) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 w 16) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 w 24) :: Word8)
#else
word32LE = word32Host
#endif

  on a little endian machine :
  word32LE w32 = fixedPrim 4 ( \w p - > poke ( castPtr p ) w32 )

# INLINE word64BE #
word64BE :: FixedPrim Word64
#ifdef WORDS_BIGENDIAN
word64BE = word64Host
#else
#if WORD_SIZE_IN_BITS < 64
  To avoid expensive 64 bit shifts on 32 bit machines , we cast to
   , and write that
word64BE =
    fixedPrim 8 $ \w p -> do
        let a = fromIntegral (shiftr_w64 w 32) :: Word32
            b = fromIntegral w                 :: Word32
        poke p               (fromIntegral (shiftr_w32 a 24) :: Word8)
        poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a 16) :: Word8)
        poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a  8) :: Word8)
        poke (p `plusPtr` 3) (fromIntegral (a)               :: Word8)
        poke (p `plusPtr` 4) (fromIntegral (shiftr_w32 b 24) :: Word8)
        poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b 16) :: Word8)
        poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b  8) :: Word8)
        poke (p `plusPtr` 7) (fromIntegral (b)               :: Word8)
#else
word64BE = fixedPrim 8 $ \w p -> do
    poke p               (fromIntegral (shiftr_w64 w 56) :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w 48) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 40) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 32) :: Word8)
    poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 24) :: Word8)
    poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 16) :: Word8)
    poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w  8) :: Word8)
    poke (p `plusPtr` 7) (fromIntegral (w)               :: Word8)
#endif
#endif

  | Encoding ' Word64 's in little endian format .
# INLINE word64LE #
word64LE :: FixedPrim Word64
#ifdef WORDS_BIGENDIAN
#if WORD_SIZE_IN_BITS < 64
word64LE =
    fixedPrim 8 $ \w p -> do
        let b = fromIntegral (shiftr_w64 w 32) :: Word32
            a = fromIntegral w                 :: Word32
        poke (p)             (fromIntegral (a)               :: Word8)
        poke (p `plusPtr` 1) (fromIntegral (shiftr_w32 a  8) :: Word8)
        poke (p `plusPtr` 2) (fromIntegral (shiftr_w32 a 16) :: Word8)
        poke (p `plusPtr` 3) (fromIntegral (shiftr_w32 a 24) :: Word8)
        poke (p `plusPtr` 4) (fromIntegral (b)               :: Word8)
        poke (p `plusPtr` 5) (fromIntegral (shiftr_w32 b  8) :: Word8)
        poke (p `plusPtr` 6) (fromIntegral (shiftr_w32 b 16) :: Word8)
        poke (p `plusPtr` 7) (fromIntegral (shiftr_w32 b 24) :: Word8)
#else
word64LE = fixedPrim 8 $ \w p -> do
    poke p               (fromIntegral (w)               :: Word8)
    poke (p `plusPtr` 1) (fromIntegral (shiftr_w64 w  8) :: Word8)
    poke (p `plusPtr` 2) (fromIntegral (shiftr_w64 w 16) :: Word8)
    poke (p `plusPtr` 3) (fromIntegral (shiftr_w64 w 24) :: Word8)
    poke (p `plusPtr` 4) (fromIntegral (shiftr_w64 w 32) :: Word8)
    poke (p `plusPtr` 5) (fromIntegral (shiftr_w64 w 40) :: Word8)
    poke (p `plusPtr` 6) (fromIntegral (shiftr_w64 w 48) :: Word8)
    poke (p `plusPtr` 7) (fromIntegral (shiftr_w64 w 56) :: Word8)
#endif
#else
word64LE = word64Host
#endif


  | Encode a single native machine ' Word ' . The ' Word 's is encoded in host order ,
  host endian form , for the machine you are on . On a 64 bit machine the ' Word '
  is an 8 byte value , on a 32 bit machine , 4 bytes . Values encoded this way
# INLINE wordHost #
wordHost :: FixedPrim Word
wordHost = storableToF

  | Encoding ' Word16 's in native host order and host endianness .
# INLINE word16Host #
word16Host :: FixedPrim Word16
word16Host = storableToF

  | Encoding '  's in native host order and host endianness .
# INLINE word32Host #
word32Host :: FixedPrim Word32
word32Host = storableToF

# INLINE word64Host #
word64Host :: FixedPrim Word64
word64Host = storableToF



# INLINE int8 #
int8 :: FixedPrim Int8
int8 = fromIntegral >$< word8

# INLINE int16BE #
int16BE :: FixedPrim Int16
int16BE = fromIntegral >$< word16BE

  | Encoding ' Int16 's in little endian format .
# INLINE int16LE #
int16LE :: FixedPrim Int16
int16LE = fromIntegral >$< word16LE

  | Encoding ' Int32 's in big endian format .
# INLINE int32BE #
int32BE :: FixedPrim Int32
int32BE = fromIntegral >$< word32BE

  | Encoding ' Int32 's in little endian format .
# INLINE int32LE #
int32LE :: FixedPrim Int32
int32LE = fromIntegral >$< word32LE

  | Encoding ' Int64 's in big endian format .
# INLINE int64BE #
int64BE :: FixedPrim Int64
int64BE = fromIntegral >$< word64BE

  | Encoding ' Int64 's in little endian format .
# INLINE int64LE #
int64LE :: FixedPrim Int64
int64LE = fromIntegral >$< word64LE



  host endian form , for the machine you are on . On a 64 bit machine the ' Int '
  is an 8 byte value , on a 32 bit machine , 4 bytes . Values encoded this way
# INLINE intHost #
intHost :: FixedPrim Int
intHost = storableToF

# INLINE int16Host #
int16Host :: FixedPrim Int16
int16Host = storableToF

  | Encoding ' Int32 's in native host order and host endianness .
# INLINE int32Host #
int32Host :: FixedPrim Int32
int32Host = storableToF

  | Encoding ' Int64 's in native host order and host endianness .
# INLINE int64Host #
int64Host :: FixedPrim Int64
int64Host = storableToF


# INLINE floatBE #
floatBE :: FixedPrim Float
floatBE = encodeFloatViaWord32F word32BE

  | Encode a ' Float ' in little endian format .
# INLINE floatLE #
floatLE :: FixedPrim Float
floatLE = encodeFloatViaWord32F word32LE

doubleBE :: FixedPrim Double
doubleBE = encodeDoubleViaWord64F word64BE

  | Encode a ' Double ' in little endian format .
# INLINE doubleLE #
doubleLE :: FixedPrim Double
doubleLE = encodeDoubleViaWord64F word64LE


  this way are not portable to different endian machines , without conversion .
# INLINE floatHost #
floatHost :: FixedPrim Float
floatHost = storableToF

# INLINE doubleHost #
doubleHost :: FixedPrim Double
doubleHost = storableToF


