content: -- | This module provides functionality for working with a streaming request body.
  --
  module Hreq.Conduit.Internal.StreamBody where
  
  import Data.ByteString
  import qualified Data.ByteString as B
  import Data.Conduit (ConduitT, await, ($$+), ($$++))
  import Data.IORef
  import Hreq.Core.API
  import qualified Network.HTTP.Client as HTTP
  
  -- | The conduit type representing a streaming request body.
  type BodyConduit = ConduitT () ByteString IO ()
  
  -- | The Request body Stream is treated as a chucked body stream 'HTTP.RequestBodyStreamChunked'.
  -- Ensure your server supports chucked body stream.
  newtype ReqBodySource = ReqBodySource BodyConduit
  
  -- | For use in API endpoint type definition
  -- >>> type ExampleQuery = "post" :> ConduitReqBody :> RawResponse POST
  --
  type ConduitReqBody = StreamBody OctetStream ReqBodySource
  
  instance HasStreamBody ReqBodySource where
    givePopper (ReqBodySource src)= GivesPooper $ srcToPopperIO src
  
  -- * Helpers
  
  -- | This is taken from "Network.HTTP.Client.Conduit" without modifications.
  srcToPopperIO :: BodyConduit -> HTTP.GivesPopper ()
  srcToPopperIO src f = do
    (rsrc0, ()) <- src $$+ return ()
    irsrc <- newIORef rsrc0
    let popper :: IO ByteString
        popper = do
          rsrc <- readIORef irsrc
          (rsrc', mres) <- rsrc $$++ await
          writeIORef irsrc rsrc'
          case mres of
            Nothing -> return B.empty
            Just bs
                | B.null bs -> popper
                | otherwise -> return bs
    f popper
  
  -- $setup
  -- >>> import Hreq.Core.API
  -- >>> import Hreq.Conduit.Internal.StreamBody
  