streaming-bytestring 0.1.0.3 → 0.1.0.4
raw patch · 3 files changed
+101/−12 lines, 3 files
Files
- Data/ByteString/Streaming.hs +81/−1
- Data/ByteString/Streaming/Char8.hs +9/−1
- streaming-bytestring.cabal +11/−10
Data/ByteString/Streaming.hs view
@@ -109,6 +109,13 @@ , concat -- concat :: Monad m => Stream (ByteString m) m r -> ByteString m r + -- * Builders+ + , toStreamingByteStringWith+ , toStreamingByteString+ , toBuilder+ , concatBuilders+ -- * Building ByteStrings -- ** Infinite ByteStrings@@ -177,14 +184,16 @@ import qualified Data.ByteString as S -- S for strict (hmm...) import qualified Data.ByteString.Internal as S import qualified Data.ByteString.Unsafe as S+import Data.ByteString.Builder.Internal hiding (hPut, defaultChunkSize, empty, append) import Data.ByteString.Streaming.Internal import Streaming hiding (concats, unfold, distribute, wrap) import Streaming.Internal (Stream (..)) import qualified Streaming.Prelude as SP -import Control.Monad (liftM, forever) +import Control.Monad (liftM, forever)+import Data.Monoid (Monoid(..)) import Data.Word (Word8) import Data.Int (Int64) import System.IO (Handle,openBinaryFile,IOMode(..)@@ -1554,3 +1563,74 @@ case e of Left stream -> loop stream Right (bs, qbs) -> Step (chunk bs >> fmap loop qbs)+ +{- Take a builder constructed otherwise and convert it to a genuine+ streaming bytestring. + +>>> Q.putStrLn $ Q.toStreamingByteString $ stringUtf8 "哈斯克尔" <> stringUtf8 " " <> integerDec 98+哈斯克尔 98+ + <https://gist.github.com/michaelt/6ea89ca95a77b0ef91f3 This benchmark> shows its+ indistinguishable performance is indistinguishable from @toLazyByteString@++ +-}++toStreamingByteString+ :: MonadIO m => Builder -> ByteString m ()+toStreamingByteString = toStreamingByteStringWith+ (safeStrategy BI.smallChunkSize BI.defaultChunkSize)+{-#INLINE toStreamingByteString #-}+{-#SPECIALIZE toStreamingByteString :: Builder -> ByteString IO () #-}++{-| Take a builder and convert it to a genuine+ streaming bytestring, using a specific allocation strategy.+-}+toStreamingByteStringWith+ :: MonadIO m =>+ AllocationStrategy -> Builder -> ByteString m ()+toStreamingByteStringWith strategy builder0 = do+ cios <- liftIO (buildStepToCIOS strategy (runBuilder builder0))+ let loop cios0 = case cios0 of+ Yield1 bs io -> Chunk bs $ do + cios1 <- liftIO io + loop cios1 + Finished buf r -> trimmedChunkFromBuffer buf (Empty r)+ trimmedChunkFromBuffer buffer k + | S.null bs = k+ | 2 * S.length bs < bufferSize buffer = Chunk (S.copy bs) k+ | otherwise = Chunk bs k+ where+ bs = byteStringFromBuffer buffer+ loop cios+{-#INLINABLE toStreamingByteStringWith #-}+{-#SPECIALIZE toStreamingByteStringWith :: AllocationStrategy -> Builder -> ByteString IO () #-}+ + +{- Concatenate a stream of builders (not a streaming bytestring!) into a single builder.++>>> let aa = yield (integerDec 10000) >> yield (string8 " is a number.") >> yield (char8 '\n')+>>> hPutBuilder IO.stdout $ concatBuilders aa+10000 is a number.++-}+concatBuilders :: Stream (Of Builder) IO () -> Builder+concatBuilders p = builder $ \bstep r -> do + case p of+ Return _ -> runBuilderWith mempty bstep r+ Step (b :> rest) -> runBuilderWith (b `mappend` concatBuilders rest) bstep r + Delay m -> m >>= \p' -> runBuilderWith (concatBuilders p') bstep r+{-#INLINABLE concatBuilders #-}+++{-| A simple construction of a builder from a byte stream.++>>> let aaa = "10000 is a number\n" :: Q.ByteString IO ()+>>> hPutBuilder IO.stdout $ toBuilder aaa+10000 is a number+++-}+toBuilder :: ByteString IO () -> Builder+toBuilder = concatBuilders . SP.map byteString . toChunks+{-#INLINABLE toBuilder #-}
Data/ByteString/Streaming/Char8.hs view
@@ -82,6 +82,13 @@ , concat -- concat :: Monad m => Stream (ByteString m) m r -> ByteString m r + -- * Builders+ + , toStreamingByteString+ , toStreamingByteStringWith+ , toBuilder+ , concatBuilders+ -- * Building ByteStrings -- ** Infinite ByteStrings@@ -159,7 +166,8 @@ import Data.ByteString.Streaming (fromLazy, toLazy, toLazy', nextChunk, unconsChunk, fromChunks, toChunks, fromStrict, toStrict, toStrict', - concat, distribute, drain,+ concat, distribute, drain, toStreamingByteStringWith,+ toStreamingByteString, toBuilder, concatBuilders, empty, null, null', length, length', append, cycle, take, drop, splitAt, intercalate, group, denull, appendFile, stdout, stdin, fromHandle, toHandle,
streaming-bytestring.cabal view
@@ -1,5 +1,5 @@ name: streaming-bytestring-version: 0.1.0.3+version: 0.1.0.4 synopsis: effectful byte steams, or: lazy bytestring done right description: This is an implementation of effectful, memory-constrained bytestrings (byte streams) and functions for streaming @@ -33,12 +33,13 @@ . > data ByteString = Empty | Chunk Strict.ByteString ByteString .- with the minimal effectful variant+ with the /minimal/ effectful variant: . > data ByteString m r = Empty r | Chunk Strict.ByteString (ByteString m r) | Go (m (ByteString m r)) . (Constructors are necessarily hidden in internal modules in both cases.) - As a lazy bytestring is implemented internally + .+ That's it. As a lazy bytestring is implemented internally by a sort of list of strict bytestring chunks, a streaming bytestring is simply implemented as a /producer/ or /generator/ of strict bytestring chunks. Most operations are defined by simply adding a line to what we find in@@ -102,17 +103,17 @@ this library depends the @streaming@ library, which is used in place of @free@ to express the (streaming) splitting and division of byte streams. Those elementary concepts are catastrophically mishandled in the streaming io libraries - other than pipes; already the @enumerator@ and @iteratee@ libraries- were completely defeated by it: see e.g. the implementation of + other than pipes. Already the @enumerator@ and @iteratee@ libraries+ were completely defeated by it: see e.g. the @enumerator@ implementation of <http://hackage.haskell.org/package/enumerator-0.4.20/docs/Data-Enumerator-Text.html#v:splitWhen splitWhen and lines>. This will concatenate strict text forever, if that's what is coming- in.+ in. It becomes torture to express elementary distinctions. . Though we barely alter signatures in @Data.ByteString.Lazy@ - more than is required- by the types, the point of view that emerges is very much that of+ more than is required by the types, + the point of view that emerges is very much that of @pipes-bytestring@ and @pipes-group@. In particular- we have the correspondences:+ we have these correspondences: . > Lazy.splitAt :: Int -> ByteString -> (ByteString, ByteString) > Streaming.splitAt :: Int -> ByteString m r -> ByteString m (ByteString m r)@@ -163,4 +164,4 @@ -- hs-source-dirs: default-language: Haskell2010- -- ghc-options: -Wall+ ghc-options: -O2