    module Network.Wai.Handler.Warp.Buffer (
        createWriteBuffer,
        allocateBuffer,
        freeBuffer,
        toBuilderBuffer,
        bufferIO,
    ) where

    import Data.IORef (IORef, readIORef)
    import qualified Data.Streaming.ByteString.Builder.Buffer as B (Buffer (..))
    import Foreign.ForeignPtr
    import Foreign.Marshal.Alloc (free, mallocBytes)
    import Foreign.Ptr (plusPtr)
    import Network.Socket.BufferPool

    import Network.Wai.Handler.Warp.Imports
    import Network.Wai.Handler.Warp.Types

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

    -- | Allocate a buffer of the given size and wrap it in a 'WriteBuffer'
    -- containing that size and a finalizer.
    createWriteBuffer :: BufSize -> IO WriteBuffer
    createWriteBuffer :: BufSize -> IO WriteBuffer
    createWriteBuffer BufSize
    size = do
        bytes <- BufSize -> IO Buffer
    allocateBuffer BufSize
    size
        return
            WriteBuffer
                { bufBuffer = bytes
                , bufSize = size
                , bufFree = freeBuffer bytes
                }

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

    -- | Allocating a buffer with malloc().
    allocateBuffer :: Int -> IO Buffer
    allocateBuffer :: BufSize -> IO Buffer
    allocateBuffer = BufSize -> IO Buffer
    forall a. BufSize -> IO (Ptr a)
    mallocBytes

    -- | Releasing a buffer with free().
    freeBuffer :: Buffer -> IO ()
    freeBuffer :: Buffer -> IO ()
    freeBuffer = Buffer -> IO ()
    forall a. Ptr a -> IO ()
    free

    ----------------------------------------------------------------
    --
    -- Utilities
    --

    toBuilderBuffer :: IORef WriteBuffer -> IO B.Buffer
    toBuilderBuffer :: IORef WriteBuffer -> IO Buffer
    toBuilderBuffer IORef WriteBuffer
    writeBufferRef = do
        writeBuffer <- IORef WriteBuffer -> IO WriteBuffer
    forall a. IORef a -> IO a
    readIORef IORef WriteBuffer
    writeBufferRef
        let ptr = WriteBuffer -> Buffer
    bufBuffer WriteBuffer
    writeBuffer
            size = WriteBuffer -> BufSize
    bufSize WriteBuffer
    writeBuffer
        fptr <- newForeignPtr_ ptr
        return $ B.Buffer fptr ptr ptr (ptr `plusPtr` size)

    bufferIO :: Buffer -> Int -> (ByteString -> IO ()) -> IO ()
    bufferIO :: Buffer -> BufSize -> (ByteString -> IO ()) -> IO ()
    bufferIO Buffer
    ptr BufSize
    siz ByteString -> IO ()
    io = do
        fptr <- Buffer -> IO (ForeignPtr Word8)
    forall a. Ptr a -> IO (ForeignPtr a)
    newForeignPtr_ Buffer
    ptr
        io $ PS fptr 0 siz