module Ptr.Receive
  ( Receive,
    create,
    peek,
  )
where

import qualified Ptr.Peek as B
import Ptr.Prelude hiding (peek)
import qualified Ptr.Receive.Core as A

-- |
-- A wrapper of a receiving action, which extends it with bufferization.
data Receive
  = -- |
    --  * Exception-free action to receive another chunk of bytes. E.g., an exception-free wrapper of @Network.Socket.recvBuf@
    --  * Buffer
    --  * Size of the buffer
    --  * Chunk size
    Receive !(Ptr Word8 -> Int -> IO (Either Text Int)) !(ForeignPtr Word8) !(IORef (Int, Int)) !Int

create :: (Ptr Word8 -> Int -> IO (Either Text Int)) -> Int -> IO Receive
create :: (Ptr Word8 -> Int -> IO (Either Text Int)) -> Int -> IO Receive
create Ptr Word8 -> Int -> IO (Either Text Int)
fetch Int
chunkSize =
  do
    ForeignPtr Word8
bufferFP <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes Int
chunkSize
    IORef (Int, Int)
bufferStateRef <- (Int, Int) -> IO (IORef (Int, Int))
forall a. a -> IO (IORef a)
newIORef (Int
0, Int
0)
    Receive -> IO Receive
forall (m :: * -> *) a. Monad m => a -> m a
return ((Ptr Word8 -> Int -> IO (Either Text Int))
-> ForeignPtr Word8 -> IORef (Int, Int) -> Int -> Receive
Receive Ptr Word8 -> Int -> IO (Either Text Int)
fetch ForeignPtr Word8
bufferFP IORef (Int, Int)
bufferStateRef Int
chunkSize)

-- |
-- Receive as many bytes as is required by the provided decoder and decode immediately.
--
-- If all you need is just to get a 'ByteString' chunk then use the 'B.bytes' decoder.
peek :: Receive -> B.Peek peekd -> IO (Either Text peekd)
peek :: Receive -> Peek peekd -> IO (Either Text peekd)
peek (Receive Ptr Word8 -> Int -> IO (Either Text Int)
fetch ForeignPtr Word8
bufferFP IORef (Int, Int)
bufferStateRef Int
chunkSize) (B.Peek Int
amount Ptr Word8 -> IO peekd
action) =
  (Ptr Word8 -> Int -> IO (Either Text Int))
-> ForeignPtr Word8
-> IORef (Int, Int)
-> Int
-> Int
-> (Ptr Word8 -> IO peekd)
-> IO (Either Text peekd)
forall peekd.
(Ptr Word8 -> Int -> IO (Either Text Int))
-> ForeignPtr Word8
-> IORef (Int, Int)
-> Int
-> Int
-> (Ptr Word8 -> IO peekd)
-> IO (Either Text peekd)
A.peek Ptr Word8 -> Int -> IO (Either Text Int)
fetch ForeignPtr Word8
bufferFP IORef (Int, Int)
bufferStateRef Int
chunkSize Int
amount Ptr Word8 -> IO peekd
action