    {-# LANGUAGE CPP, MagicHash #-}
    #if __GLASGOW_HASKELL__ >= 701
    {-# LANGUAGE Safe #-}
    #endif

    -----------------------------------------------------------------------------
    -- |
    -- Module      : Data.Binary.Builder
    -- Copyright   : Lennart Kolmodin, Ross Paterson
    -- License     : BSD3-style (see LICENSE)
    --
    -- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
    -- Stability   : experimental
    -- Portability : portable to Hugs and GHC
    --
    -- Efficient constructions of lazy bytestrings.
    --
    -- This now re-exports 'Data.ByteString.Lazy.Builder'.
    --
    -----------------------------------------------------------------------------

    module Data.Binary.Builder (
        -- * The Builder type
          Builder
        , toLazyByteString

        -- * Constructing Builders
        , empty
        , singleton
        , append
        , fromByteString        -- :: S.ByteString -> Builder
        , fromLazyByteString    -- :: L.ByteString -> Builder
    #if MIN_VERSION_bytestring(0,10,4)
        , fromShortByteString   -- :: T.ByteString -> Builder
    #endif
        -- * Flushing the buffer state
        , flush

        -- * Derived Builders
        -- ** Big-endian writes
        , putWord16be           -- :: Word16 -> Builder
        , putWord32be           -- :: Word32 -> Builder
        , putWord64be           -- :: Word64 -> Builder
        , putInt16be            -- :: Int16 -> Builder
        , putInt32be            -- :: Int32 -> Builder
        , putInt64be            -- :: Int64 -> Builder

        -- ** Little-endian writes
        , putWord16le           -- :: Word16 -> Builder
        , putWord32le           -- :: Word32 -> Builder
        , putWord64le           -- :: Word64 -> Builder
        , putInt16le            -- :: Int16 -> Builder
        , putInt32le            -- :: Int32 -> Builder
        , putInt64le            -- :: Int64 -> Builder

        -- ** Host-endian, unaligned writes
        , putWordhost           -- :: Word -> Builder
        , putWord16host         -- :: Word16 -> Builder
        , putWord32host         -- :: Word32 -> Builder
        , putWord64host         -- :: Word64 -> Builder
        , putInthost            -- :: Int -> Builder
        , putInt16host          -- :: Int16 -> Builder
        , putInt32host          -- :: Int32 -> Builder
        , putInt64host          -- :: Int64 -> Builder

          -- ** Unicode
        , putCharUtf8
        , putStringUtf8
        ) where

    import qualified Data.ByteString      as S
    import qualified Data.ByteString.Lazy as L
    import qualified Data.ByteString.Short as T
    import qualified Data.ByteString.Builder as B
    import qualified Data.ByteString.Builder.Prim as Prim
    import Data.ByteString.Builder ( Builder, toLazyByteString )
    import Data.ByteString.Builder.Extra ( flush )
    import Data.Monoid
    import Data.Word
    import Data.Int
    import Prelude -- Silence AMP warning.

    ------------------------------------------------------------------------

    -- | /O(1)./ The empty Builder, satisfying
    --
    --  * @'toLazyByteString' 'empty' = 'L.empty'@
    --
    empty :: Builder
    empty = mempty
    {-# INLINE empty #-}

    -- | /O(1)./ A Builder taking a single byte, satisfying
    --
    --  * @'toLazyByteString' ('singleton' b) = 'L.singleton' b@
    --
    singleton :: Word8 -> Builder
    singleton = B.word8
    {-# INLINE singleton #-}

    ------------------------------------------------------------------------

    -- | /O(1)./ The concatenation of two Builders, an associative operation
    -- with identity 'empty', satisfying
    --
    --  * @'toLazyByteString' ('append' x y) = 'L.append' ('toLazyByteString' x) ('toLazyByteString' y)@
    --
    append :: Builder -> Builder -> Builder
    append = mappend
    {-# INLINE append #-}

    -- | /O(1)./ A Builder taking a 'S.ByteString', satisfying
    --
    --  * @'toLazyByteString' ('fromByteString' bs) = 'L.fromChunks' [bs]@
    --
    fromByteString :: S.ByteString -> Builder
    fromByteString = B.byteString
    {-# INLINE fromByteString #-}

    -- | /O(1)./ A Builder taking a lazy 'L.ByteString', satisfying
    --
    --  * @'toLazyByteString' ('fromLazyByteString' bs) = bs@
    --
    fromLazyByteString :: L.ByteString -> Builder
    fromLazyByteString = B.lazyByteString
    {-# INLINE fromLazyByteString #-}

    #if MIN_VERSION_bytestring(0,10,4)
    -- | /O(n)./ A builder taking 'T.ShortByteString' and copy it to a Builder,
    -- satisfying
    --
    -- * @'toLazyByteString' ('fromShortByteString' bs) = 'L.fromChunks' ['T.fromShort' bs]
    fromShortByteString :: T.ShortByteString -> Builder
    fromShortByteString = B.shortByteString
    {-# INLINE fromShortByteString #-}
    #endif

    ------------------------------------------------------------------------

    -- | Write a Word16 in big endian format
    putWord16be :: Word16 -> Builder
    putWord16be = B.word16BE
    {-# INLINE putWord16be #-}

    -- | Write a Word16 in little endian format
    putWord16le :: Word16 -> Builder
    putWord16le = B.word16LE
    {-# INLINE putWord16le #-}

    -- | Write a Word32 in big endian format
    putWord32be :: Word32 -> Builder
    putWord32be = B.word32BE
    {-# INLINE putWord32be #-}

    -- | Write a Word32 in little endian format
    putWord32le :: Word32 -> Builder
    putWord32le = B.word32LE
    {-# INLINE putWord32le #-}

    -- | Write a Word64 in big endian format
    putWord64be :: Word64 -> Builder
    putWord64be = B.word64BE
    {-# INLINE putWord64be #-}

    -- | Write a Word64 in little endian format
    putWord64le :: Word64 -> Builder
    putWord64le = B.word64LE
    {-# INLINE putWord64le #-}

    -- | Write a Int16 in big endian format
    putInt16be :: Int16 -> Builder
    putInt16be = B.int16BE
    {-# INLINE putInt16be #-}

    -- | Write a Int16 in little endian format
    putInt16le :: Int16 -> Builder
    putInt16le = B.int16LE
    {-# INLINE putInt16le #-}

    -- | Write a Int32 in big endian format
    putInt32be :: Int32 -> Builder
    putInt32be = B.int32BE
    {-# INLINE putInt32be #-}

    -- | Write a Int32 in little endian format
    putInt32le :: Int32 -> Builder
    putInt32le = B.int32LE
    {-# INLINE putInt32le #-}

    -- | Write a Int64 in big endian format
    putInt64be :: Int64 -> Builder
    putInt64be = B.int64BE

    -- | Write a Int64 in little endian format
    putInt64le :: Int64 -> Builder
    putInt64le = B.int64LE

    ------------------------------------------------------------------------
    -- Unaligned, word size ops

    -- | /O(1)./ A Builder taking a single native machine word. The word is
    -- written in host order, host endian form, for the machine you're on.
    -- On a 64 bit machine the Word is an 8 byte value, on a 32 bit machine,
    -- 4 bytes. Values written this way are not portable to
    -- different endian or word sized machines, without conversion.
    --
    putWordhost :: Word -> Builder
    putWordhost = Prim.primFixed Prim.wordHost
    {-# INLINE putWordhost #-}

    -- | Write a Word16 in native host order and host endianness.
    -- 2 bytes will be written, unaligned.
    putWord16host :: Word16 -> Builder
    putWord16host = Prim.primFixed Prim.word16Host
    {-# INLINE putWord16host #-}

    -- | Write a Word32 in native host order and host endianness.
    -- 4 bytes will be written, unaligned.
    putWord32host :: Word32 -> Builder
    putWord32host = Prim.primFixed Prim.word32Host
    {-# INLINE putWord32host #-}

    -- | Write a Word64 in native host order.
    -- On a 32 bit machine we write two host order Word32s, in big endian form.
    -- 8 bytes will be written, unaligned.
    putWord64host :: Word64 -> Builder
    putWord64host = Prim.primFixed Prim.word64Host
    {-# INLINE putWord64host #-}

    -- | /O(1)./ A Builder taking a single native machine word. The word is
    -- written in host order, host endian form, for the machine you're on.
    -- On a 64 bit machine the Int is an 8 byte value, on a 32 bit machine,
    -- 4 bytes. Values written this way are not portable to
    -- different endian or word sized machines, without conversion.
    --
    putInthost :: Int -> Builder
    putInthost = Prim.primFixed Prim.intHost
    {-# INLINE putInthost #-}

    -- | Write a Int16 in native host order and host endianness.
    -- 2 bytes will be written, unaligned.
    putInt16host :: Int16 -> Builder
    putInt16host = Prim.primFixed Prim.int16Host
    {-# INLINE putInt16host #-}

    -- | Write a Int32 in native host order and host endianness.
    -- 4 bytes will be written, unaligned.
    putInt32host :: Int32 -> Builder
    putInt32host = Prim.primFixed Prim.int32Host
    {-# INLINE putInt32host #-}

    -- | Write a Int64 in native host order.
    -- On a 32 bit machine we write two host order Int32s, in big endian form.
    -- 8 bytes will be written, unaligned.
    putInt64host :: Int64 -> Builder
    putInt64host = Prim.primFixed Prim.int64Host
    {-# INLINE putInt64host #-}

    ------------------------------------------------------------------------
    -- Unicode

    -- | Write a character using UTF-8 encoding.
    putCharUtf8 :: Char -> Builder
    putCharUtf8 = Prim.primBounded Prim.charUtf8
    {-# INLINE putCharUtf8 #-}

    -- | Write a String using UTF-8 encoding.
    putStringUtf8 :: String -> Builder
    putStringUtf8 = Prim.primMapListBounded Prim.charUtf8
    {-# INLINE putStringUtf8 #-}