@@ -9,15 +9,24 @@
99-- Stability : experimental
1010-- Portability : GHC
1111--
12−-- The fundamental singleton APIs are 'getChunk' and 'putChunk' and the
13−-- fundamental stream APIs built on top of those are 'readChunksWithBufferOf'
14−-- and 'writeChunks'. Rest of this module is just combinatorial programming
15−-- using these.
12+-- The fundamental singleton IO APIs are 'getChunk' and 'putChunk' and the
13+-- fundamental stream IO APIs built on top of those are
14+-- 'readChunksWithBufferOf' and 'writeChunks'. Rest of this module is just
15+-- combinatorial programming using these.
1616
17+-- TODO: Need a separate module for pread/pwrite based reading writing for
18+-- seekable devices. Stateless read/write can be helpful in multithreaded
19+-- applications.
20+--
1721module Streamly.Internal.FileSystem.Handle
1822 (
19− -- ** Read from Handle
20− read
23+ -- * Singleton APIs
24+ getChunk
25+ , getChunkOf
26+ , putChunk
27+
28+ -- * Byte Stream Read
29+ , read
2130 -- , readUtf8
2231 -- , readLines
2332 -- , readFrames
@@ -26,16 +35,14 @@ module Streamly.Internal.FileSystem.Handle
2635 , toBytes
2736 , toBytesWithBufferOf
2837
29− -- -- * Array Read
30− , getChunk
31− -- , readArrayOf
38+ -- * Chunked Stream Read
3239 , readChunks
3340 , readChunksWithBufferOf
3441
3542 , toChunksWithBufferOf
3643 , toChunks
3744
38− -- ** Write to Handle
45+ -- * Byte Stream Write
3946 -- Byte stream write (Folds)
4047 , write
4148 , write2
@@ -45,25 +52,22 @@ module Streamly.Internal.FileSystem.Handle
4552 -- , writeLines
4653 , writeWithBufferOf
4754
48− -- Byte stream write (Streams)
4955 , putBytes
5056 , putBytesWithBufferOf
5157
52− -- -- * Array Write
53− , putChunk
58+ -- * Chunked Stream Write
5459 , writeChunks
5560 , writeChunksWithBufferOf
5661
57− -- -- * Array stream Write
5862 , putChunksWithBufferOf
5963 , putChunks
6064
61− -- -- * Random Access (Seek)
62− -- -- | Unlike the streaming APIs listed above, these APIs apply to devices or
65+ -- * Random Access (Seek)
66+ -- | Unlike the streaming APIs listed above, these APIs apply to devices or
6367 -- files that have random access or seek capability. This type of devices
6468 -- include disks, files, memory devices and exclude terminals, pipes,
6569 -- sockets and fifos.
66− --
70+
6771 -- We can also generate the request pattern using a funciton.
6872 --
6973 -- , readIndex
@@ -76,7 +80,7 @@ module Streamly.Internal.FileSystem.Handle
7680
7781 -- , readChunksFrom
7882 -- , readChunksFromTo
79− -- , readChunksFromToWith
83+ , readChunksFromToWith
8084 -- , readChunksFromThenToWith
8185
8286 -- , writeIndex
@@ -154,13 +158,16 @@ import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
154158-- Array IO (Input)
155159-------------------------------------------------------------------------------
156160
157−-- | Read a 'ByteArray' from a file handle. If no data is available on the
158−-- handle it blocks until some data becomes available. If data is available
159−-- then it immediately returns that data without blocking. It reads a maximum
160−-- of up to the size requested.
161+-- | Read a 'ByteArray' consisting of one or more bytes from a file handle. If
162+-- no data is available on the handle it blocks until at least one byte becomes
163+-- available. If any data is available then it immediately returns that data
164+-- without blocking. As a result of this behavior, it may read less than or
165+-- equal to the size requested.
166+--
167+-- @since 0.8.1
161168{-# INLINABLE getChunk #-}
162−getChunk :: Int -> Handle -> IO (Array Word8)
163−getChunk size h = do
169+getChunk :: MonadIO m => Int -> Handle -> m (Array Word8)
170+getChunk size h = liftIO $ do
164171 ptr <- mallocPlainForeignPtrBytes size
165172 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
166173 withForeignPtr ptr $ \p -> do
@@ -170,6 +177,18 @@ getChunk size h = do
170177 unsafeFreezeWithShrink $
171178 mutableArray ptr (p `plusPtr` n) (p `plusPtr` size)
172179
180+-- This could be useful in implementing the "reverse" read APIs or if you want
181+-- to read arrays of exact size instead of compacting them later. Compacting
182+-- later requires more copying.
183+--
184+-- | Read a 'ByteArray' consisting of exactly the specified number of bytes
185+-- from a file handle.
186+--
187+-- /Unimplemented/
188+{-# INLINABLE getChunkOf #-}
189+getChunkOf :: Int -> Handle -> IO (Array Word8)
190+getChunkOf = undefined
191+
173192-------------------------------------------------------------------------------
174193-- Stream of Arrays IO
175194-------------------------------------------------------------------------------
@@ -184,7 +203,7 @@ _toChunksWithBufferOf size h = go
184203 where
185204 -- XXX use cons/nil instead
186205 go = mkStream $ \_ yld _ stp -> do
187− arr <- liftIO $ getChunk size h
206+ arr <- getChunk size h
188207 if A.length arr == 0
189208 then stp
190209 else yld arr go
@@ -203,7 +222,7 @@ toChunksWithBufferOf size h = D.fromStreamD (D.Stream step ())
203222 where
204223 {-# INLINE_LATE step #-}
205224 step _ _ = do
206− arr <- liftIO $ getChunk size h
225+ arr <- getChunk size h
207226 return $
208227 case A.length arr of
209228 0 -> D.Stop
@@ -221,12 +240,27 @@ readChunksWithBufferOf = Unfold step return
221240 where
222241 {-# INLINE_LATE step #-}
223242 step (size, h) = do
224− arr <- liftIO $ getChunk size h
243+ arr <- getChunk size h
225244 return $
226245 case A.length arr of
227246 0 -> D.Stop
228247 _ -> D.Yield arr (size, h)
229248
249+-- There are two ways to implement this.
250+--
251+-- 1. Idiomatic: use a scan on the output of readChunksWithBufferOf to total
252+-- the array lengths and trim the last array to correct size.
253+-- 2. Simply implement it from scratch like readChunksWithBufferOf.
254+--
255+-- | The input to the unfold is @(from, to, bufferSize, handle)@. It starts
256+-- reading from the offset `from` in the file and reads up to the offset `to`.
257+--
258+--
259+{-# INLINE_NORMAL readChunksFromToWith #-}
260+readChunksFromToWith :: -- MonadIO m =>
261+ Unfold m (Int, Int, Int, Handle) (Array Word8)
262+readChunksFromToWith = undefined
263+
230264-- XXX read 'Array a' instead of Word8
231265--
232266-- | @toChunks handle@ reads a stream of arrays from the specified file
@@ -316,7 +350,7 @@ toBytes = AS.concat . toChunks
316350
317351-- | Write an 'Array' to a file handle.
318352--
319−-- @since 0.7.0
353+-- @since 0.8.1
320354{-# INLINABLE putChunk #-}
321355putChunk :: (MonadIO m, Storable a) => Handle -> Array a -> m ()
322356putChunk _ arr | A.length arr == 0 = return ()