------------------------------------------------------------------------------
-- |
-- Module:      Blaze.ByteString.Builder.ByteString
-- Copyright:   (c) 2013 Leon P Smith
-- License:     BSD3
-- Maintainer:  Leon P Smith <leon@melding-monads.com>
-- Stability:   experimental
--
-- 'Write's and 'B.Builder's for strict and lazy bytestrings.
--
-- We assume the following qualified imports in order to differentiate between
-- strict and lazy bytestrings in the code examples.
--
-- > import qualified Data.ByteString      as S
-- > import qualified Data.ByteString.Lazy as L
--
------------------------------------------------------------------------------

module Blaze.ByteString.Builder.ByteString
    (
    -- * Strict bytestrings
      writeByteString
    , fromByteString
    , fromByteStringWith
    , copyByteString
    , insertByteString

    -- * Lazy bytestrings
    , fromLazyByteString
    , fromLazyByteStringWith
    , copyLazyByteString
    , insertLazyByteString

    ) where


import Blaze.ByteString.Builder.Internal.Write ( Write, exactWrite )
import Foreign
import qualified Data.ByteString.Builder       as B
import qualified Data.ByteString.Builder.Extra as B
import qualified Data.ByteString               as S
import qualified Data.ByteString.Internal      as S
import qualified Data.ByteString.Lazy          as L


-- | Write a strict 'S.ByteString' to a buffer.
writeByteString :: S.ByteString -> Write
writeByteString :: ByteString -> Write
writeByteString ByteString
bs = Int -> (Ptr Word8 -> IO ()) -> Write
exactWrite Int
l Ptr Word8 -> IO ()
forall a. Ptr a -> IO ()
io
  where
  (ForeignPtr Word8
fptr, Int
o, Int
l) = ByteString -> (ForeignPtr Word8, Int, Int)
S.toForeignPtr ByteString
bs
  io :: Ptr a -> IO ()
io Ptr a
pf = ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fptr ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> Ptr a -> Ptr a -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytes Ptr a
pf (Ptr Word8
p Ptr Word8 -> Int -> Ptr a
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
o) Int
l
{-# INLINE writeByteString #-}

-- | Create a 'B.Builder' denoting the same sequence of bytes as a strict
-- 'S.ByteString'.
-- The 'B.Builder' inserts large 'S.ByteString's directly, but copies small ones
-- to ensure that the generated chunks are large on average.
fromByteString :: S.ByteString -> B.Builder
fromByteString :: ByteString -> Builder
fromByteString = ByteString -> Builder
B.byteString
{-# INLINE fromByteString #-}


-- | Construct a 'B.Builder' that copies the strict 'S.ByteString's, if it is
-- smaller than the treshold, and inserts it directly otherwise.
--
-- For example, @fromByteStringWith 1024@ copies strict 'S.ByteString's whose size
-- is less or equal to 1kb, and inserts them directly otherwise. This implies
-- that the average chunk-size of the generated lazy 'L.ByteString' may be as
-- low as 513 bytes, as there could always be just a single byte between the
-- directly inserted 1025 byte, strict 'S.ByteString's.
--
fromByteStringWith :: Int          -- ^ Maximal number of bytes to copy.
                   -> S.ByteString -- ^ Strict 'S.ByteString' to serialize.
                   -> B.Builder    -- ^ Resulting 'B.Builder'.
fromByteStringWith :: Int -> ByteString -> Builder
fromByteStringWith = Int -> ByteString -> Builder
B.byteStringThreshold
{-# INLINE fromByteStringWith #-}

-- | Construct a 'B.Builder' that copies the strict 'S.ByteString'.
--
-- Use this function to create 'B.Builder's from smallish (@<= 4kb@)
-- 'S.ByteString's or if you need to guarantee that the 'S.ByteString' is not
-- shared with the chunks generated by the 'B.Builder'.
--
copyByteString :: S.ByteString -> B.Builder
copyByteString :: ByteString -> Builder
copyByteString = ByteString -> Builder
B.byteStringCopy
{-# INLINE copyByteString #-}

-- | Construct a 'B.Builder' that always inserts the strict 'S.ByteString'
-- directly as a chunk.
--
-- This implies flushing the output buffer, even if it contains just
-- a single byte. You should therefore use 'insertByteString' only for large
-- (@> 8kb@) 'S.ByteString's. Otherwise, the generated chunks are too
-- fragmented to be processed efficiently afterwards.
--
insertByteString :: S.ByteString -> B.Builder
insertByteString :: ByteString -> Builder
insertByteString = ByteString -> Builder
B.byteStringInsert
{-# INLINE insertByteString #-}

-- | Create a 'B.Builder' denoting the same sequence of bytes as a lazy
-- 'S.ByteString'.
-- The 'B.Builder' inserts large chunks of the lazy 'L.ByteString' directly,
-- but copies small ones to ensure that the generated chunks are large on
-- average.
--
fromLazyByteString :: L.ByteString -> B.Builder
fromLazyByteString :: ByteString -> Builder
fromLazyByteString = ByteString -> Builder
B.lazyByteString
{-# INLINE fromLazyByteString #-}

-- | Construct a 'B.Builder' that uses the thresholding strategy of 'fromByteStringWith'
-- for each chunk of the lazy 'L.ByteString'.
--
fromLazyByteStringWith :: Int -> L.ByteString -> B.Builder
fromLazyByteStringWith :: Int -> ByteString -> Builder
fromLazyByteStringWith = Int -> ByteString -> Builder
B.lazyByteStringThreshold
{-# INLINE fromLazyByteStringWith #-}

-- | Construct a 'B.Builder' that copies the lazy 'L.ByteString'.
--
copyLazyByteString :: L.ByteString -> B.Builder
copyLazyByteString :: ByteString -> Builder
copyLazyByteString = ByteString -> Builder
B.lazyByteStringCopy
{-# INLINE copyLazyByteString #-}

-- | Construct a 'B.Builder' that inserts all chunks of the lazy 'L.ByteString'
-- directly.
--
insertLazyByteString :: L.ByteString -> B.Builder
insertLazyByteString :: ByteString -> Builder
insertLazyByteString = ByteString -> Builder
B.lazyByteStringInsert
{-# INLINE insertLazyByteString #-}