io-streams 1.2.1.3 → 1.3.0.0
raw patch · 10 files changed
+179/−158 lines, 10 filesdep +bytestring-builderdep −blaze-builderPVP ok
version bump matches the API change (PVP)
Dependencies added: bytestring-builder
Dependencies removed: blaze-builder
API changes (from Hackage documentation)
- System.IO.Streams.Builder: builderStreamWith :: BufferAllocStrategy -> OutputStream ByteString -> IO (OutputStream Builder)
+ System.IO.Streams.Builder: builderStreamWithBufferSize :: Int -> OutputStream ByteString -> IO (OutputStream Builder)
+ System.IO.Streams.Core: writeTo :: OutputStream a -> Maybe a -> IO ()
+ System.IO.Streams.Internal: writeTo :: OutputStream a -> Maybe a -> IO ()
Files
- changelog.md +9/−0
- io-streams.cabal +30/−32
- src/System/IO/Streams/Builder.hs +88/−84
- src/System/IO/Streams/Core.hs +1/−0
- src/System/IO/Streams/Internal.hs +10/−0
- src/System/IO/Streams/Zlib.hs +12/−12
- test/System/IO/Streams/Tests/Builder.hs +20/−18
- test/System/IO/Streams/Tests/Concurrent.hs +1/−5
- test/System/IO/Streams/Tests/Handle.hs +3/−3
- test/System/IO/Streams/Tests/Zlib.hs +5/−4
changelog.md view
@@ -1,3 +1,12 @@+# Version 1.3.0.0+ - As long promised, removed the direct use of the `blaze-builder` package in+ favor of the new `bytestring-builder` transitional package (to be replaced+ by bytestring's native builder once it is mature enough).+ - Added a new convenience function, a flipped version of `write`:+ ```haskell+writeTo :: OutputStream a -> Maybe a -> IO ()+ ```+ # Version 1.2.1.3 - Dependency bump for primitive 0.6.
io-streams.cabal view
@@ -1,5 +1,5 @@ Name: io-streams-Version: 1.2.1.3+Version: 1.3.0.0 License: BSD3 License-file: LICENSE Category: Data, Network, IO-Streams@@ -7,8 +7,7 @@ Maintainer: Gregory Collins <greg@gregorycollins.net> Cabal-version: >= 1.10 Synopsis: Simple, composable, and easy-to-use stream I/O-Tested-With: GHC==7.8.4, GHC==7.8.2, GHC==7.6.2, GHC==7.6.1, GHC==7.4.2,- GHC==7.4.1, GHC==7.2.2, GHC==7.0.4+Tested-With: GHC==7.8.4, GHC==7.8.3, GHC==7.6.3, GHC==7.4.2 Bug-Reports: https://github.com/snapframework/io-streams/issues Description: /Overview/@@ -118,18 +117,18 @@ System.IO.Streams.Internal.Network, System.IO.Streams.Internal.Search - Build-depends: base >= 4 && <5,- attoparsec >= 0.10 && <0.13,- blaze-builder >= 0.3.1 && <0.4,- bytestring >= 0.9 && <0.11,- network >= 2.3 && <2.7,- primitive >= 0.2 && <0.7,- process >= 1.1 && <1.3,- text >= 0.10 && <1.3,- time >= 1.2 && <1.6,- transformers >= 0.2 && <0.5,- vector >= 0.7 && <0.11,- zlib-bindings >= 0.1 && <0.2+ Build-depends: base >= 4 && <5,+ attoparsec >= 0.10 && <0.13,+ bytestring >= 0.9 && <0.11,+ bytestring-builder >= 0.10 && <0.11,+ network >= 2.3 && <2.7,+ primitive >= 0.2 && <0.7,+ process >= 1.1 && <1.3,+ text >= 0.10 && <1.3,+ time >= 1.2 && <1.6,+ transformers >= 0.2 && <0.5,+ vector >= 0.7 && <0.11,+ zlib-bindings >= 0.1 && <0.2 if impl(ghc >= 7.2) other-extensions: Trustworthy@@ -199,23 +198,22 @@ if !os(windows) && !flag(NoInteractiveTests) cpp-options: -DENABLE_PROCESS_TESTS -- Build-depends: base >= 4 && <5,- attoparsec >= 0.10 && <0.13,- blaze-builder >= 0.3.1 && <0.4,- bytestring >= 0.9 && <0.11,- deepseq >= 1.2 && <1.5,- directory >= 1.1 && <2,- filepath >= 1.2 && <2,- mtl >= 2 && <3,- network >= 2.3 && <2.7,- primitive >= 0.2 && <0.7,- process >= 1 && <1.3,- text >= 0.10 && <1.3,- time >= 1.2 && <1.6,- transformers >= 0.2 && <0.5,- vector >= 0.7 && <0.11,- zlib-bindings >= 0.1 && <0.2,+ Build-depends: base >= 4 && <5,+ attoparsec >= 0.10 && <0.13,+ bytestring >= 0.9 && <0.11,+ bytestring-builder >= 0.10 && <0.11,+ deepseq >= 1.2 && <1.5,+ directory >= 1.1 && <2,+ filepath >= 1.2 && <2,+ mtl >= 2 && <3,+ network >= 2.3 && <2.7,+ primitive >= 0.2 && <0.7,+ process >= 1 && <1.3,+ text >= 0.10 && <1.3,+ time >= 1.2 && <1.6,+ transformers >= 0.2 && <0.5,+ vector >= 0.7 && <0.11,+ zlib-bindings >= 0.1 && <0.2, HUnit >= 1.2 && <2, QuickCheck >= 2.3.0.2 && <3,
src/System/IO/Streams/Builder.hs view
@@ -1,18 +1,20 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} -- | Buffering for output streams based on bytestring builders. -- -- Buffering an output stream can often improve throughput by reducing the--- number of system calls made through the file descriptor. The @blaze-builder@--- package provides an efficient set of primitives for serializing values--- directly to an output buffer.+-- number of system calls made through the file descriptor. The @bytestring@+-- package provides an efficient monoidal datatype used for serializing values+-- directly to an output buffer, called a 'Builder', originally implemented in+-- the @blaze-builder@ package by Simon Meier. When compiling with @bytestring@+-- versions older than 0.10.4, (i.e. GHC <= 7.6) users must depend on the+-- @bytestring-builder@ library to get the new builder implementation. Since we+-- try to maintain compatibility with the last three GHC versions, the+-- dependency on @bytestring-builder@ can be dropped after the release of GHC+-- 7.12. ----- (/N.B./: most of the @blaze-builder@ package has been moved into--- @bytestring@ in versions \>= 0.10; once two or three Haskell Platform--- editions have been released that contain @bytestring@ 0.10.2 or higher, the--- dependency on @blaze-builder@ will be dropped in favor of the native support--- for 'Builder' contained in the @bytestring@ package.) -- -- /Using this module/ --@@ -27,16 +29,16 @@ -- @ -- do -- newStream <- Streams.'builderStream' someOutputStream--- Streams.'write' ('Just' $ 'Blaze.ByteString.Builder.fromByteString' \"hello\") newStream+-- Streams.'write' ('Just' $ 'Data.ByteString.Builder.byteString' \"hello\") newStream -- .... -- @ -- ----- You can flush the output buffer using 'Blaze.ByteString.Builder.flush':+-- You can flush the output buffer using 'Data.ByteString.Builder.Extra.flush': -- -- @ -- ....--- Streams.'write' ('Just' 'Blaze.ByteString.Builder.flush') newStream+-- Streams.'write' ('Just' 'Data.ByteString.Builder.Extra.flush') newStream -- .... -- @ --@@ -53,7 +55,7 @@ -- example = do -- let l1 = 'Data.List.intersperse' \" \" [\"the\", \"quick\", \"brown\", \"fox\"] -- let l2 = 'Data.List.intersperse' \" \" [\"jumped\", \"over\", \"the\"]--- let l = map 'Blaze.ByteString.Builder.fromByteString' l1 ++ ['Blaze.ByteString.Builder.flush'] ++ map 'Blaze.ByteString.Builder.fromByteString' l2+-- let l = map 'Data.ByteString.Builder.byteString' l1 ++ ['Data.ByteString.Builder.Extra.flush'] ++ map 'Data.ByteString.Builder.byteString' l2 -- is \<- Streams.'System.IO.Streams.fromList' l -- (os0, grab) \<- Streams.'System.IO.Streams.listOutputStream' -- os \<- Streams.'builderStream' os0@@ -66,23 +68,83 @@ module System.IO.Streams.Builder ( -- * Blaze builder conversion builderStream+ , builderStreamWithBufferSize , unsafeBuilderStream- , builderStreamWith ) where -------------------------------------------------------------------------------import Control.Monad (when)-import Data.ByteString.Char8 (ByteString)-import qualified Data.ByteString.Char8 as S-import Data.IORef (newIORef, readIORef, writeIORef)+import Control.Monad (when)+import Data.ByteString.Builder.Internal (Buffer (..), BufferRange (..), Builder, byteStringFromBuffer, defaultChunkSize, fillWithBuildStep, newBuffer, runBuilder)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import Data.IORef (newIORef, readIORef, writeIORef)+ -------------------------------------------------------------------------------import Blaze.ByteString.Builder.Internal (defaultBufferSize)-import Blaze.ByteString.Builder.Internal.Buffer (Buffer, BufferAllocStrategy, allNewBuffersStrategy, execBuildStep, reuseBufferStrategy, unsafeFreezeBuffer, unsafeFreezeNonEmptyBuffer, updateEndOfSlice)-import Blaze.ByteString.Builder.Internal.Types (BufRange (..), BuildSignal (..), Builder (..), buildStep)-import System.IO.Streams.Internal (OutputStream, makeOutputStream, write)+import System.IO.Streams.Internal (OutputStream, makeOutputStream, write, writeTo) ------------------------------------------------------------------------------+builderStreamWithBufferFunc :: IO Buffer+ -> OutputStream ByteString+ -> IO (OutputStream Builder)+builderStreamWithBufferFunc mkNewBuf os = do+ ref <- newIORef Nothing+ makeOutputStream $ chunk ref+ where+ chunk ref Nothing = do+ mbuf <- readIORef ref+ case mbuf of+ -- If we existing buffer leftovers, write them to the output.+ Nothing -> return $! ()+ Just buf -> writeBuf buf+ write Nothing os+ chunk ref (Just builder) = runStep ref $ runBuilder builder++ getBuf ref = readIORef ref >>= maybe mkNewBuf return++ bumpBuf (Buffer fp (BufferRange !_ endBuf)) endPtr =+ Buffer fp (BufferRange endPtr endBuf)++ updateBuf ref buf endPtr = writeIORef ref $! Just $! bumpBuf buf endPtr++ writeBuf buf = do+ let bs = byteStringFromBuffer buf+ when (not . S.null $ bs) $ writeTo os $! Just bs++ bufRange (Buffer _ rng) = rng++ runStep ref step = do+ buf <- getBuf ref+ fillWithBuildStep step (cDone buf) (cFull buf) (cInsert buf)+ (bufRange buf)+ where+ cDone buf endPtr !() = updateBuf ref buf endPtr+ cFull buf !endPtr !_ newStep = do+ writeBuf $! bumpBuf buf endPtr+ writeIORef ref Nothing+ runStep ref newStep+ cInsert buf !endPtr !bs newStep = do+ writeBuf $! bumpBuf buf endPtr+ writeIORef ref Nothing+ writeTo os $! Just bs+ runStep ref newStep+++------------------------------------------------------------------------------+-- | Converts a 'ByteString' sink into a 'Builder' sink, using the supplied+-- buffer size.+--+-- Note that if the generated builder receives a+-- 'Blaze.ByteString.Builder.flush', by convention it will send an empty string+-- to the supplied @'OutputStream' 'ByteString'@ to indicate that any output+-- buffers are to be flushed.+--+-- /Since: 1.3.0.0./+builderStreamWithBufferSize :: Int -> OutputStream ByteString -> IO (OutputStream Builder)+builderStreamWithBufferSize bufsiz = builderStreamWithBufferFunc (newBuffer bufsiz)+++------------------------------------------------------------------------------ -- | Converts a 'ByteString' sink into a 'Builder' sink. -- -- Note that if the generated builder receives a@@ -91,7 +153,7 @@ -- buffers are to be flushed. -- builderStream :: OutputStream ByteString -> IO (OutputStream Builder)-builderStream = builderStreamWith (allNewBuffersStrategy defaultBufferSize)+builderStream = builderStreamWithBufferSize defaultChunkSize ------------------------------------------------------------------------------@@ -108,69 +170,11 @@ -- 'Data.ByteString.copy' to ensure that you have a fresh copy of the -- underlying string. ----- You can create a Buffer with--- 'Blaze.ByteString.Builder.Internal.Buffer.allocBuffer'.---+-- You can create a Buffer with 'Data.ByteString.Builder.Internal.newBuffer'. -- unsafeBuilderStream :: IO Buffer -> OutputStream ByteString -> IO (OutputStream Builder)-unsafeBuilderStream = builderStreamWith . reuseBufferStrategy------------------------------------------------------------------------------------ | A customized version of 'builderStream', using the specified--- 'BufferAllocStrategy'.-builderStreamWith :: BufferAllocStrategy- -> OutputStream ByteString- -> IO (OutputStream Builder)-builderStreamWith (ioBuf0, nextBuf) os = do- bufRef <- newIORef ioBuf0- makeOutputStream $ sink bufRef- where- sink bufRef m = do- buf <- readIORef bufRef- maybe (eof buf) (chunk buf) m- where- eof ioBuf = do- buf <- ioBuf- case unsafeFreezeNonEmptyBuffer buf of- Nothing -> write Nothing os- x@(Just s) -> do- when (not $ S.null s) $ write x os- write Nothing os-- chunk ioBuf c = feed bufRef (unBuilder c (buildStep finalStep)) ioBuf-- finalStep !(BufRange pf _) = return $! Done pf $! ()-- feed bufRef bStep ioBuf = do- !buf <- ioBuf- signal <- execBuildStep bStep buf-- case signal of- Done op' _ ->- writeIORef bufRef $ (return (updateEndOfSlice buf op'))-- BufferFull minSize op' bStep' -> do- let buf' = updateEndOfSlice buf op'- {-# INLINE cont #-}- cont = do- ioBuf' <- nextBuf minSize buf'- feed bufRef bStep' ioBuf'-- write (Just $! unsafeFreezeBuffer buf') os- cont-- InsertByteString op' bs bStep' -> do- let buf' = updateEndOfSlice buf op'-- case unsafeFreezeNonEmptyBuffer buf' of- Nothing -> return $! ()- x -> write x os-- -- empty string here notifies downstream of flush- write (Just bs) os-- ioBuf' <- nextBuf 1 buf'- feed bufRef bStep' ioBuf'+unsafeBuilderStream mkBuf os = do+ buf <- mkBuf+ builderStreamWithBufferFunc (return buf) os
src/System/IO/Streams/Core.hs view
@@ -17,6 +17,7 @@ , unRead , peek , write+ , writeTo , atEOF -- * Connecting streams together
src/System/IO/Streams/Internal.hs view
@@ -27,6 +27,7 @@ , unRead , peek , write+ , writeTo , atEOF -- * Building streams@@ -146,6 +147,15 @@ write :: Maybe a -> OutputStream a -> IO () write = flip _write {-# INLINE write #-}+++------------------------------------------------------------------------------+-- | Flipped version of 'write'.+--+-- /Since: 1.3.0.0./+writeTo :: OutputStream a -> Maybe a -> IO ()+writeTo = _write+{-# INLINE writeTo #-} ------------------------------------------------------------------------------
src/System/IO/Streams/Zlib.hs view
@@ -18,18 +18,18 @@ ) where -------------------------------------------------------------------------------import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import Data.IORef (newIORef, readIORef, writeIORef)-import Prelude hiding (read)+import Data.ByteString (ByteString)+import qualified Data.ByteString as S+import Data.IORef (newIORef, readIORef, writeIORef)+import Prelude hiding (read) -------------------------------------------------------------------------------import Blaze.ByteString.Builder (fromByteString)-import Blaze.ByteString.Builder.Internal (Builder, defaultBufferSize, flush)-import Blaze.ByteString.Builder.Internal.Buffer (allocBuffer)-import Codec.Zlib (Deflate, Inflate, Popper, WindowBits (..), feedDeflate, feedInflate, finishDeflate, finishInflate, flushDeflate, flushInflate, initDeflate, initInflate)+import Codec.Zlib (Deflate, Inflate, Popper, WindowBits (..), feedDeflate, feedInflate, finishDeflate, finishInflate, flushDeflate, flushInflate, initDeflate, initInflate)+import Data.ByteString.Builder (Builder, byteString)+import Data.ByteString.Builder.Extra (defaultChunkSize, flush)+import Data.ByteString.Builder.Internal (newBuffer) -------------------------------------------------------------------------------import System.IO.Streams.Builder (unsafeBuilderStream)-import System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, read, write)+import System.IO.Streams.Builder (unsafeBuilderStream)+import System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, read, write) ------------------------------------------------------------------------------@@ -105,13 +105,13 @@ -- we can use unsafeBuilderStream here because zlib is going to consume the -- stream- unsafeBuilderStream (allocBuffer defaultBufferSize) zippedStr+ unsafeBuilderStream (newBuffer defaultChunkSize) zippedStr where bytestringStream x = write (fmap cvt x) stream cvt s | S.null s = flush- | otherwise = fromByteString s+ | otherwise = byteString s ------------------------------------------------------------------------------
test/System/IO/Streams/Tests/Builder.hs view
@@ -3,17 +3,19 @@ module System.IO.Streams.Tests.Builder (tests) where -------------------------------------------------------------------------------import Blaze.ByteString.Builder-import Blaze.ByteString.Builder.Internal.Buffer import Control.Monad-import qualified Data.ByteString.Char8 as S+import Data.ByteString.Builder (byteString, toLazyByteString)+import Data.ByteString.Builder.Extra (flush)+import Data.ByteString.Builder.Internal (newBuffer)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L import Data.List import Data.Monoid-import System.IO.Streams hiding (fromByteString, intersperse, map, take)-import qualified System.IO.Streams as Streams+import System.IO.Streams hiding (intersperse, map, take)+import qualified System.IO.Streams as Streams import Test.Framework import Test.Framework.Providers.HUnit-import Test.HUnit hiding (Test)+import Test.HUnit hiding (Test) ------------------------------------------------------------------------------ tests :: [Test]@@ -31,7 +33,7 @@ testBuilderStream = testCase "builder/builderStream" $ do let l1 = intersperse " " ["the", "quick", "brown", "fox"] let l2 = intersperse " " ["jumped", "over", "the"]- let l = map fromByteString l1 ++ [flush] ++ map fromByteString l2+ let l = map byteString l1 ++ [flush] ++ map byteString l2 is <- fromList l (os0, grab) <- listOutputStream@@ -53,9 +55,9 @@ (os0, grab) <- Streams.listOutputStream os <- Streams.builderStream os0 is0 <- Streams.fromList ["Hello, world!\n"]- >>= Streams.map fromByteString+ >>= Streams.map byteString is1 <- Streams.fromList ["Bye, world!\n"]- >>= Streams.map fromByteString+ >>= Streams.map byteString Streams.connect is0 os Streams.connect is1 os Streams.write Nothing os@@ -68,13 +70,13 @@ testUnsafeBuilderStream = testCase "builder/unsafeBuilderStream" $ do let l1 = intersperse " " ["the", "quick", "brown", "fox"] let l2 = intersperse " " ["jumped", "over", "the"]- let l = map fromByteString l1 ++ [flush] ++ map fromByteString l2+ let l = map byteString l1 ++ [flush] ++ map byteString l2 is <- fromList l (os0, grab) <- listOutputStream os1 <- contramapM (return . S.copy) os0 - os <- unsafeBuilderStream (allocBuffer 1024) os1+ os <- unsafeBuilderStream (newBuffer 1024) os1 connect is os output <- grab@@ -89,11 +91,11 @@ testSmallBuffer :: Test testSmallBuffer = testCase "builder/smallBuffer" $ do (os0, grab) <- listOutputStream- os <- builderStreamWith (allNewBuffersStrategy 10) os0+ os <- builderStreamWithBufferSize 10 os0 let l1 = intersperse " " ["the", "quick", "brown"] let l2 = [" fooooooooooooooooox"]- let l = map fromByteString l1 ++ [flush, flush, flush]- ++ map fromByteString l2+ let l = map byteString l1 ++ [flush, flush, flush]+ ++ map byteString l2 is <- fromList l connect is os@@ -108,20 +110,20 @@ testCase "builder/smallBufferWithLargeOutput" $ do (os0, grab) <- listOutputStream os1 <- contramapM (return . S.copy) os0- os <- unsafeBuilderStream (allocBuffer 10) os1+ os <- unsafeBuilderStream (newBuffer 10) os1 let l = take 3000 $ cycle $- replicate 20 (fromByteString "bloooooooort") ++ [flush]+ replicate 20 (byteString "bloooooooort") ++ [flush] is <- fromList l- let s = toByteString $ mconcat l+ let s = S.concat $ L.toChunks $ toLazyByteString $ mconcat l connect is os output <- liftM S.concat grab assertEqual "short buffer 2" s output - write (Just $ fromByteString "ok") os+ write (Just $ byteString "ok") os write Nothing os fout <- grab
test/System/IO/Streams/Tests/Concurrent.hs view
@@ -3,11 +3,7 @@ ------------------------------------------------------------------------------ import Control.Concurrent import Control.Monad-import Prelude hiding (lines, read,- takeWhile, unlines,- unwords, unwords,- words)-import qualified Prelude+import Prelude hiding (lines, read, takeWhile, unlines, unwords, unwords, words) import qualified System.IO.Streams as Streams import qualified System.IO.Streams.Concurrent as Streams import System.IO.Streams.Tests.Common
test/System/IO/Streams/Tests/Handle.hs view
@@ -4,9 +4,9 @@ module System.IO.Streams.Tests.Handle (tests) where -------------------------------------------------------------------------------import Blaze.ByteString.Builder import Control.Exception import Control.Monad hiding (mapM)+import Data.ByteString.Builder (byteString) import qualified Data.ByteString.Char8 as S import Data.List import Foreign.Marshal.Alloc (allocaBytes)@@ -76,8 +76,8 @@ os0 <- Streams.handleToOutputStream h os <- Streams.builderStream os0 - let l1 = map fromByteString ["the ", "quick ", "brown "]- let l2 = map fromByteString ["fox ", "jumped"]+ let l1 = map byteString ["the ", "quick ", "brown "]+ let l2 = map byteString ["fox ", "jumped"] Streams.fromList l1 >>= Streams.connectTo os Streams.fromList l2 >>= Streams.connectTo os S.readFile fn >>= assertEqual "eof should close" "the quick brown "
test/System/IO/Streams/Tests/Zlib.hs view
@@ -3,10 +3,11 @@ module System.IO.Streams.Tests.Zlib (tests) where -------------------------------------------------------------------------------import Blaze.ByteString.Builder import qualified Codec.Compression.GZip as GZ import qualified Codec.Compression.Zlib as Z import Control.Monad hiding (mapM)+import Data.ByteString.Builder (Builder, byteString)+import Data.ByteString.Builder.Extra (flush) import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as S import qualified Data.ByteString.Lazy.Char8 as L@@ -18,7 +19,7 @@ import Test.QuickCheck hiding (output) import Test.QuickCheck.Monadic -------------------------------------------------------------------------------import System.IO.Streams hiding (fromByteString)+import System.IO.Streams import System.IO.Streams.Tests.Common tests :: [Test]@@ -153,10 +154,10 @@ propBuilderFlush name inf comp a b = do pre (not (S.null a) && not (S.null b)) liftQ $ do- t 7 [ fromByteString a, flush, flush, fromByteString b+ t 7 [ byteString a, flush, flush, byteString b , flush, flush ] - t 4 [ fromByteString a, flush, flush, fromByteString b ]+ t 4 [ byteString a, flush, flush, byteString b ] where t expected input = do