module Ptr.Receive.Core
where
import Ptr.Prelude
import qualified Data.ByteString.Internal as A
write :: (Ptr Word8 -> Int -> IO (Either Text Int)) -> ForeignPtr Word8 -> IORef (Int, Int) -> Int -> Int -> Ptr Word8 -> IO (Either Text ())
write fetch bufferFP bufferStateRef chunkSize howMany destination =
do
(offset, end) <- readIORef bufferStateRef
if end == offset
then
fetchMany fetch bufferFP bufferStateRef chunkSize howMany destination
else
withForeignPtr bufferFP $ \bufferPtr ->
let
amountInBuffer = end - offset
in if amountInBuffer >= howMany
then
do
A.memcpy destination (plusPtr bufferPtr offset) howMany
writeIORef bufferStateRef (offset + howMany, end)
return (Right ())
else
do
A.memcpy destination (plusPtr bufferPtr offset) amountInBuffer
fetchMany fetch bufferFP bufferStateRef chunkSize (howMany - amountInBuffer) (plusPtr destination amountInBuffer)
fetchMany :: (Ptr Word8 -> Int -> IO (Either Text Int)) -> ForeignPtr Word8 -> IORef (Int, Int) -> Int -> Int -> Ptr Word8 -> IO (Either Text ())
fetchMany fetch bufferFP bufferStateRef chunkSize remaining destination =
if remaining >= chunkSize
then
fetchingSome destination chunkSize $ \amountFetched ->
if amountFetched == remaining
then
do
writeIORef bufferStateRef (0, 0)
return (Right ())
else
fetchMany fetch bufferFP bufferStateRef chunkSize (remaining - amountFetched) (plusPtr destination amountFetched)
else
withForeignPtr bufferFP $ \bufferPtr ->
fetchingSome bufferPtr chunkSize $ \amountFetched ->
do
A.memcpy destination bufferPtr remaining
writeIORef bufferStateRef (remaining, amountFetched)
return (Right ())
where
fetchingSome destination amount handle =
do
fetchResult <- fetch destination amount
case fetchResult of
Left msg -> return (Left msg)
Right amountFetched ->
if amountFetched == 0
then return (Left "End of input")
else handle amountFetched
peek :: (Ptr Word8 -> Int -> IO (Either Text Int)) -> ForeignPtr Word8 -> IORef (Int, Int) -> Int -> Int -> (Ptr Word8 -> IO peekd) -> IO (Either Text peekd)
peek fetch bufferFP bufferStateRef chunkSize howMany peek =
do
(offset, end) <- readIORef bufferStateRef
let
amountInBuffer = end - offset
in if amountInBuffer >= howMany
then
withForeignPtr bufferFP $ \bufferPtr ->
do
peekd <- peek bufferPtr
writeIORef bufferStateRef (offset + howMany, end)
return (Right peekd)
else
allocaBytes howMany $ \tmpPtr ->
do
writeResult <-
if end == offset
then
fetchMany fetch bufferFP bufferStateRef chunkSize howMany tmpPtr
else
withForeignPtr bufferFP $ \bufferPtr ->
do
A.memcpy tmpPtr (plusPtr bufferPtr offset) amountInBuffer
fetchMany fetch bufferFP bufferStateRef chunkSize (howMany - amountInBuffer) (plusPtr tmpPtr amountInBuffer)
case writeResult of
Right () -> do
peekd <- peek tmpPtr
return (Right peekd)
Left msg -> return (Left msg)