1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE GADTs #-}
4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE ViewPatterns #-}
7
8-- |
9-- Module : Streaming.ByteString
10-- Copyright : (c) Don Stewart 2006
11-- (c) Duncan Coutts 2006-2011
12-- (c) Michael Thompson 2015
13-- License : BSD-style
14--
15-- Maintainer : what_is_it_to_do_anything@yahoo.com
16-- Stability : experimental
17-- Portability : portable
18--
19-- See the simple examples of use <https://gist.github.com/michaelt/6c6843e6dd8030e95d58 here>
20-- and the @ghci@ examples especially in "Streaming.ByteString.Char8".
21-- We begin with a slight modification of the documentation to "Data.ByteString.Lazy":
22--
23-- A time and space-efficient implementation of effectful byte streams using a
24-- stream of packed 'Word8' arrays, suitable for high performance use, both in
25-- terms of large data quantities, or high speed requirements. Streaming
26-- ByteStrings are encoded as streams of strict chunks of bytes.
27--
28-- A key feature of streaming ByteStrings is the means to manipulate large or
29-- unbounded streams of data without requiring the entire sequence to be
30-- resident in memory. To take advantage of this you have to write your
31-- functions in a streaming style, e.g. classic pipeline composition. The
32-- default I\/O chunk size is 32k, which should be good in most circumstances.
33--
34-- Some operations, such as 'concat', 'append', and 'cons', have better
35-- complexity than their "Data.ByteString" equivalents, due to optimisations
36-- resulting from the list spine structure. For other operations streaming, like
37-- lazy, ByteStrings are usually within a few percent of strict ones.
38--
39-- This module is intended to be imported @qualified@, to avoid name clashes
40-- with "Prelude" functions. eg.
41--
42-- > import qualified Streaming.ByteString as Q
43--
44-- Original GHC implementation by Bryan O\'Sullivan. Rewritten to use
45-- 'Data.Array.Unboxed.UArray' by Simon Marlow. Rewritten to support slices and
46-- use 'Foreign.ForeignPtr.ForeignPtr' by David Roundy. Rewritten again and
47-- extended by Don Stewart and Duncan Coutts. Lazy variant by Duncan Coutts and
48-- Don Stewart. Streaming variant by Michael Thompson, following the ideas of
49-- Gabriel Gonzales' pipes-bytestring.
50module Streaming.ByteString
51 ( -- * The @ByteStream@ type
52 ByteStream
53 , ByteString
54
55 -- * Introducing and eliminating 'ByteStream's
56 , empty
57 , singleton
58 , pack
59 , unpack
60 , fromLazy
61 , toLazy
62 , toLazy_
63 , fromChunks
64 , toChunks
65 , fromStrict
66 , toStrict
67 , toStrict_
68 , effects
69 , copy
70 , drained
71 , mwrap
72
73 -- * Transforming ByteStreams
74 , map
75 , for
76 , intercalate
77 , intersperse
78
79 -- * Basic interface
80 , cons
81 , cons'
82 , snoc
83 , append
84 , filter
85 , uncons
86 , nextByte
87
88 -- * Substrings
89 -- ** Breaking strings
90 , break
91 , drop
92 , dropWhile
93 , group
94 , groupBy
95 , span
96 , splitAt
97 , splitWith
98 , take
99 , takeWhile
100
101 -- ** Breaking into many substrings
102 , split
103
104 -- ** Special folds
105 , concat
106 , denull
107
108 -- * Builders
109 , toStreamingByteString
110
111 , toStreamingByteStringWith
112
113 , toBuilder
114 , concatBuilders
115
116 -- * Building ByteStreams
117 -- ** Infinite ByteStreams
118 , repeat
119 , iterate
120 , cycle
121
122 -- ** Unfolding ByteStreams
123 , unfoldM
124 , unfoldr
125 , reread
126
127 -- * Folds, including support for `Control.Foldl`
128 , foldr
129 , fold
130 , fold_
131 , head
132 , head_
133 , last
134 , last_
135 , length
136 , length_
137 , null
138 , null_
139 , nulls
140 , testNull
141 , count
142 , count_
143
144 -- * I\/O with 'ByteStream's
145 -- ** Standard input and output
146 , getContents
147 , stdin
148 , stdout
149 , interact
150
151 -- ** Files
152 , readFile
153 , writeFile
154 , appendFile
155
156 -- ** I\/O with Handles
157 , fromHandle
158 , toHandle
159 , hGet
160 , hGetContents
161 , hGetContentsN
162 , hGetN
163 , hGetNonBlocking
164 , hGetNonBlockingN
165 , hPut
166 -- , hPutNonBlocking
167
168 -- * Simple chunkwise operations
169 , unconsChunk
170 , nextChunk
171 , chunk
172 , foldrChunks
173 , foldlChunks
174 , chunkFold
175 , chunkFoldM
176 , chunkMap
177 , chunkMapM
178 , chunkMapM_
179
180 -- * Etc.
181 , dematerialize
182 , materialize
183 , distribute
184 , zipWithStream
185 ) where
186
187import Prelude hiding
188 (all, any, appendFile, break, concat, concatMap, cycle, drop, dropWhile,
189 elem, filter, foldl, foldl1, foldr, foldr1, getContents, getLine, head,
190 init, interact, iterate, last, length, lines, map, maximum, minimum,
191 notElem, null, putStr, putStrLn, readFile, repeat, replicate, reverse,
192 scanl, scanl1, scanr, scanr1, span, splitAt, tail, take, takeWhile,
193 unlines, unzip, writeFile, zip, zipWith)
194
195import qualified Data.ByteString as P (ByteString)
196import qualified Data.ByteString as B
197import Data.ByteString.Builder.Internal hiding
198 (append, defaultChunkSize, empty, hPut)
199import qualified Data.ByteString.Internal as B
200import qualified Data.ByteString.Lazy.Internal as BI
201import qualified Data.ByteString.Unsafe as B
202
203import Streaming hiding (concats, distribute, unfold)
204import Streaming.ByteString.Internal
205import Streaming.Internal (Stream(..))
206import qualified Streaming.Prelude as SP
207
208import Control.Monad (forever)
209import Control.Monad.Trans.Resource
210import Data.Int (Int64)
211import qualified Data.List as L
212import Data.Word (Word8)
213import Foreign.Ptr
214import Foreign.Storable
215import System.IO (Handle, IOMode(..), hClose, openBinaryFile)
216import qualified System.IO as IO (stdin, stdout)
217import System.IO.Error (illegalOperationErrorType, mkIOError)
218
219-- | /O(n)/ Concatenate a stream of byte streams.
220concat :: Monad m => Stream (ByteStream m) m r -> ByteStream m r
221concat x = destroy x join Go Empty
222{-# INLINE concat #-}
223
224-- | Given a byte stream on a transformed monad, make it possible to \'run\'
225-- transformer.
226distribute
227 :: (Monad m, MonadTrans t, MFunctor t, Monad (t m), Monad (t (ByteStream m)))
228 => ByteStream (t m) a -> t (ByteStream m) a
229distribute ls = dematerialize ls
230 return
231 (\bs x -> join $ lift $ Chunk bs (Empty x) )
232 (join . hoist (Go . fmap Empty))
233{-# INLINE distribute #-}
234
235-- | Perform the effects contained in an effectful bytestring, ignoring the bytes.
236effects :: Monad m => ByteStream m r -> m r
237effects bs = case bs of
238 Empty r -> return r
239 Go m -> m >>= effects
240 Chunk _ rest -> effects rest
241{-# INLINABLE effects #-}
242
243-- | Perform the effects contained in the second in an effectful pair of
244-- bytestrings, ignoring the bytes. It would typically be used at the type
245--
246-- > ByteStream m (ByteStream m r) -> ByteStream m r
247drained :: (Monad m, MonadTrans t, Monad (t m)) => t m (ByteStream m r) -> t m r
248drained t = t >>= lift . effects
249
250-- -----------------------------------------------------------------------------
251-- Introducing and eliminating 'ByteStream's
252
253-- | /O(1)/ The empty 'ByteStream' -- i.e. @return ()@ Note that @ByteStream m w@ is
254-- generally a monoid for monoidal values of @w@, like @()@.
255empty :: ByteStream m ()
256empty = Empty ()
257{-# INLINE empty #-}
258
259-- | /O(1)/ Yield a 'Word8' as a minimal 'ByteStream'.
260singleton :: Monad m => Word8 -> ByteStream m ()
261singleton w = Chunk (B.singleton w) (Empty ())
262{-# INLINE singleton #-}
263
264-- | /O(n)/ Convert a monadic stream of individual 'Word8's into a packed byte stream.
265pack :: Monad m => Stream (Of Word8) m r -> ByteStream m r
266pack = packBytes
267{-# INLINE pack #-}
268
269-- | /O(n)/ Converts a packed byte stream into a stream of individual bytes.
270unpack :: Monad m => ByteStream m r -> Stream (Of Word8) m r
271unpack = unpackBytes
272
273-- | /O(c)/ Convert a monadic stream of individual strict 'ByteString' chunks
274-- into a byte stream.
275fromChunks :: Monad m => Stream (Of P.ByteString) m r -> ByteStream m r
276fromChunks cs = destroy cs (\(bs :> rest) -> Chunk bs rest) Go return
277{-# INLINE fromChunks #-}
278
279-- | /O(c)/ Convert a byte stream into a stream of individual strict
280-- bytestrings. This of course exposes the internal chunk structure.
281toChunks :: Monad m => ByteStream m r -> Stream (Of P.ByteString) m r
282toChunks bs = dematerialize bs return (\b mx -> Step (b:> mx)) Effect
283{-# INLINE toChunks #-}
284
285-- | /O(1)/ Yield a strict 'ByteString' chunk.
286fromStrict :: P.ByteString -> ByteStream m ()
287fromStrict bs | B.null bs = Empty ()
288 | otherwise = Chunk bs (Empty ())
289{-# INLINE fromStrict #-}
290
291-- | /O(n)/ Convert a byte stream into a single strict 'ByteString'.
292--
293-- Note that this is an /expensive/ operation that forces the whole monadic
294-- ByteString into memory and then copies all the data. If possible, try to
295-- avoid converting back and forth between streaming and strict bytestrings.
296toStrict_ :: Monad m => ByteStream m r -> m B.ByteString
297#if MIN_VERSION_streaming (0,2,2)
298toStrict_ = fmap B.concat . SP.toList_ . toChunks
299#else
300toStrict_ = fmap B.concat . SP.toList_ . void . toChunks
301#endif
302{-# INLINE toStrict_ #-}
303
304-- | /O(n)/ Convert a monadic byte stream into a single strict 'ByteString',
305-- retaining the return value of the original pair. This operation is for use
306-- with 'mapped'.
307--
308-- > mapped R.toStrict :: Monad m => Stream (ByteStream m) m r -> Stream (Of ByteString) m r
309--
310-- It is subject to all the objections one makes to Data.ByteString.Lazy
311-- 'toStrict'; all of these are devastating.
312toStrict :: Monad m => ByteStream m r -> m (Of B.ByteString r)
313toStrict bs = do
314 (bss :> r) <- SP.toList (toChunks bs)
315 return (B.concat bss :> r)
316{-# INLINE toStrict #-}
317
318-- |/O(c)/ Transmute a pseudo-pure lazy bytestring to its representation as a
319-- monadic stream of chunks.
320--
321-- >>> Q.putStrLn $ Q.fromLazy "hi"
322-- hi
323-- >>> Q.fromLazy "hi"
324-- Chunk "hi" (Empty (())) -- note: a 'show' instance works in the identity monad
325-- >>> Q.fromLazy $ BL.fromChunks ["here", "are", "some", "chunks"]
326-- Chunk "here" (Chunk "are" (Chunk "some" (Chunk "chunks" (Empty (())))))
327fromLazy :: Monad m => BI.ByteString -> ByteStream m ()
328fromLazy = BI.foldrChunks Chunk (Empty ())
329{-# INLINE fromLazy #-}
330
331-- | /O(n)/ Convert an effectful byte stream into a single lazy 'ByteStream'
332-- with the same internal chunk structure. See `toLazy` which preserve
333-- connectedness by keeping the return value of the effectful bytestring.
334toLazy_ :: Monad m => ByteStream m r -> m BI.ByteString
335toLazy_ bs = dematerialize bs (\_ -> return BI.Empty) (fmap . BI.Chunk) join
336{-# INLINE toLazy_ #-}
337
338-- | /O(n)/ Convert an effectful byte stream into a single lazy 'ByteString'
339-- with the same internal chunk structure, retaining the original return value.
340--
341-- This is the canonical way of breaking streaming (`toStrict` and the like are
342-- far more demonic). Essentially one is dividing the interleaved layers of
343-- effects and bytes into one immense layer of effects, followed by the memory
344-- of the succession of bytes.
345--
346-- Because one preserves the return value, `toLazy` is a suitable argument for
347-- 'Streaming.mapped':
348--
349-- > S.mapped Q.toLazy :: Stream (ByteStream m) m r -> Stream (Of L.ByteString) m r
350--
351-- >>> Q.toLazy "hello"
352-- "hello" :> ()
353-- >>> S.toListM $ traverses Q.toLazy $ Q.lines "one\ntwo\nthree\nfour\nfive\n"
354-- ["one","two","three","four","five",""] -- [L.ByteString]
355toLazy :: Monad m => ByteStream m r -> m (Of BI.ByteString r)
356toLazy bs0 = dematerialize bs0
357 (\r -> return (BI.Empty :> r))
358 (\b mx -> do
359 (bs :> x) <- mx
360 return $ BI.Chunk b bs :> x
361 )
362 join
363{-# INLINE toLazy #-}
364
365-- ---------------------------------------------------------------------
366-- Basic interface
367--
368
369-- | Test whether a `ByteStream` is empty, collecting its return value; to reach
370-- the return value, this operation must check the whole length of the string.
371--
372-- >>> Q.null "one\ntwo\three\nfour\nfive\n"
373-- False :> ()
374-- >>> Q.null ""
375-- True :> ()
376-- >>> S.print $ mapped R.null $ Q.lines "yours,\nMeredith"
377-- False
378-- False
379--
380-- Suitable for use with `SP.mapped`:
381--
382-- @
383-- S.mapped Q.null :: Streaming (ByteStream m) m r -> Stream (Of Bool) m r
384-- @
385null :: Monad m => ByteStream m r -> m (Of Bool r)
386null (Empty r) = return (True :> r)
387null (Go m) = m >>= null
388null (Chunk bs rest) = if B.null bs
389 then null rest
390 else do
391 r <- SP.effects (toChunks rest)
392 return (False :> r)
393{-# INLINABLE null #-}
394
395-- | /O(1)/ Test whether a `ByteStream` is empty. The value is of course in the
396-- monad of the effects.
397--
398-- >>> Q.null "one\ntwo\three\nfour\nfive\n"
399-- False
400-- >>> Q.null $ Q.take 0 Q.stdin
401-- True
402-- >>> :t Q.null $ Q.take 0 Q.stdin
403-- Q.null $ Q.take 0 Q.stdin :: MonadIO m => m Bool
404null_ :: Monad m => ByteStream m r -> m Bool
405null_ (Empty _) = return True
406null_ (Go m) = m >>= null_
407null_ (Chunk bs rest) = if B.null bs
408 then null_ rest
409 else return False
410{-# INLINABLE null_ #-}
411
412-- | Similar to `null`, but yields the remainder of the `ByteStream` stream when
413-- an answer has been determined.
414testNull :: Monad m => ByteStream m r -> m (Of Bool (ByteStream m r))
415testNull (Empty r) = return (True :> Empty r)
416testNull (Go m) = m >>= testNull
417testNull p@(Chunk bs rest) = if B.null bs
418 then testNull rest
419 else return (False :> p)
420{-# INLINABLE testNull #-}
421
422-- | Remove empty ByteStrings from a stream of bytestrings.
423denull :: Monad m => Stream (ByteStream m) m r -> Stream (ByteStream m) m r
424{-# INLINABLE denull #-}
425denull = loop . Right
426 where
427 -- Scan each substream, dropping empty chunks along the way. As soon as a
428 -- non-empty chunk is found, just apply the loop to the next substream in
429 -- the terminal value via fmap. If Empty comes up before that happens,
430 -- continue the current stream instead with its denulled tail.
431 --
432 -- This implementation is tail recursive:
433 -- * Recursion via 'loop . Left' continues scanning an inner ByteStream.
434 -- * Recursion via 'loop . Right' moves to the next substream.
435 --
436 -- The old version below was shorter, but noticeably slower, especially
437 -- when empty substreams are frequent:
438 --
439 -- denull = hoist (run . maps effects) . separate . mapped nulls
440 --
441 loop = \ case
442 Left mbs -> case mbs of
443 Chunk c cs | B.length c > 0 -> Step $ Chunk c $ fmap (loop . Right) cs
444 | otherwise -> loop $ Left cs
445 Go m -> Effect $ loop . Left <$> m
446 Empty r -> loop $ Right r
447 Right strm -> case strm of
448 Step mbs -> case mbs of
449 Chunk c cs | B.length c > 0 -> Step $ Chunk c $ fmap (loop . Right) cs
450 | otherwise -> loop $ Left cs
451 Go m -> Effect $ loop . Left <$> m
452 Empty r -> loop $ Right r
453 Effect m -> Effect $ fmap (loop . Right) m
454 r@(Return _) -> r
455
456{-| /O1/ Distinguish empty from non-empty lines, while maintaining streaming;
457 the empty ByteStrings are on the right
458
459>>> nulls :: ByteStream m r -> m (Sum (ByteStream m) (ByteStream m) r)
460
461 There are many (generally slower) ways to remove null bytestrings from a
462 @Stream (ByteStream m) m r@ (besides using @denull@). If we pass next to
463
464>>> mapped nulls bs :: Stream (Sum (ByteStream m) (ByteStream m)) m r
465
466 then can then apply @Streaming.separate@ to get
467
468>>> separate (mapped nulls bs) :: Stream (ByteStream m) (Stream (ByteStream m) m) r
469
470 The inner monad is now made of the empty bytestrings; we act on this
471 with @hoist@ , considering that
472
473>>> :t Q.effects . Q.concat
474Q.effects . Q.concat
475 :: Monad m => Stream (Q.ByteStream m) m r -> m r
476
477 we have
478
479>>> hoist (Q.effects . Q.concat) . separate . mapped Q.nulls
480 :: Monad n => Stream (Q.ByteStream n) n b -> Stream (Q.ByteStream n) n b
481-}
482nulls :: Monad m => ByteStream m r -> m (Sum (ByteStream m) (ByteStream m) r)
483nulls (Empty r) = return (InR (return r))
484nulls (Go m) = m >>= nulls
485nulls (Chunk bs rest) = if B.null bs
486 then nulls rest
487 else return (InL (Chunk bs rest))
488{-# INLINABLE nulls #-}
489
490-- | Like `length`, report the length in bytes of the `ByteStream` by running
491-- through its contents. Since the return value is in the effect @m@, this is
492-- one way to "get out" of the stream.
493length_ :: Monad m => ByteStream m r -> m Int
494length_ = fmap (\(n:> _) -> n) . foldlChunks (\n c -> n + fromIntegral (B.length c)) 0
495{-# INLINE length_ #-}
496
497-- | /O(n\/c)/ 'length' returns the length of a byte stream as an 'Int' together
498-- with the return value. This makes various maps possible.
499--
500-- >>> Q.length "one\ntwo\three\nfour\nfive\n"
501-- 23 :> ()
502-- >>> S.print $ S.take 3 $ mapped Q.length $ Q.lines "one\ntwo\three\nfour\nfive\n"
503-- 3
504-- 8
505-- 4
506length :: Monad m => ByteStream m r -> m (Of Int r)
507length = foldlChunks (\n c -> n + fromIntegral (B.length c)) 0
508{-# INLINE length #-}
509
510-- | /O(1)/ 'cons' is analogous to @(:)@ for lists.
511cons :: Monad m => Word8 -> ByteStream m r -> ByteStream m r
512cons c cs = Chunk (B.singleton c) cs
513{-# INLINE cons #-}
514
515-- | /O(1)/ Unlike 'cons', 'cons\'' is strict in the ByteString that we are
516-- consing onto. More precisely, it forces the head and the first chunk. It does
517-- this because, for space efficiency, it may coalesce the new byte onto the
518-- first \'chunk\' rather than starting a new \'chunk\'.
519--
520-- So that means you can't use a lazy recursive contruction like this:
521--
522-- > let xs = cons\' c xs in xs
523--
524-- You can however use 'cons', as well as 'repeat' and 'cycle', to build
525-- infinite byte streams.
526cons' :: Word8 -> ByteStream m r -> ByteStream m r
527cons' w (Chunk c cs) | B.length c < 16 = Chunk (B.cons w c) cs
528cons' w cs = Chunk (B.singleton w) cs
529{-# INLINE cons' #-}
530
531-- | /O(n\/c)/ Append a byte to the end of a 'ByteStream'.
532snoc :: Monad m => ByteStream m r -> Word8 -> ByteStream m r
533snoc cs w = do -- cs <* singleton w
534 r <- cs
535 singleton w
536 return r
537{-# INLINE snoc #-}
538
539-- | /O(1)/ Extract the first element of a 'ByteStream', which must be non-empty.
540head_ :: Monad m => ByteStream m r -> m Word8
541head_ (Empty _) = error "head"
542head_ (Chunk c bs) = if B.null c
543 then head_ bs
544 else return $ B.unsafeHead c
545head_ (Go m) = m >>= head_
546{-# INLINABLE head_ #-}
547
548-- | /O(c)/ Extract the first element of a 'ByteStream', if there is one.
549-- Suitable for use with `SP.mapped`:
550--
551-- @
552-- S.mapped Q.head :: Stream (Q.ByteStream m) m r -> Stream (Of (Maybe Word8)) m r
553-- @
554head :: Monad m => ByteStream m r -> m (Of (Maybe Word8) r)
555head (Empty r) = return (Nothing :> r)
556head (Chunk c rest) = case B.uncons c of
557 Nothing -> head rest
558 Just (w,_) -> do
559 r <- SP.effects $ toChunks rest
560 return $! Just w :> r
561head (Go m) = m >>= head
562{-# INLINABLE head #-}
563
564-- | /O(1)/ Extract the head and tail of a 'ByteStream', or its return value if
565-- it is empty. This is the \'natural\' uncons for an effectful byte stream.
566uncons :: Monad m => ByteStream m r -> m (Either r (Word8, ByteStream m r))
567uncons (Chunk c@(B.length -> len) cs)
568 | len > 0 = let !h = B.unsafeHead c
569 !t = if len > 1 then Chunk (B.unsafeTail c) cs else cs
570 in return $ Right (h, t)
571 | otherwise = uncons cs
572uncons (Go m) = m >>= uncons
573uncons (Empty r) = return (Left r)
574{-# INLINABLE uncons #-}
575
576-- | The same as `uncons`, will be removed in the next version.
577nextByte :: Monad m => ByteStream m r -> m (Either r (Word8, ByteStream m r))
578nextByte = uncons
579{-# INLINABLE nextByte #-}
580{-# DEPRECATED nextByte "Use uncons instead." #-}
581
582-- | Like `uncons`, but yields the entire first `B.ByteString` chunk that the
583-- stream is holding onto. If there wasn't one, it tries to fetch it. Yields
584-- the final @r@ return value when the 'ByteStream' is empty.
585unconsChunk :: Monad m => ByteStream m r -> m (Either r (B.ByteString, ByteStream m r))
586unconsChunk (Chunk c cs)
587 | B.null c = unconsChunk cs
588 | otherwise = return (Right (c,cs))
589unconsChunk (Go m) = m >>= unconsChunk
590unconsChunk (Empty r) = return (Left r)
591{-# INLINABLE unconsChunk #-}
592
593-- | The same as `unconsChunk`, will be removed in the next version.
594nextChunk :: Monad m => ByteStream m r -> m (Either r (B.ByteString, ByteStream m r))
595nextChunk = unconsChunk
596{-# INLINABLE nextChunk #-}
597{-# DEPRECATED nextChunk "Use unconsChunk instead." #-}
598
599-- | /O(n\/c)/ Extract the last element of a 'ByteStream', which must be finite
600-- and non-empty.
601last_ :: Monad m => ByteStream m r -> m Word8
602last_ (Empty _) = error "Streaming.ByteString.last: empty string"
603last_ (Go m) = m >>= last_
604last_ (Chunk c0 cs0) = go c0 cs0
605 where
606 go c (Empty _) = if B.null c
607 then error "Streaming.ByteString.last: empty string"
608 else return $ unsafeLast c
609 go _ (Chunk c cs) = go c cs
610 go x (Go m) = m >>= go x
611{-# INLINABLE last_ #-}
612
613-- | Extract the last element of a `ByteStream`, if possible. Suitable for use
614-- with `SP.mapped`:
615--
616-- @
617-- S.mapped Q.last :: Streaming (ByteStream m) m r -> Stream (Of (Maybe Word8)) m r
618-- @
619last :: Monad m => ByteStream m r -> m (Of (Maybe Word8) r)
620last (Empty r) = return (Nothing :> r)
621last (Go m) = m >>= last
622last (Chunk c0 cs0) = go c0 cs0
623 where
624 go c (Empty r) = return (Just (unsafeLast c) :> r)
625 go _ (Chunk c cs) = go c cs
626 go x (Go m) = m >>= go x
627{-# INLINABLE last #-}
628
629-- | /O(n\/c)/ Append two `ByteString`s together.
630append :: Monad m => ByteStream m r -> ByteStream m s -> ByteStream m s
631append xs ys = dematerialize xs (const ys) Chunk Go
632{-# INLINE append #-}
633
634-- ---------------------------------------------------------------------
635-- Transformations
636
637-- | /O(n)/ 'map' @f xs@ is the ByteStream obtained by applying @f@ to each
638-- element of @xs@.
639map :: Monad m => (Word8 -> Word8) -> ByteStream m r -> ByteStream m r
640map f z = dematerialize z Empty (Chunk . B.map f) Go
641{-# INLINE map #-}
642
643-- | @'for' xs f@ applies @f@ to each chunk in the stream, and
644-- concatenates the resulting streams.
645--
646-- Generalised in 0.2.4 to match @streaming@: the callback's (ignored)
647-- return value can be of any type.
648--
649-- @since 0.2.3
650for :: Monad m => ByteStream m r -> (P.ByteString -> ByteStream m x) -> ByteStream m r
651for stream f = case stream of
652 Empty r -> Empty r
653 Chunk bs bss -> f bs *> for bss f
654 Go m -> Go ((`for` f) <$> m)
655{-# INLINE for #-}
656
657-- -- | /O(n)/ 'reverse' @xs@ returns the elements of @xs@ in reverse order.
658-- reverse :: ByteString -> ByteString
659-- reverse cs0 = rev Empty cs0
660-- where rev a Empty = a
661-- rev a (Chunk c cs) = rev (Chunk (B.reverse c) a) cs
662-- {-# INLINE reverse #-}
663
664-- | The 'intersperse' function takes a 'Word8' and a 'ByteStream' and
665-- \`intersperses\' that byte between the elements of the 'ByteStream'. It is
666-- analogous to the intersperse function on Streams.
667intersperse :: Monad m => Word8 -> ByteStream m r -> ByteStream m r
668intersperse _ (Empty r) = Empty r
669intersperse w (Go m) = Go (fmap (intersperse w) m)
670intersperse w (Chunk c cs) | B.null c = intersperse w cs
671 | otherwise =
672 Chunk (B.intersperse w c)
673 (dematerialize cs Empty (Chunk . intersperse') Go)
674 where intersperse' :: P.ByteString -> P.ByteString
675 intersperse' (B.PS fp o l)
676 | l > 0 = B.unsafeCreate (2*l) $ \p' -> unsafeWithForeignPtr fp $ \p -> do
677 poke p' w
678 B.c_intersperse (p' `plusPtr` 1) (p `plusPtr` o) (fromIntegral l) w
679 | otherwise = B.empty
680{-# INLINABLE intersperse #-}
681
682-- | 'foldr', applied to a binary operator, a starting value (typically the
683-- right-identity of the operator), and a ByteStream, reduces the ByteStream
684-- using the binary operator, from right to left.
685--
686foldr :: Monad m => (Word8 -> a -> a) -> a -> ByteStream m () -> m a
687foldr k = foldrChunks (flip (B.foldr k))
688{-# INLINE foldr #-}
689
690-- | 'fold_', applied to a binary operator, a starting value (typically the
691-- left-identity of the operator), and a ByteStream, reduces the ByteStream
692-- using the binary operator, from left to right. We use the style of the foldl
693-- library for left folds
694fold_ :: Monad m => (x -> Word8 -> x) -> x -> (x -> b) -> ByteStream m () -> m b
695fold_ step0 begin finish p0 = loop p0 begin
696 where
697 loop p !x = case p of
698 Chunk bs bss -> loop bss $! B.foldl' step0 x bs
699 Go m -> m >>= \p' -> loop p' x
700 Empty _ -> return (finish x)
701{-# INLINABLE fold_ #-}
702
703-- | 'fold' keeps the return value of the left-folded bytestring. Useful for
704-- simultaneous folds over a segmented bytestream.
705fold :: Monad m => (x -> Word8 -> x) -> x -> (x -> b) -> ByteStream m r -> m (Of b r)
706fold step0 begin finish p0 = loop p0 begin
707 where
708 loop p !x = case p of
709 Chunk bs bss -> loop bss $! B.foldl' step0 x bs
710 Go m -> m >>= \p' -> loop p' x
711 Empty r -> return (finish x :> r)
712{-# INLINABLE fold #-}
713
714-- ---------------------------------------------------------------------
715-- Special folds
716
717-- /O(n)/ Concatenate a list of ByteStreams.
718-- concat :: (Monad m) => [ByteStream m ()] -> ByteStream m ()
719-- concat css0 = to css0
720-- where
721-- go css (Empty m') = to css
722-- go css (Chunk c cs) = Chunk c (go css cs)
723-- go css (Go m) = Go (fmap (go css) m)
724-- to [] = Empty ()
725-- to (cs:css) = go css cs
726
727-- ---------------------------------------------------------------------
728-- Unfolds and replicates
729
730{-| @'iterate' f x@ returns an infinite ByteStream of repeated applications
731-- of @f@ to @x@:
732
733> iterate f x == [x, f x, f (f x), ...]
734
735>>> R.stdout $ R.take 50 $ R.iterate succ 39
736()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXY
737>>> Q.putStrLn $ Q.take 50 $ Q.iterate succ '\''
738()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXY
739-}
740iterate :: (Word8 -> Word8) -> Word8 -> ByteStream m r
741iterate f = unfoldr (\x -> case f x of !x' -> Right (x', x'))
742{-# INLINABLE iterate #-}
743
744{- | @'repeat' x@ is an infinite ByteStream, with @x@ the value of every
745 element.
746
747>>> R.stdout $ R.take 50 $ R.repeat 60
748<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
749>>> Q.putStrLn $ Q.take 50 $ Q.repeat 'z'
750zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
751-}
752repeat :: Word8 -> ByteStream m r
753repeat w = cs where cs = Chunk (B.replicate BI.smallChunkSize w) cs
754{-# INLINABLE repeat #-}
755
756{- | 'cycle' ties a finite ByteStream into a circular one, or equivalently,
757 the infinite repetition of the original ByteStream. For an empty bytestring
758 (like @return 17@) it of course makes an unproductive loop
759
760>>> Q.putStrLn $ Q.take 7 $ Q.cycle "y\n"
761y
762y
763y
764y
765-}
766cycle :: Monad m => ByteStream m r -> ByteStream m s
767cycle = forever
768{-# INLINE cycle #-}
769
770-- | /O(n)/ The 'unfoldM' function is analogous to the Stream @unfoldr@.
771-- 'unfoldM' builds a ByteStream from a seed value. The function takes the
772-- element and returns 'Nothing' if it is done producing the ByteStream or
773-- returns @'Just' (a,b)@, in which case, @a@ is a prepending to the ByteStream
774-- and @b@ is used as the next element in a recursive call.
775unfoldM :: Monad m => (a -> Maybe (Word8, a)) -> a -> ByteStream m ()
776unfoldM f s0 = unfoldChunk 32 s0
777 where unfoldChunk n s =
778 case B.unfoldrN n f s of
779 (c, Nothing)
780 | B.null c -> Empty ()
781 | otherwise -> Chunk c (Empty ())
782 (c, Just s') -> Chunk c (unfoldChunk (n*2) s')
783{-# INLINABLE unfoldM #-}
784
785-- | Like `unfoldM`, but yields a final @r@ when the `Word8` generation is
786-- complete.
787unfoldr :: (a -> Either r (Word8, a)) -> a -> ByteStream m r
788unfoldr f s0 = unfoldChunk 32 s0
789 where unfoldChunk n s =
790 case unfoldrNE n f s of
791 (c, Left r)
792 | B.null c -> Empty r
793 | otherwise -> Chunk c (Empty r)
794 (c, Right s') -> Chunk c (unfoldChunk (n*2) s')
795{-# INLINABLE unfoldr #-}
796
797-- ---------------------------------------------------------------------
798-- Substrings
799
800{-| /O(n\/c)/ 'take' @n@, applied to a ByteStream @xs@, returns the prefix
801 of @xs@ of length @n@, or @xs@ itself if @n > 'length' xs@.
802
803 Note that in the streaming context this drops the final return value;
804 'splitAt' preserves this information, and is sometimes to be preferred.
805
806>>> Q.putStrLn $ Q.take 8 $ "Is there a God?" >> return True
807Is there
808>>> Q.putStrLn $ "Is there a God?" >> return True
809Is there a God?
810True
811>>> rest <- Q.putStrLn $ Q.splitAt 8 $ "Is there a God?" >> return True
812Is there
813>>> Q.effects rest
814True
815-}
816take :: Monad m => Int64 -> ByteStream m r -> ByteStream m ()
817take i _ | i <= 0 = Empty ()
818take i cs0 = take' i cs0
819 where take' 0 _ = Empty ()
820 take' _ (Empty _) = Empty ()
821 take' n (Chunk c cs) =
822 if n < fromIntegral (B.length c)
823 then Chunk (B.take (fromIntegral n) c) (Empty ())
824 else Chunk c (take' (n - fromIntegral (B.length c)) cs)
825 take' n (Go m) = Go (fmap (take' n) m)
826{-# INLINABLE take #-}
827
828{-| /O(n\/c)/ 'drop' @n xs@ returns the suffix of @xs@ after the first @n@
829 elements, or @[]@ if @n > 'length' xs@.
830
831>>> Q.putStrLn $ Q.drop 6 "Wisconsin"
832sin
833>>> Q.putStrLn $ Q.drop 16 "Wisconsin"
834<BLANKLINE>
835-}
836drop :: Monad m => Int64 -> ByteStream m r -> ByteStream m r
837drop i p | i <= 0 = p
838drop i cs0 = drop' i cs0
839 where drop' 0 cs = cs
840 drop' _ (Empty r) = Empty r
841 drop' n (Chunk c cs) =
842 if n < fromIntegral (B.length c)
843 then Chunk (B.drop (fromIntegral n) c) cs
844 else drop' (n - fromIntegral (B.length c)) cs
845 drop' n (Go m) = Go (fmap (drop' n) m)
846{-# INLINABLE drop #-}
847
848{-| /O(n\/c)/ 'splitAt' @n xs@ is equivalent to @('take' n xs, 'drop' n xs)@.
849
850>>> rest <- Q.putStrLn $ Q.splitAt 3 "therapist is a danger to good hyphenation, as Knuth notes"
851the
852>>> Q.putStrLn $ Q.splitAt 19 rest
853rapist is a danger
854-}
855splitAt :: Monad m => Int64 -> ByteStream m r -> ByteStream m (ByteStream m r)
856splitAt i cs0 | i <= 0 = Empty cs0
857splitAt i cs0 = splitAt' i cs0
858 where splitAt' 0 cs = Empty cs
859 splitAt' _ (Empty r ) = Empty (Empty r)
860 splitAt' n (Chunk c cs) =
861 if n < fromIntegral (B.length c)
862 then Chunk (B.take (fromIntegral n) c) $
863 Empty (Chunk (B.drop (fromIntegral n) c) cs)
864 else Chunk c (splitAt' (n - fromIntegral (B.length c)) cs)
865 splitAt' n (Go m) = Go (fmap (splitAt' n) m)
866{-# INLINABLE splitAt #-}
867
868-- | 'takeWhile', applied to a predicate @p@ and a ByteStream @xs@, returns the
869-- longest prefix (possibly empty) of @xs@ of elements that satisfy @p@.
870takeWhile :: Monad m => (Word8 -> Bool) -> ByteStream m r -> ByteStream m ()
871takeWhile f cs0 = takeWhile' cs0
872 where
873 takeWhile' (Empty _) = Empty ()
874 takeWhile' (Go m) = Go $ fmap takeWhile' m
875 takeWhile' (Chunk c cs) =
876 case findIndexOrEnd (not . f) c of
877 0 -> Empty ()
878 n | n < B.length c -> Chunk (B.take n c) (Empty ())
879 | otherwise -> Chunk c (takeWhile' cs)
880{-# INLINABLE takeWhile #-}
881
882-- | 'dropWhile' @p xs@ returns the suffix remaining after 'takeWhile' @p xs@.
883dropWhile :: Monad m => (Word8 -> Bool) -> ByteStream m r -> ByteStream m r
884dropWhile p = drop' where
885 drop' bs = case bs of
886 Empty r -> Empty r
887 Go m -> Go (fmap drop' m)
888 Chunk c cs -> case findIndexOrEnd (not . p) c of
889 0 -> Chunk c cs
890 n | n < B.length c -> Chunk (B.drop n c) cs
891 | otherwise -> drop' cs
892{-# INLINABLE dropWhile #-}
893
894-- | 'break' @p@ is equivalent to @'span' ('not' . p)@.
895break :: Monad m => (Word8 -> Bool) -> ByteStream m r -> ByteStream m (ByteStream m r)
896break f cs0 = break' cs0
897 where break' (Empty r) = Empty (Empty r)
898 break' (Chunk c cs) =
899 case findIndexOrEnd f c of
900 0 -> Empty (Chunk c cs)
901 n | n < B.length c -> Chunk (B.take n c) $
902 Empty (Chunk (B.drop n c) cs)
903 | otherwise -> Chunk c (break' cs)
904 break' (Go m) = Go (fmap break' m)
905{-# INLINABLE break #-}
906
907-- | 'span' @p xs@ breaks the ByteStream into two segments. It is equivalent to
908-- @('takeWhile' p xs, 'dropWhile' p xs)@.
909span :: Monad m => (Word8 -> Bool) -> ByteStream m r -> ByteStream m (ByteStream m r)
910span p = break (not . p)
911{-# INLINE span #-}
912
913-- | /O(n)/ Splits a 'ByteStream' into components delimited by separators, where
914-- the predicate returns True for a separator element. The resulting components
915-- do not contain the separators. Two adjacent separators result in an empty
916-- component in the output. eg.
917--
918-- > splitWith (=='a') "aabbaca" == ["","","bb","c",""]
919-- > splitWith (=='a') [] == []
920splitWith :: Monad m => (Word8 -> Bool) -> ByteStream m r -> Stream (ByteStream m) m r
921splitWith _ (Empty r) = Return r
922splitWith p (Go m) = Effect $ fmap (splitWith p) m
923splitWith p (Chunk c0 cs0) = comb [] (B.splitWith p c0) cs0
924 where
925-- comb :: [P.ByteString] -> [P.ByteString] -> ByteString -> [ByteString]
926-- comb acc (s:[]) (Empty r) = Step (revChunks (s:acc) (Return r))
927 comb acc [s] (Empty r) = Step $ L.foldl' (flip Chunk)
928 (Empty (Return r))
929 (s:acc)
930 comb acc [s] (Chunk c cs) = comb (s:acc) (B.splitWith p c) cs
931 comb acc b (Go m) = Effect (fmap (comb acc b) m)
932 comb acc (s:ss) cs = Step $ L.foldl' (flip Chunk)
933 (Empty (comb [] ss cs))
934 (s:acc)
935 comb acc [] (Empty r) = Step $ L.foldl' (flip Chunk)
936 (Empty (Return r))
937 acc
938 comb acc [] (Chunk c cs) = comb acc (B.splitWith p c) cs
939 -- comb acc (s:ss) cs = Step (revChunks (s:acc) (comb [] ss cs))
940
941{-# INLINABLE splitWith #-}
942
943-- | /O(n)/ Break a 'ByteStream' into pieces separated by the byte
944-- argument, consuming the delimiter. I.e.
945--
946-- > split '\n' "a\nb\nd\ne" == ["a","b","d","e"]
947-- > split 'a' "aXaXaXa" == ["","X","X","X",""]
948-- > split 'x' "x" == ["",""]
949--
950-- and
951--
952-- > intercalate [c] . split c == id
953-- > split == splitWith . (==)
954--
955-- As for all splitting functions in this library, this function does not copy
956-- the substrings, it just constructs new 'ByteStream's that are slices of the
957-- original.
958split :: Monad m => Word8 -> ByteStream m r -> Stream (ByteStream m) m r
959split w = loop
960 where
961 loop !x = case x of
962 Empty r -> Return r
963 Go m -> Effect $ fmap loop m
964 Chunk c0 cs0 -> comb [] (B.split w c0) cs0
965 comb !acc [] (Empty r) = Step $ revChunks acc (Return r)
966 comb acc [] (Chunk c cs) = comb acc (B.split w c) cs
967 comb !acc [s] (Empty r) = Step $ revChunks (s:acc) (Return r)
968 comb acc [s] (Chunk c cs) = comb (s:acc) (B.split w c) cs
969 comb acc b (Go m) = Effect (fmap (comb acc b) m)
970 comb acc (s:ss) cs = Step $ revChunks (s:acc) (comb [] ss cs)
971{-# INLINABLE split #-}
972
973-- | The 'group' function takes a ByteStream and returns a list of ByteStreams
974-- such that the concatenation of the result is equal to the argument. Moreover,
975-- each sublist in the result contains only equal elements. For example,
976--
977-- > group "Mississippi" = ["M","i","ss","i","ss","i","pp","i"]
978--
979-- It is a special case of 'groupBy', which allows the programmer to supply
980-- their own equality test.
981group :: Monad m => ByteStream m r -> Stream (ByteStream m) m r
982group = go
983 where
984 go (Empty r) = Return r
985 go (Go m) = Effect $ fmap go m
986 go (Chunk c cs)
987 | B.length c == 1 = Step $ to [c] (B.unsafeHead c) cs
988 | otherwise = Step $ to [B.unsafeTake 1 c] (B.unsafeHead c) (Chunk (B.unsafeTail c) cs)
989
990 to acc !_ (Empty r) = revNonEmptyChunks acc (Empty (Return r))
991 to acc !w (Go m) = Go $ to acc w <$> m
992 to acc !w (Chunk c cs) = case findIndexOrEnd (/= w) c of
993 0 -> revNonEmptyChunks acc (Empty (go (Chunk c cs)))
994 n | n == B.length c -> to (B.unsafeTake n c : acc) w cs
995 | otherwise -> revNonEmptyChunks (B.unsafeTake n c : acc) (Empty (go (Chunk (B.unsafeDrop n c) cs)))
996{-# INLINABLE group #-}
997
998-- | The 'groupBy' function is a generalized version of 'group'.
999groupBy :: Monad m => (Word8 -> Word8 -> Bool) -> ByteStream m r -> Stream (ByteStream m) m r
1000groupBy rel = go
1001 where
1002 -- go :: ByteStream m r -> Stream (ByteStream m) m r
1003 go (Empty r) = Return r
1004 go (Go m) = Effect $ fmap go m
1005 go (Chunk c cs)
1006 | B.length c == 1 = Step $ to [c] (B.unsafeHead c) cs
1007 | otherwise = Step $ to [B.unsafeTake 1 c] (B.unsafeHead c) (Chunk (B.unsafeTail c) cs)
1008
1009 -- to :: [B.ByteString] -> Word8 -> ByteStream m r -> ByteStream m (Stream (ByteStream m) m r)
1010 to acc !_ (Empty r) = revNonEmptyChunks acc (Empty (Return r))
1011 to acc !w (Go m) = Go $ to acc w <$> m
1012 to acc !w (Chunk c cs) = case findIndexOrEnd (not . rel w) c of
1013 0 -> revNonEmptyChunks acc (Empty (go (Chunk c cs)))
1014 n | n == B.length c -> to (B.unsafeTake n c : acc) w cs
1015 | otherwise -> revNonEmptyChunks (B.unsafeTake n c : acc) (Empty (go (Chunk (B.unsafeDrop n c) cs)))
1016{-# INLINABLE groupBy #-}
1017
1018-- | /O(n)/ The 'intercalate' function takes a 'ByteStream' and a list of
1019-- 'ByteStream's and concatenates the list after interspersing the first
1020-- argument between each element of the list.
1021intercalate :: Monad m => ByteStream m () -> Stream (ByteStream m) m r -> ByteStream m r
1022intercalate s = loop
1023 where
1024 loop (Return r) = Empty r
1025 loop (Effect m) = Go $ fmap loop m
1026 loop (Step bs) = bs >>= \case
1027 Return r -> Empty r -- not between final substream and stream end
1028 x -> s >> loop x
1029{-# INLINABLE intercalate #-}
1030
1031-- | Returns the number of times its argument appears in the `ByteStream`.
1032--
1033-- > count = length . elemIndices
1034count_ :: Monad m => Word8 -> ByteStream m r -> m Int
1035count_ w = fmap (\(n :> _) -> n) . foldlChunks (\n c -> n + fromIntegral (B.count w c)) 0
1036{-# INLINE count_ #-}
1037
1038-- | Returns the number of times its argument appears in the `ByteStream`.
1039-- Suitable for use with `SP.mapped`:
1040--
1041-- @
1042-- S.mapped (Q.count 37) :: Stream (Q.ByteStream m) m r -> Stream (Of Int) m r
1043-- @
1044count :: Monad m => Word8 -> ByteStream m r -> m (Of Int r)
1045count w cs = foldlChunks (\n c -> n + fromIntegral (B.count w c)) 0 cs
1046{-# INLINE count #-}
1047
1048-- ---------------------------------------------------------------------
1049-- Searching ByteStreams
1050
1051-- | /O(n)/ 'filter', applied to a predicate and a ByteStream, returns a
1052-- ByteStream containing those characters that satisfy the predicate.
1053filter :: Monad m => (Word8 -> Bool) -> ByteStream m r -> ByteStream m r
1054filter p s = go s
1055 where
1056 go (Empty r ) = Empty r
1057 go (Chunk x xs) = consChunk (B.filter p x) (go xs)
1058 go (Go m) = Go (fmap go m)
1059 -- should inspect for null
1060{-# INLINABLE filter #-}
1061
1062-- ---------------------------------------------------------------------
1063-- ByteStream IO
1064--
1065-- Rule for when to close: is it expected to read the whole file?
1066-- If so, close when done.
1067--
1068
1069-- | Read entire handle contents /lazily/ into a 'ByteStream'. Chunks are read
1070-- on demand, in at most @k@-sized chunks. It does not block waiting for a whole
1071-- @k@-sized chunk, so if less than @k@ bytes are available then they will be
1072-- returned immediately as a smaller chunk.
1073--
1074-- Note: the 'Handle' should be placed in binary mode with
1075-- 'System.IO.hSetBinaryMode' for 'hGetContentsN' to work correctly.
1076hGetContentsN :: MonadIO m => Int -> Handle -> ByteStream m ()
1077hGetContentsN k h = loop -- TODO close on exceptions
1078 where
1079 loop = do
1080 c <- liftIO (B.hGetSome h k)
1081 -- only blocks if there is no data available
1082 if B.null c
1083 then Empty ()
1084 else Chunk c loop
1085{-# INLINABLE hGetContentsN #-} -- very effective inline pragma
1086
1087-- | Read @n@ bytes into a 'ByteStream', directly from the specified 'Handle',
1088-- in chunks of size @k@.
1089hGetN :: MonadIO m => Int -> Handle -> Int -> ByteStream m ()
1090hGetN k h n | n > 0 = readChunks n
1091 where
1092 readChunks !i = Go $ do
1093 c <- liftIO $ B.hGet h (min k i)
1094 case B.length c of
1095 0 -> return $ Empty ()
1096 m -> return $ Chunk c (readChunks (i - m))
1097hGetN _ _ 0 = Empty ()
1098hGetN _ h n = liftIO $ illegalBufferSize h "hGet" n -- <--- REPAIR !!!
1099{-# INLINABLE hGetN #-}
1100
1101-- | hGetNonBlockingN is similar to 'hGetContentsN', except that it will never
1102-- block waiting for data to become available, instead it returns only whatever
1103-- data is available. Chunks are read on demand, in @k@-sized chunks.
1104hGetNonBlockingN :: MonadIO m => Int -> Handle -> Int -> ByteStream m ()
1105hGetNonBlockingN k h n | n > 0 = readChunks n
1106 where
1107 readChunks !i = Go $ do
1108 c <- liftIO $ B.hGetNonBlocking h (min k i)
1109 case B.length c of
1110 0 -> return (Empty ())
1111 m -> return (Chunk c (readChunks (i - m)))
1112hGetNonBlockingN _ _ 0 = Empty ()
1113hGetNonBlockingN _ h n = liftIO $ illegalBufferSize h "hGetNonBlocking" n
1114{-# INLINABLE hGetNonBlockingN #-}
1115
1116illegalBufferSize :: Handle -> String -> Int -> IO a
1117illegalBufferSize handle fn sz =
1118 ioError (mkIOError illegalOperationErrorType msg (Just handle) Nothing)
1119 --TODO: System.IO uses InvalidArgument here, but it's not exported :-(
1120 where
1121 msg = fn ++ ": illegal ByteStream size " ++ showsPrec 9 sz []
1122{-# INLINABLE illegalBufferSize #-}
1123
1124-- | Read entire handle contents /lazily/ into a 'ByteStream'. Chunks are read
1125-- on demand, using the default chunk size.
1126--
1127-- Note: the 'Handle' should be placed in binary mode with
1128-- 'System.IO.hSetBinaryMode' for 'hGetContents' to work correctly.
1129hGetContents :: MonadIO m => Handle -> ByteStream m ()
1130hGetContents = hGetContentsN defaultChunkSize
1131{-# INLINE hGetContents #-}
1132
1133-- | Pipes-style nomenclature for 'hGetContents'.
1134fromHandle :: MonadIO m => Handle -> ByteStream m ()
1135fromHandle = hGetContents
1136{-# INLINE fromHandle #-}
1137
1138-- | Pipes-style nomenclature for 'getContents'.
1139stdin :: MonadIO m => ByteStream m ()
1140stdin = hGetContents IO.stdin
1141{-# INLINE stdin #-}
1142
1143-- | Read @n@ bytes into a 'ByteStream', directly from the specified 'Handle'.
1144hGet :: MonadIO m => Handle -> Int -> ByteStream m ()
1145hGet = hGetN defaultChunkSize
1146{-# INLINE hGet #-}
1147
1148-- | hGetNonBlocking is similar to 'hGet', except that it will never block
1149-- waiting for data to become available, instead it returns only whatever data
1150-- is available. If there is no data available to be read, 'hGetNonBlocking'
1151-- returns 'empty'.
1152--
1153-- Note: on Windows and with Haskell implementation other than GHC, this
1154-- function does not work correctly; it behaves identically to 'hGet'.
1155hGetNonBlocking :: MonadIO m => Handle -> Int -> ByteStream m ()
1156hGetNonBlocking = hGetNonBlockingN defaultChunkSize
1157{-# INLINE hGetNonBlocking #-}
1158
1159-- | Write a 'ByteStream' to a file. Use
1160-- 'Control.Monad.Trans.ResourceT.runResourceT' to ensure that the handle is
1161-- closed.
1162--
1163-- >>> :set -XOverloadedStrings
1164-- >>> runResourceT $ Q.writeFile "hello.txt" "Hello world.\nGoodbye world.\n"
1165-- >>> :! cat "hello.txt"
1166-- Hello world.
1167-- Goodbye world.
1168-- >>> runResourceT $ Q.writeFile "hello2.txt" $ Q.readFile "hello.txt"
1169-- >>> :! cat hello2.txt
1170-- Hello world.
1171-- Goodbye world.
1172writeFile :: MonadResource m => FilePath -> ByteStream m r -> m r
1173writeFile f str = do
1174 (key, handle) <- allocate (openBinaryFile f WriteMode) hClose
1175 r <- hPut handle str
1176 release key
1177 return r
1178{-# INLINE writeFile #-}
1179
1180-- | Read an entire file into a chunked @'ByteStream' IO ()@. The handle will be
1181-- held open until EOF is encountered. The block governed by
1182-- 'Control.Monad.Trans.Resource.runResourceT' will end with the closing of any
1183-- handles opened.
1184--
1185-- >>> :! cat hello.txt
1186-- Hello world.
1187-- Goodbye world.
1188-- >>> runResourceT $ Q.stdout $ Q.readFile "hello.txt"
1189-- Hello world.
1190-- Goodbye world.
1191readFile :: MonadResource m => FilePath -> ByteStream m ()
1192readFile f = bracketByteString (openBinaryFile f ReadMode) hClose hGetContents
1193{-# INLINE readFile #-}
1194
1195-- | Append a 'ByteStream' to a file. Use
1196-- 'Control.Monad.Trans.ResourceT.runResourceT' to ensure that the handle is
1197-- closed.
1198--
1199-- >>> runResourceT $ Q.writeFile "hello.txt" "Hello world.\nGoodbye world.\n"
1200-- >>> runResourceT $ Q.stdout $ Q.readFile "hello.txt"
1201-- Hello world.
1202-- Goodbye world.
1203-- >>> runResourceT $ Q.appendFile "hello.txt" "sincerely yours,\nArthur\n"
1204-- >>> runResourceT $ Q.stdout $ Q.readFile "hello.txt"
1205-- Hello world.
1206-- Goodbye world.
1207-- sincerely yours,
1208-- Arthur
1209appendFile :: MonadResource m => FilePath -> ByteStream m r -> m r
1210appendFile f str = do
1211 (key, handle) <- allocate (openBinaryFile f AppendMode) hClose
1212 r <- hPut handle str
1213 release key
1214 return r
1215{-# INLINE appendFile #-}
1216
1217-- | Equivalent to @hGetContents stdin@. Will read /lazily/.
1218getContents :: MonadIO m => ByteStream m ()
1219getContents = hGetContents IO.stdin
1220{-# INLINE getContents #-}
1221
1222-- | Outputs a 'ByteStream' to the specified 'Handle'.
1223hPut :: MonadIO m => Handle -> ByteStream m r -> m r
1224hPut h cs = dematerialize cs return (\x y -> liftIO (B.hPut h x) >> y) (>>= id)
1225{-# INLINE hPut #-}
1226
1227-- | Pipes nomenclature for 'hPut'.
1228toHandle :: MonadIO m => Handle -> ByteStream m r -> m r
1229toHandle = hPut
1230{-# INLINE toHandle #-}
1231
1232-- | Pipes-style nomenclature for @putStr@.
1233stdout :: MonadIO m => ByteStream m r -> m r
1234stdout = hPut IO.stdout
1235{-# INLINE stdout #-}
1236
1237-- -- | Similar to 'hPut' except that it will never block. Instead it returns
1238-- any tail that did not get written. This tail may be 'empty' in the case that
1239-- the whole string was written, or the whole original string if nothing was
1240-- written. Partial writes are also possible.
1241--
1242-- Note: on Windows and with Haskell implementation other than GHC, this
1243-- function does not work correctly; it behaves identically to 'hPut'.
1244--
1245-- hPutNonBlocking :: MonadIO m => Handle -> ByteStream m r -> ByteStream m r
1246-- hPutNonBlocking _ (Empty r) = Empty r
1247-- hPutNonBlocking h (Go m) = Go $ fmap (hPutNonBlocking h) m
1248-- hPutNonBlocking h bs@(Chunk c cs) = do
1249-- c' <- lift $ B.hPutNonBlocking h c
1250-- case B.length c' of
1251-- l' | l' == B.length c -> hPutNonBlocking h cs
1252-- 0 -> bs
1253-- _ -> Chunk c' cs
1254-- {-# INLINABLE hPutNonBlocking #-}
1255
1256-- | A synonym for @hPut@, for compatibility
1257--
1258-- hPutStr :: Handle -> ByteStream IO r -> IO r
1259-- hPutStr = hPut
1260--
1261-- -- | Write a ByteStream to stdout
1262-- putStr :: ByteStream IO r -> IO r
1263-- putStr = hPut IO.stdout
1264
1265-- | The interact function takes a function of type @ByteStream -> ByteStream@
1266-- as its argument. The entire input from the standard input device is passed to
1267-- this function as its argument, and the resulting string is output on the
1268-- standard output device.
1269--
1270-- > interact morph = stdout (morph stdin)
1271interact :: (ByteStream IO () -> ByteStream IO r) -> IO r
1272interact f = stdout (f stdin)
1273{-# INLINE interact #-}
1274
1275-- -- ---------------------------------------------------------------------
1276-- -- Internal utilities
1277
1278-- | Used in `group` and `groupBy`.
1279revNonEmptyChunks :: [P.ByteString] -> ByteStream m r -> ByteStream m r
1280revNonEmptyChunks = L.foldl' (\f bs -> Chunk bs . f) id
1281{-# INLINE revNonEmptyChunks #-}
1282
1283-- | Reverse a list of possibly-empty chunks into a lazy ByteString.
1284revChunks :: Monad m => [P.ByteString] -> r -> ByteStream m r
1285revChunks cs r = L.foldl' (flip Chunk) (Empty r) cs
1286{-# INLINE revChunks #-}
1287
1288-- | Zip a list and a stream-of-byte-streams together.
1289zipWithStream
1290 :: Monad m
1291 => (forall x . a -> ByteStream m x -> ByteStream m x)
1292 -> [a]
1293 -> Stream (ByteStream m) m r
1294 -> Stream (ByteStream m) m r
1295zipWithStream op zs = loop zs
1296 where
1297 loop [] !ls = loop zs ls
1298 loop a@(x:xs) ls = case ls of
1299 Return r -> Return r
1300 Step fls -> Step $ fmap (loop xs) (op x fls)
1301 Effect mls -> Effect $ fmap (loop a) mls
1302{-# INLINABLE zipWithStream #-}
1303
1304-- | Take a builder constructed otherwise and convert it to a genuine streaming
1305-- bytestring.
1306--
1307-- >>> Q.putStrLn $ Q.toStreamingByteString $ stringUtf8 "哈斯克尔" <> stringUtf8 " " <> integerDec 98
1308-- 哈斯克尔 98
1309--
1310-- <https://gist.github.com/michaelt/6ea89ca95a77b0ef91f3 This benchmark> shows
1311-- its performance is indistinguishable from @toLazyByteString@
1312toStreamingByteString :: MonadIO m => Builder -> ByteStream m ()
1313toStreamingByteString = toStreamingByteStringWith
1314 (safeStrategy BI.smallChunkSize BI.defaultChunkSize)
1315{-# INLINE toStreamingByteString #-}
1316
1317-- | Take a builder and convert it to a genuine streaming bytestring, using a
1318-- specific allocation strategy.
1319toStreamingByteStringWith :: MonadIO m => AllocationStrategy -> Builder -> ByteStream m ()
1320toStreamingByteStringWith strategy builder0 = do
1321 cios <- liftIO (buildStepToCIOS strategy (runBuilder builder0))
1322 let loop cios0 = case cios0 of
1323 Yield1 bs io -> Chunk bs $ do
1324 cios1 <- liftIO io
1325 loop cios1
1326 Finished buf r -> trimmedChunkFromBuffer buf (Empty r)
1327 trimmedChunkFromBuffer buffer k
1328 | B.null bs = k
1329 | 2 * B.length bs < bufferSize buffer = Chunk (B.copy bs) k
1330 | otherwise = Chunk bs k
1331 where
1332 bs = byteStringFromBuffer buffer
1333 loop cios
1334{-# INLINABLE toStreamingByteStringWith #-}
1335{-# SPECIALIZE toStreamingByteStringWith :: AllocationStrategy -> Builder -> ByteStream IO () #-}
1336
1337-- | Concatenate a stream of builders (not a streaming bytestring!) into a
1338-- single builder.
1339--
1340-- >>> let aa = yield (integerDec 10000) >> yield (string8 " is a number.") >> yield (char8 '\n')
1341-- >>> hPutBuilder IO.stdout $ concatBuilders aa
1342-- 10000 is a number.
1343concatBuilders :: Stream (Of Builder) IO () -> Builder
1344concatBuilders p = builder $ \bstep r -> do
1345 case p of
1346 Return _ -> runBuilderWith mempty bstep r
1347 Step (b :> rest) -> runBuilderWith (b `mappend` concatBuilders rest) bstep r
1348 Effect m -> m >>= \p' -> runBuilderWith (concatBuilders p') bstep r
1349{-# INLINABLE concatBuilders #-}
1350
1351-- | A simple construction of a builder from a 'ByteString'.
1352--
1353-- >>> let aaa = "10000 is a number\n" :: Q.ByteString IO ()
1354-- >>> hPutBuilder IO.stdout $ toBuilder aaa
1355-- 10000 is a number
1356toBuilder :: ByteStream IO () -> Builder
1357toBuilder = concatBuilders . SP.map byteString . toChunks
1358{-# INLINABLE toBuilder #-}