{-# 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 (free, mallocBytes)
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 = BufSize -> IO Buffer
forall a. BufSize -> IO (Ptr a)
mallocBytes

freeBuffer :: Buffer -> IO ()
freeBuffer :: Buffer -> IO ()
freeBuffer = Buffer -> IO ()
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 (BufferWriter -> IO ()) -> BufferWriter -> IO ()
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 -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
            More BufSize
minSize BufferWriter
writer'
                | BufSize
size BufSize -> BufSize -> Bool
forall a. Ord a => a -> a -> Bool
< BufSize
minSize -> [Char] -> IO ()
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' ->
                ForeignPtr Word8 -> (Buffer -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
fptr ((Buffer -> IO ()) -> IO ()) -> (Buffer -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Buffer
ptr -> Buffer -> BufSize -> IO ()
io (Buffer
ptr Buffer -> BufSize -> Buffer
forall a b. Ptr a -> BufSize -> Ptr b
`plusPtr` BufSize
off) BufSize
siz IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferWriter -> IO ()
loop BufferWriter
writer'