{-# LANGUAGE CPP #-}

#ifdef USE_MONO_PAT_BINDS
{-# LANGUAGE MonoPatBinds #-}
#endif

-- |
-- Module      : Blaze.ByteString.Builder.Int
-- Copyright   : (c) 2010 Simon Meier
--
-- License     : BSD3-style (see LICENSE)
--
-- Maintainer  : Simon Meier <iridcode@gmail.com>
-- Stability   : experimental
-- Portability : tested on GHC only
--
-- 'Write's and 'Builder's for serializing integers.
--
-- See "Blaze.ByteString.Builder.Word" for information about how to best write several
-- integers at once.
--
module Blaze.ByteString.Builder.Int
    (
    -- * Writing integers to a buffer

      writeInt8

    -- ** Big-endian writes
    , writeInt16be           -- :: Int16 -> Write
    , writeInt32be           -- :: Int32 -> Write
    , writeInt64be           -- :: Int64 -> Write

    -- ** Little-endian writes
    , writeInt16le           -- :: Int16 -> Write
    , writeInt32le           -- :: Int32 -> Write
    , writeInt64le           -- :: Int64 -> Write

    -- ** Host-endian writes
    , writeInthost           -- :: Int -> Write
    , writeInt16host         -- :: Int16 -> Write
    , writeInt32host         -- :: Int32 -> Write
    , writeInt64host         -- :: Int64 -> Write

    -- * Creating builders from integers

    -- | We provide serialization functions both for singleton integers as well as
    -- for lists of integers. Using these list serialization functions is /much/ faster
    -- than using @mconcat . map fromInt/<n/>@, as the list serialization
    -- functions use a tighter inner loop.

    , fromInt8
    , fromInt8s

    -- ** Big-endian serialization
    , fromInt16be            -- :: Int16   -> Builder
    , fromInt32be            -- :: Int32   -> Builder
    , fromInt64be            -- :: Int64   -> Builder
    , fromInt32sbe           -- :: [Int32] -> Builder
    , fromInt16sbe           -- :: [Int16] -> Builder
    , fromInt64sbe           -- :: [Int64] -> Builder

    -- ** Little-endian serialization
    , fromInt16le            -- :: Int16   -> Builder
    , fromInt32le            -- :: Int32   -> Builder
    , fromInt64le            -- :: Int64   -> Builder
    , fromInt16sle           -- :: [Int16] -> Builder
    , fromInt32sle           -- :: [Int32] -> Builder
    , fromInt64sle           -- :: [Int64] -> Builder

    -- ** Host-endian serialization
    , fromInthost            -- :: Int     -> Builder
    , fromInt16host          -- :: Int16   -> Builder
    , fromInt32host          -- :: Int32   -> Builder
    , fromInt64host          -- :: Int64   -> Builder
    , fromIntshost           -- :: [Int]   -> Builder
    , fromInt16shost         -- :: [Int16] -> Builder
    , fromInt32shost         -- :: [Int32] -> Builder
    , fromInt64shost         -- :: [Int64] -> Builder

    ) where

import Blaze.ByteString.Builder.Internal
import Blaze.ByteString.Builder.Word

import Foreign

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


-- | Write a single signed byte.
--
writeInt8 :: Int8 -> Write
writeInt8 = writeWord8 . fromIntegral
{-# INLINE writeInt8 #-}

-- | Write an 'Int16' in big endian format.
writeInt16be :: Int16 -> Write
writeInt16be = writeWord16be . fromIntegral
{-# INLINE writeInt16be #-}

-- | Write an 'Int16' in little endian format.
writeInt16le :: Int16 -> Write
writeInt16le = writeWord16le . fromIntegral
{-# INLINE writeInt16le #-}

-- | Write an 'Int32' in big endian format.
writeInt32be :: Int32 -> Write
writeInt32be = writeWord32be . fromIntegral
{-# INLINE writeInt32be #-}

-- | Write an 'Int32' in little endian format.
writeInt32le :: Int32 -> Write
writeInt32le = writeWord32le . fromIntegral
{-# INLINE writeInt32le #-}

-- | Write an 'Int64' in big endian format.
writeInt64be :: Int64 -> Write
writeInt64be = writeWord64be . fromIntegral
{-# INLINE writeInt64be #-}

-- | Write an 'Int64' in little endian format.
writeInt64le :: Int64 -> Write
writeInt64le = writeWord64le . fromIntegral
{-# INLINE writeInt64le #-}


------------------------------------------------------------------------
-- Unaligned, integer size ops

-- | Write a single native machine 'Int'. The 'Int' 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 integer sized machines, without
-- conversion.
--
writeInthost :: Int -> Write
writeInthost = writeStorable
{-# INLINE writeInthost #-}

-- | Write an 'Int16' in native host order and host endianness.
writeInt16host :: Int16 -> Write
writeInt16host = writeStorable
{-# INLINE writeInt16host #-}

-- | Write an 'Int32' in native host order and host endianness.
writeInt32host :: Int32 -> Write
writeInt32host = writeStorable
{-# INLINE writeInt32host #-}

-- | Write an 'Int64' in native host order and host endianness.
writeInt64host :: Int64 -> Write
writeInt64host = writeStorable
{-# INLINE writeInt64host #-}


------------------------------------------------------------------------------
-- Builders corresponding to the integer writes
------------------------------------------------------------------------------

-- Single bytes
------------------------------------------------------------------------------

-- | Serialize a single byte.
--
fromInt8 :: Int8 -> Builder
fromInt8 = fromWriteSingleton writeInt8

-- | Serialize a list of bytes.
--
fromInt8s :: [Int8] -> Builder
fromInt8s = fromWriteList writeInt8


-- Int16
------------------------------------------------------------------------------

-- | Serialize an 'Int16' in big endian format.
fromInt16be :: Int16 -> Builder
fromInt16be = fromWriteSingleton writeInt16be
{-# INLINE fromInt16be #-}

-- | Serialize a list of 'Int16's in big endian format.
fromInt16sbe :: [Int16] -> Builder
fromInt16sbe = fromWriteList writeInt16be
{-# INLINE fromInt16sbe #-}

-- | Serialize an 'Int16' in little endian format.
fromInt16le :: Int16 -> Builder
fromInt16le = fromWriteSingleton writeInt16le
{-# INLINE fromInt16le #-}

-- | Serialize a list of 'Int16's in little endian format.
fromInt16sle :: [Int16] -> Builder
fromInt16sle = fromWriteList writeInt16le
{-# INLINE fromInt16sle #-}


-- Int32
-----------------------------------------------------------------------------

-- | Serialize an 'Int32' in big endian format.
fromInt32be :: Int32 -> Builder
fromInt32be = fromWriteSingleton writeInt32be
{-# INLINE fromInt32be #-}

-- | Serialize a list of 'Int32's in big endian format.
fromInt32sbe :: [Int32] -> Builder
fromInt32sbe = fromWriteList writeInt32be
{-# INLINE fromInt32sbe #-}

-- | Serialize an 'Int32' in little endian format.
fromInt32le :: Int32 -> Builder
fromInt32le = fromWriteSingleton writeInt32le
{-# INLINE fromInt32le #-}

-- | Serialize a list of 'Int32's in little endian format.
fromInt32sle :: [Int32] -> Builder
fromInt32sle = fromWriteList writeInt32le
{-# INLINE fromInt32sle #-}

-- | Serialize an 'Int64' in big endian format.
fromInt64be :: Int64 -> Builder
fromInt64be = fromWriteSingleton writeInt64be
{-# INLINE fromInt64be #-}

-- | Serialize a list of 'Int64's in big endian format.
fromInt64sbe :: [Int64] -> Builder
fromInt64sbe = fromWriteList writeInt64be
{-# INLINE fromInt64sbe #-}

-- | Serialize an 'Int64' in little endian format.
fromInt64le :: Int64 -> Builder
fromInt64le = fromWriteSingleton writeInt64le
{-# INLINE fromInt64le #-}

-- | Serialize a list of 'Int64's in little endian format.
fromInt64sle :: [Int64] -> Builder
fromInt64sle = fromWriteList writeInt64le
{-# INLINE fromInt64sle #-}


------------------------------------------------------------------------
-- Unaligned, integer size ops

-- | Serialize a single native machine 'Int'. The 'Int' is serialized 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 integer sized machines, without
-- conversion.
--
fromInthost :: Int -> Builder
fromInthost = fromWriteSingleton writeInthost
{-# INLINE fromInthost #-}

-- | Serialize a list of 'Int's.
-- See 'fromInthost' for usage considerations.
fromIntshost :: [Int] -> Builder
fromIntshost = fromWriteList writeInthost
{-# INLINE fromIntshost #-}

-- | Write an 'Int16' in native host order and host endianness.
fromInt16host :: Int16 -> Builder
fromInt16host = fromWriteSingleton writeInt16host
{-# INLINE fromInt16host #-}

-- | Write a list of 'Int16's in native host order and host endianness.
fromInt16shost :: [Int16] -> Builder
fromInt16shost = fromWriteList writeInt16host
{-# INLINE fromInt16shost #-}

-- | Write an 'Int32' in native host order and host endianness.
fromInt32host :: Int32 -> Builder
fromInt32host = fromWriteSingleton writeInt32host
{-# INLINE fromInt32host #-}

-- | Write a list of 'Int32's in native host order and host endianness.
fromInt32shost :: [Int32] -> Builder
fromInt32shost = fromWriteList writeInt32host
{-# INLINE fromInt32shost #-}

-- | Write an 'Int64' in native host order and host endianness.
fromInt64host :: Int64 -> Builder
fromInt64host = fromWriteSingleton writeInt64host
{-# INLINE fromInt64host #-}

-- | Write a list of 'Int64's in native host order and host endianness.
fromInt64shost :: [Int64] -> Builder
fromInt64shost = fromWriteList writeInt64host
{-# INLINE fromInt64shost #-}