{-# LANGUAGE CPP #-}

#if __GLASGOW_HASKELL__ <= 708
{-# LANGUAGE Trustworthy #-}
#else
{-# LANGUAGE Safe #-}
#endif

module System.Log.FastLogger.IO where

import Data.ByteString.Builder.Extra (Next(..))
import qualified Data.ByteString.Builder.Extra as BBE
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Marshal.Alloc (mallocBytes, free)
import Foreign.Ptr (Ptr, plusPtr)

import System.Log.FastLogger.Imports
import System.Log.FastLogger.LogStr

type Buffer = Ptr Word8

-- | The type for buffer size of each core.
type BufSize = Int

-- | The default buffer size (4,096 bytes).
defaultBufSize :: BufSize
defaultBufSize :: BufSize
defaultBufSize = BufSize
4096

getBuffer :: BufSize -> IO Buffer
getBuffer :: BufSize -> IO Buffer
getBuffer = forall a. BufSize -> IO (Ptr a)
mallocBytes

freeBuffer :: Buffer -> IO ()
freeBuffer :: Buffer -> IO ()
freeBuffer = forall a. Ptr a -> IO ()
free

toBufIOWith :: Buffer -> BufSize -> (Buffer -> Int -> IO ()) -> Builder -> IO ()
toBufIOWith :: Buffer
-> BufSize -> (Buffer -> BufSize -> IO ()) -> Builder -> IO ()
toBufIOWith Buffer
buf BufSize
size Buffer -> BufSize -> IO ()
io Builder
builder = BufferWriter -> IO ()
loop forall a b. (a -> b) -> a -> b
$ Builder -> BufferWriter
BBE.runBuilder Builder
builder
  where
    loop :: BufferWriter -> IO ()
loop BufferWriter
writer = do
        (BufSize
len, Next
next) <- BufferWriter
writer Buffer
buf BufSize
size
        Buffer -> BufSize -> IO ()
io Buffer
buf BufSize
len
        case Next
next of
             Next
Done -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
             More BufSize
minSize BufferWriter
writer'
               | BufSize
size forall a. Ord a => a -> a -> Bool
< BufSize
minSize -> forall a. HasCallStack => [Char] -> a
error [Char]
"toBufIOWith: More: minSize"
               | Bool
otherwise      -> BufferWriter -> IO ()
loop BufferWriter
writer'
             Chunk (PS ForeignPtr Word8
fptr BufSize
off BufSize
siz) BufferWriter
writer' ->
               forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fptr forall a b. (a -> b) -> a -> b
$ \Buffer
ptr -> Buffer -> BufSize -> IO ()
io (Buffer
ptr forall a b. Ptr a -> BufSize -> Ptr b
`plusPtr` BufSize
off) BufSize
siz forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferWriter -> IO ()
loop BufferWriter
writer'