io-streams 1.3.6.1 → 1.5.2.2
raw patch · 24 files changed
Files
- CONTRIBUTORS +1/−0
- changelog.md +29/−0
- io-streams.cabal +81/−40
- src/System/IO/Streams.hs +10/−0
- src/System/IO/Streams/Attoparsec.hs +4/−3
- src/System/IO/Streams/Attoparsec/ByteString.hs +75/−0
- src/System/IO/Streams/Attoparsec/Text.hs +76/−0
- src/System/IO/Streams/ByteString.hs +8/−10
- src/System/IO/Streams/Combinators.hs +15/−0
- src/System/IO/Streams/Concurrent.hs +8/−3
- src/System/IO/Streams/Core.hs +2/−0
- src/System/IO/Streams/Internal.hs +28/−15
- src/System/IO/Streams/Internal/Attoparsec.hs +38/−75
- src/System/IO/Streams/Vector.hs +15/−4
- test/System/IO/Streams/Tests/Attoparsec.hs +0/−112
- test/System/IO/Streams/Tests/Attoparsec/ByteString.hs +113/−0
- test/System/IO/Streams/Tests/Attoparsec/Text.hs +140/−0
- test/System/IO/Streams/Tests/ByteString.hs +5/−9
- test/System/IO/Streams/Tests/Combinators.hs +21/−0
- test/System/IO/Streams/Tests/Concurrent.hs +1/−1
- test/System/IO/Streams/Tests/Handle.hs +24/−15
- test/System/IO/Streams/Tests/Network.hs +26/−8
- test/System/IO/Streams/Tests/Process.hs +1/−1
- test/TestSuite.hs +29/−17
CONTRIBUTORS view
@@ -3,6 +3,7 @@ - Gregory Collins <greg@gregorycollins.net> - Gabriel Gonzalez <gabriel439@gmail.com>+ - Ignat Insarov <kindaro@gmail.com> ------------------------------------------------------------------------------ Contains some code ported from the "blaze-builder-enumerator" package by Simon
changelog.md view
@@ -1,3 +1,32 @@+# Version 1.5.2.0+- Add `contraunzip`.++- Guard support for `network` and `zlib` by cabal flags, to support platforms+ like GHCJS where they are not available.++# Version 1.5.1.0+Fix [stackage#4312](https://github.com/commercialhaskell/stackage/issues/4312): Relax `network` upper bound++# Version 1.5.0.1+Bugfix: `concurrentMerge []` should not block forever, even if this case is+pathological.++# Version 1.5.0.0+- Changed the behaviour of `ByteString.splitOn` to not emit empty string if the+ input ends in the delimiter; now `lines` should match Prelude's. Bumped major+ version because this is a potentially breaking change (even if it is a bugfix.)++# Version 1.4.1.0++- Added `writeTo` export to the main module (forgotten when it was added to+ `.Core`.)++# Version 1.4.0.0++- Added support for Text with Attoparsec, courtesy Kevin Brubeck Unhammer. Adds+ modules `System.IO.Streams.Attoparsec.{ByteString, Text}` and deprecates+ `System.IO.Streams.Attoparsec`, which is now a thin wrapper.+ # Version 1.3.6.1 - Bumped dependencies on `time` and `process`.
io-streams.cabal view
@@ -1,5 +1,5 @@ Name: io-streams-Version: 1.3.6.1+Version: 1.5.2.2 License: BSD3 License-file: LICENSE Category: Data, Network, IO-Streams@@ -7,7 +7,21 @@ 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.3, GHC==7.6.3, GHC==7.4.2+Tested-With:+ GHC == 9.4.1+ GHC == 9.2.4+ GHC == 9.0.2+ GHC == 8.10.7+ GHC == 8.8.4+ GHC == 8.6.5+ GHC == 8.4.4+ GHC == 8.2.2+ GHC == 8.0.2+ GHC == 7.10.3+ GHC == 7.8.4+ GHC == 7.6.3+ GHC == 7.4.2+ Bug-Reports: https://github.com/snapframework/io-streams/issues Description: /Overview/@@ -84,6 +98,16 @@ Description: Do not run interactive tests Default: False +Flag Zlib+ Description: Include zlib support+ Default: True+ Manual: True++Flag Network+ Description: Include network support+ Default: True+ Manual: True+ ------------------------------------------------------------------------------ Library hs-source-dirs: src@@ -92,10 +116,10 @@ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -fno-warn-unused-do-bind - ghc-prof-options: -auto-all- Exposed-modules: System.IO.Streams, System.IO.Streams.Attoparsec,+ System.IO.Streams.Attoparsec.ByteString,+ System.IO.Streams.Attoparsec.Text, System.IO.Streams.Builder, System.IO.Streams.ByteString, System.IO.Streams.Combinators,@@ -105,34 +129,42 @@ System.IO.Streams.Handle, System.IO.Streams.File, System.IO.Streams.List,- System.IO.Streams.Network, System.IO.Streams.Process, System.IO.Streams.Text, System.IO.Streams.Vector,- System.IO.Streams.Zlib, System.IO.Streams.Internal, System.IO.Streams.Tutorial Other-modules: System.IO.Streams.Internal.Attoparsec,- System.IO.Streams.Internal.Network, System.IO.Streams.Internal.Search Build-depends: base >= 4 && <5,- attoparsec >= 0.10 && <0.14,- bytestring >= 0.9 && <0.11,- bytestring-builder >= 0.10 && <0.11,- network >= 2.3 && <2.7,- primitive >= 0.2 && <0.7,+ attoparsec >= 0.10 && <0.15,+ bytestring >= 0.9 && <0.12,+ primitive >= 0.2 && <0.8, process >= 1.1 && <1.7,- text >= 0.10 && <1.3,- time >= 1.2 && <1.9,- transformers >= 0.2 && <0.6,- vector >= 0.7 && <0.13,- zlib-bindings >= 0.1 && <0.2+ text >=0.10 && <1.3 || >= 2.0 && <2.1,+ time >= 1.2 && <1.13,+ transformers >= 0.2 && <0.7,+ vector >= 0.7 && <0.14 + if !impl(ghc >= 7.8)+ Build-depends: bytestring-builder >= 0.10 && <0.11+ if impl(ghc >= 7.2) other-extensions: Trustworthy + if flag(Zlib)+ Exposed-modules: System.IO.Streams.Zlib+ Build-depends: zlib-bindings >= 0.1 && <0.2+ cpp-options: -DENABLE_ZLIB++ if flag(Network)+ Exposed-modules: System.IO.Streams.Network+ Other-modules: System.IO.Streams.Internal.Network+ Build-depends: network >= 2.3 && <3.2+ cpp-options: -DENABLE_NETWORK+ other-extensions: BangPatterns, CPP,@@ -153,7 +185,8 @@ Main-is: TestSuite.hs Default-language: Haskell2010 - Other-modules: System.IO.Streams.Tests.Attoparsec,+ Other-modules: System.IO.Streams.Tests.Attoparsec.ByteString,+ System.IO.Streams.Tests.Attoparsec.Text, System.IO.Streams.Tests.Builder, System.IO.Streams.Tests.ByteString, System.IO.Streams.Tests.Combinators,@@ -164,13 +197,12 @@ System.IO.Streams.Tests.Handle, System.IO.Streams.Tests.Internal, System.IO.Streams.Tests.List,- System.IO.Streams.Tests.Network, System.IO.Streams.Tests.Process, System.IO.Streams.Tests.Text, System.IO.Streams.Tests.Vector,- System.IO.Streams.Tests.Zlib, System.IO.Streams,- System.IO.Streams.Attoparsec,+ System.IO.Streams.Attoparsec.ByteString,+ System.IO.Streams.Attoparsec.Text, System.IO.Streams.Builder, System.IO.Streams.ByteString, System.IO.Streams.Combinators,@@ -180,47 +212,56 @@ System.IO.Streams.Handle, System.IO.Streams.File, System.IO.Streams.List,- System.IO.Streams.Network, System.IO.Streams.Process, System.IO.Streams.Text, System.IO.Streams.Vector,- System.IO.Streams.Zlib, System.IO.Streams.Internal, System.IO.Streams.Internal.Attoparsec,- System.IO.Streams.Internal.Network, System.IO.Streams.Internal.Search - ghc-options: -Wall -fhpc -fwarn-tabs -funbox-strict-fields -threaded+ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -threaded -fno-warn-unused-do-bind- ghc-prof-options: -auto-all if !os(windows) && !flag(NoInteractiveTests) cpp-options: -DENABLE_PROCESS_TESTS - Build-depends: base >= 4 && <5,- attoparsec >= 0.10 && <0.14,- bytestring >= 0.9 && <0.11,- bytestring-builder >= 0.10 && <0.11,+ if flag(Zlib)+ Other-modules: System.IO.Streams.Tests.Zlib,+ System.IO.Streams.Zlib+ Build-depends: zlib-bindings,+ zlib >= 0.5 && <0.7+ cpp-options: -DENABLE_ZLIB++ if flag(Network)+ Other-modules: System.IO.Streams.Internal.Network,+ System.IO.Streams.Network,+ System.IO.Streams.Tests.Network+ Build-depends: network+ cpp-options: -DENABLE_NETWORK++ Build-depends: base,+ attoparsec,+ bytestring, 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 && <1.7,- text >= 0.10 && <1.3,- time >= 1.2 && <1.9,- transformers >= 0.2 && <0.6,- vector >= 0.7 && <0.13,- zlib-bindings >= 0.1 && <0.2,+ primitive,+ process,+ text,+ time,+ transformers,+ vector, HUnit >= 1.2 && <2, QuickCheck >= 2.3.0.2 && <3, test-framework >= 0.6 && <0.9, test-framework-hunit >= 0.2.7 && <0.4,- test-framework-quickcheck2 >= 0.2.12.1 && <0.4,- zlib >= 0.5 && <0.7+ test-framework-quickcheck2 >= 0.2.12.1 && <0.4++ if !impl(ghc >= 7.8)+ Build-depends: bytestring-builder if impl(ghc >= 7.2) other-extensions: Trustworthy
src/System/IO/Streams.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} @@ -34,6 +35,7 @@ , unRead , peek , write+ , writeTo , atEOF -- * Connecting streams together@@ -65,11 +67,15 @@ , module System.IO.Streams.Handle , module System.IO.Streams.File , module System.IO.Streams.List+#ifdef ENABLE_NETWORK , module System.IO.Streams.Network+#endif , module System.IO.Streams.Process , module System.IO.Streams.Text , module System.IO.Streams.Vector+#ifdef ENABLE_ZLIB , module System.IO.Streams.Zlib+#endif ) where ------------------------------------------------------------------------------@@ -84,11 +90,15 @@ import System.IO.Streams.File import System.IO.Streams.Handle import System.IO.Streams.List+#ifdef ENABLE_NETWORK import System.IO.Streams.Network+#endif import System.IO.Streams.Process import System.IO.Streams.Text import System.IO.Streams.Vector+#ifdef ENABLE_ZLIB import System.IO.Streams.Zlib+#endif ------------------------------------------------------------------------------ -- $generator
src/System/IO/Streams/Attoparsec.hs view
@@ -1,5 +1,6 @@--- | This module provides support for parsing values from 'InputStream's using--- @attoparsec@.+-- | This module is deprecated -- use+-- System.IO.Streams.Attoparsec.ByteString instead (this module simply+-- re-exports that one). module System.IO.Streams.Attoparsec ( -- * Parsing@@ -9,4 +10,4 @@ ) where -------------------------------------------------------------------------------import System.IO.Streams.Internal.Attoparsec (ParseException (..), parseFromStream, parserToInputStream)+import System.IO.Streams.Attoparsec.ByteString (ParseException (..), parseFromStream, parserToInputStream)
+ src/System/IO/Streams/Attoparsec/ByteString.hs view
@@ -0,0 +1,75 @@+-- | This module provides support for parsing values from ByteString+-- 'InputStream's using @attoparsec@. /Since: 1.4.0.0./++module System.IO.Streams.Attoparsec.ByteString+ ( -- * Parsing+ parseFromStream+ , parserToInputStream+ , ParseException(..)+ ) where++------------------------------------------------------------------------------+import Data.Attoparsec.ByteString.Char8 (Parser)+import Data.ByteString (ByteString)+------------------------------------------------------------------------------+import System.IO.Streams.Internal (InputStream)+import qualified System.IO.Streams.Internal as Streams+import System.IO.Streams.Internal.Attoparsec (ParseData (..), ParseException (..), parseFromStreamInternal)++------------------------------------------------------------------------------+-- | Supplies an @attoparsec@ 'Parser' with an 'InputStream', returning the+-- final parsed value or throwing a 'ParseException' if parsing fails.+--+-- 'parseFromStream' consumes only as much input as necessary to satisfy the+-- 'Parser': any unconsumed input is pushed back onto the 'InputStream'.+--+-- If the 'Parser' exhausts the 'InputStream', the end-of-stream signal is sent+-- to attoparsec.+--+-- Example:+--+-- @+-- ghci> import "Data.Attoparsec.ByteString.Char8"+-- ghci> is <- 'System.IO.Streams.fromList' [\"12345xxx\" :: 'ByteString']+-- ghci> 'parseFromStream' ('Data.Attoparsec.ByteString.Char8.takeWhile' 'Data.Attoparsec.ByteString.Char8.isDigit') is+-- \"12345\"+-- ghci> 'System.IO.Streams.read' is+-- Just \"xxx\"+-- @+parseFromStream :: Parser r+ -> InputStream ByteString+ -> IO r+parseFromStream = parseFromStreamInternal parse feed++------------------------------------------------------------------------------+-- | Given a 'Parser' yielding values of type @'Maybe' r@, transforms an+-- 'InputStream' over byte strings to an 'InputStream' yielding values of type+-- @r@.+--+-- If the parser yields @Just x@, then @x@ will be passed along downstream, and+-- if the parser yields @Nothing@, that will be interpreted as end-of-stream.+--+-- Upon a parse error, 'parserToInputStream' will throw a 'ParseException'.+--+-- Example:+--+-- @+-- ghci> import "Control.Applicative"+-- ghci> import "Data.Attoparsec.ByteString.Char8"+-- ghci> is <- 'System.IO.Streams.fromList' [\"1 2 3 4 5\" :: 'ByteString']+-- ghci> let parser = ('Data.Attoparsec.ByteString.Char8.endOfInput' >> 'Control.Applicative.pure' 'Nothing') \<|\> (Just \<$\> ('Data.Attoparsec.ByteString.Char8.skipWhile' 'Data.Attoparsec.ByteString.Char8.isSpace' *> 'Data.Attoparsec.ByteString.Char8.decimal'))+-- ghci> 'parserToInputStream' parser is >>= 'System.IO.Streams.toList'+-- [1,2,3,4,5]+-- ghci> is' \<- 'System.IO.Streams.fromList' [\"1 2xx3 4 5\" :: 'ByteString'] >>= 'parserToInputStream' parser+-- ghci> 'read' is'+-- Just 1+-- ghci> 'read' is'+-- Just 2+-- ghci> 'read' is'+-- *** Exception: Parse exception: Failed reading: takeWhile1+-- @+parserToInputStream :: Parser (Maybe r)+ -> InputStream ByteString+ -> IO (InputStream r)+parserToInputStream = (Streams.makeInputStream .) . parseFromStream+{-# INLINE parserToInputStream #-}
+ src/System/IO/Streams/Attoparsec/Text.hs view
@@ -0,0 +1,76 @@+-- | This module provides support for parsing values from Text+-- 'InputStream's using @attoparsec@. /Since: 1.4.0.0./++module System.IO.Streams.Attoparsec.Text+ ( -- * Parsing+ parseFromStream+ , parserToInputStream+ , ParseException(..)+ ) where++------------------------------------------------------------------------------+import Data.Attoparsec.Text (Parser)+import Data.Text (Text)+------------------------------------------------------------------------------+import System.IO.Streams.Internal (InputStream)+import qualified System.IO.Streams.Internal as Streams+import System.IO.Streams.Internal.Attoparsec (ParseData (..), ParseException (..), parseFromStreamInternal)+++------------------------------------------------------------------------------+-- | Supplies an @attoparsec@ 'Parser' with an 'InputStream', returning the+-- final parsed value or throwing a 'ParseException' if parsing fails.+--+-- 'parseFromStream' consumes only as much input as necessary to satisfy the+-- 'Parser': any unconsumed input is pushed back onto the 'InputStream'.+--+-- If the 'Parser' exhausts the 'InputStream', the end-of-stream signal is sent+-- to attoparsec.+--+-- Example:+--+-- @+-- ghci> import "Data.Attoparsec.Text"+-- ghci> is <- 'System.IO.Streams.fromList' [\"12345xxx\" :: 'Text']+-- ghci> 'parseFromStream' ('Data.Attoparsec.Text.takeWhile' 'Data.Char.isDigit') is+-- \"12345\"+-- ghci> 'System.IO.Streams.read' is+-- Just \"xxx\"+-- @+parseFromStream :: Parser r+ -> InputStream Text+ -> IO r+parseFromStream = parseFromStreamInternal parse feed++------------------------------------------------------------------------------+-- | Given a 'Parser' yielding values of type @'Maybe' r@, transforms an+-- 'InputStream' over byte strings to an 'InputStream' yielding values of type+-- @r@.+--+-- If the parser yields @Just x@, then @x@ will be passed along downstream, and+-- if the parser yields @Nothing@, that will be interpreted as end-of-stream.+--+-- Upon a parse error, 'parserToInputStream' will throw a 'ParseException'.+--+-- Example:+--+-- @+-- ghci> import "Control.Applicative"+-- ghci> import "Data.Attoparsec.Text"+-- ghci> is <- 'System.IO.Streams.fromList' [\"1 2 3 4 5\" :: 'Text']+-- ghci> let parser = ('Data.Attoparsec.Text.endOfInput' >> 'Control.Applicative.pure' 'Nothing') \<|\> (Just \<$\> ('Data.Attoparsec.Text.skipWhile' 'Data.Attoparsec.Text.isSpace' *> 'Data.Attoparsec.Text.decimal'))+-- ghci> 'parserToInputStream' parser is >>= 'System.IO.Streams.toList'+-- [1,2,3,4,5]+-- ghci> is' \<- 'System.IO.Streams.fromList' [\"1 2xx3 4 5\" :: 'Text'] >>= 'parserToInputStream' parser+-- ghci> 'read' is'+-- Just 1+-- ghci> 'read' is'+-- Just 2+-- ghci> 'read' is'+-- *** Exception: Parse exception: Failed reading: takeWhile1+-- @+parserToInputStream :: Parser (Maybe r)+ -> InputStream Text+ -> IO (InputStream r)+parserToInputStream = (Streams.makeInputStream .) . parseFromStream+{-# INLINE parserToInputStream #-}
src/System/IO/Streams/ByteString.hs view
@@ -61,7 +61,7 @@ import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Typeable (Typeable)-import Prelude hiding (read, lines, unlines, words, unwords)+import Prelude hiding (lines, read, unlines, unwords, words) ------------------------------------------------------------------------------ import System.IO.Streams.Combinators (filterM, intersperse, outputFoldM) import System.IO.Streams.Internal (InputStream (..), OutputStream, makeInputStream, makeOutputStream, read, unRead, write)@@ -272,6 +272,10 @@ -- -- * consecutive delimiters are not merged. --+-- * if the input ends in the delimiter, a final empty string is /not/+-- emitted. (/Since: 1.5.0.0. Previous versions had the opposite behaviour,+-- which was changed to match 'Prelude.lines'./)+-- -- Example: -- -- @@@ -305,15 +309,9 @@ else do let !b' = S.unsafeDrop 1 b dl <- readIORef ref-- if S.null b'- then do- writeIORef ref ("" :)- return $ Just $! S.concat $ dl [a]- else do- writeIORef ref id- unRead b' is- return $ Just $! S.concat $ dl [a]+ when (not $ S.null b') $ unRead b' is+ writeIORef ref id+ return $ Just $! S.concat $ dl [a] ------------------------------------------------------------------------------
src/System/IO/Streams/Combinators.hs view
@@ -47,6 +47,7 @@ , zipWith , zipWithM , unzip+ , contraunzip -- * Utility , intersperse@@ -748,6 +749,20 @@ let (a, b) = proj x modifyIORef buf (. (b:)) return $! Just a)+++------------------------------------------------------------------------------+-- | Given two 'OutputStream's, returns a new stream that "unzips" the tuples+-- being written, writing the two elements to the corresponding given streams.+--+-- You can use this together with @'contramap' (\\ x -> (x, x))@ to "fork" a+-- stream into two.+--+-- /Since: 1.5.2.0/+contraunzip :: OutputStream a -> OutputStream b -> IO (OutputStream (a, b))+contraunzip sink1 sink2 = makeOutputStream $ \ tuple -> do+ write (fmap fst tuple) sink1+ write (fmap snd tuple) sink2 ------------------------------------------------------------------------------
src/System/IO/Streams/Concurrent.hs view
@@ -23,7 +23,7 @@ import Control.Monad (forM_) import Prelude hiding (read) -------------------------------------------------------------------------------import System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, read)+import System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, nullInput, read) ------------------------------------------------------------------------------@@ -60,9 +60,14 @@ -- produced stream does not yield end-of-stream until all of the input streams -- have finished. ----- This traps exceptions in each concurrent thread and re-raises them in the--- current thread.+-- Any exceptions raised in one of the worker threads will be trapped and+-- re-raised in the current thread.+--+-- If the supplied list is empty, `concurrentMerge` will return an empty+-- stream. (/Since: 1.5.0.1/)+-- concurrentMerge :: [InputStream a] -> IO (InputStream a)+concurrentMerge [] = nullInput concurrentMerge iss = do mv <- newEmptyMVar nleft <- newMVar $! length iss
src/System/IO/Streams/Core.hs view
@@ -25,6 +25,8 @@ , connectTo , supply , supplyTo+ , appendInputStream+ , concatInputStreams -- * Thread safety \/ concurrency , lockingInputStream
src/System/IO/Streams/Internal.hs view
@@ -442,37 +442,50 @@ ------------------------------------------------------------------------------+#if MIN_VERSION_base(4,15,0)+ignoreOffset :: (a -> ptr -> n -> ioint) -> a -> ptr -> off -> n -> ioint+ignoreOffset f a ptr _ n = f a ptr n+#else+ignoreOffset :: a -> a+ignoreOffset = id+#endif+{-# INLINE ignoreOffset #-}++------------------------------------------------------------------------------+-- | The offset argument is ignored if present. instance H.RawIO (InputStream ByteString) where- read is ptr n = read is >>= maybe (return 0) f- where- f s = S.unsafeUseAsCStringLen s $ \(cstr, l) -> do+ read = ignoreOffset $ \is ptr n ->+ let f s = S.unsafeUseAsCStringLen s $ \(cstr, l) -> do let c = min n l copyBytes ptr (castPtr cstr) c return $! c+ in read is >>= maybe (return 0) f - readNonBlocking _ _ _ = unsupported- write _ _ _ = unsupported- writeNonBlocking _ _ _ = unsupported+ readNonBlocking = ignoreOffset $ \_ _ _ -> unsupported+ write = ignoreOffset $ \_ _ _ -> unsupported+ writeNonBlocking = ignoreOffset $ \_ _ _ -> unsupported ------------------------------------------------------------------------------+-- | The offset argument is ignored if present. instance H.RawIO (OutputStream ByteString) where- read _ _ _ = unsupported- readNonBlocking _ _ _ = unsupported- write os ptr n = S.packCStringLen (castPtr ptr, n) >>=- flip write os . Just- writeNonBlocking _ _ _ = unsupported+ read = ignoreOffset $ \_ _ _ -> unsupported+ readNonBlocking = ignoreOffset $ \_ _ _ -> unsupported+ write = ignoreOffset $ \os ptr n -> S.packCStringLen (castPtr ptr, n) >>=+ flip write os . Just+ writeNonBlocking = ignoreOffset $ \_ _ _ -> unsupported ------------------------------------------------------------------------------ -- | Internal convenience synonym for a pair of input\/output streams. type StreamPair a = SP (InputStream a) (OutputStream a) +-- | The offset argument is ignored if present. instance H.RawIO (StreamPair ByteString) where- read (SP is _) ptr n = H.read is ptr n- readNonBlocking _ _ _ = unsupported- write (SP _ os) ptr n = H.write os ptr n- writeNonBlocking _ _ _ = unsupported+ read (SP is _) = H.read is+ readNonBlocking = ignoreOffset $ \_ _ _ -> unsupported+ write (SP _ os) = H.write os+ writeNonBlocking = ignoreOffset $ \_ _ _ -> unsupported ------------------------------------------------------------------------------
src/System/IO/Streams/Internal/Attoparsec.hs view
@@ -8,10 +8,10 @@ module System.IO.Streams.Internal.Attoparsec ( -- * Parsing- parseFromStream- , parseFromStreamInternal- , parserToInputStream+ parseFromStreamInternal + , ParseData(..)+ -- * Parse Exceptions , ParseException(..) @@ -20,14 +20,16 @@ ------------------------------------------------------------------------------ import Control.Exception (Exception, throwIO)-import Control.Monad (when)-import Data.Attoparsec.ByteString.Char8 (Parser, Result, feed, parse)-import Data.Attoparsec.Types (IResult (..))-import Data.ByteString.Char8 (ByteString)-import qualified Data.ByteString.Char8 as S+import Control.Monad (unless)+import qualified Data.Attoparsec.ByteString.Char8 as S+import qualified Data.Attoparsec.Text as T+import Data.Attoparsec.Types (IResult (..), Parser)+import qualified Data.ByteString as S import Data.List (intercalate)+import Data.String (IsString)+import qualified Data.Text as T import Data.Typeable (Typeable)-import Prelude hiding (read)+import Prelude hiding (null, read) ------------------------------------------------------------------------------ import System.IO.Streams.Internal (InputStream) import qualified System.IO.Streams.Internal as Streams@@ -45,48 +47,43 @@ --------------------------------------------------------------------------------- | Supplies an @attoparsec@ 'Parser' with an 'InputStream', returning the--- final parsed value or throwing a 'ParseException' if parsing fails.------ 'parseFromStream' consumes only as much input as necessary to satisfy the--- 'Parser': any unconsumed input is pushed back onto the 'InputStream'.------ If the 'Parser' exhausts the 'InputStream', the end-of-stream signal is sent--- to attoparsec.------ Example:------ @--- ghci> import "Data.Attoparsec.ByteString.Char8"--- ghci> is <- 'System.IO.Streams.fromList' [\"12345xxx\" :: 'ByteString']--- ghci> 'parseFromStream' ('Data.Attoparsec.ByteString.Char8.takeWhile' 'Data.Attoparsec.ByteString.Char8.isDigit') is--- \"12345\"--- ghci> 'System.IO.Streams.read' is--- Just \"xxx\"--- @-parseFromStream :: Parser r- -> InputStream ByteString- -> IO r-parseFromStream = parseFromStreamInternal parse feed-{-# INLINE parseFromStream #-}+class (IsString i) => ParseData i where+ parse :: Parser i a -> i -> IResult i a+ feed :: IResult i r -> i -> IResult i r+ null :: i -> Bool ------------------------------------------------------------------------------+instance ParseData S.ByteString where+ parse = S.parse+ feed = S.feed+ null = S.null+++------------------------------------------------------------------------------+instance ParseData T.Text where+ parse = T.parse+ feed = T.feed+ null = T.null+++------------------------------------------------------------------------------ -- | Internal version of parseFromStream allowing dependency injection of the -- parse functions for testing.-parseFromStreamInternal :: (Parser r -> ByteString -> Result r)- -> (Result r -> ByteString -> Result r)- -> Parser r- -> InputStream ByteString+parseFromStreamInternal :: ParseData i+ => (Parser i r -> i -> IResult i r)+ -> (IResult i r -> i -> IResult i r)+ -> Parser i r+ -> InputStream i -> IO r parseFromStreamInternal parseFunc feedFunc parser is = Streams.read is >>= maybe (finish $ parseFunc parser "")- (\s -> if S.null s+ (\s -> if null s then parseFromStreamInternal parseFunc feedFunc parser is else go $! parseFunc parser s) where- leftover x = when (not $ S.null x) $ Streams.unRead x is+ leftover x = unless (null x) $ Streams.unRead x is finish k = let k' = feedFunc (feedFunc k "") "" in case k' of@@ -104,49 +101,15 @@ go (Done x r) = leftover x >> return r go r = Streams.read is >>= maybe (finish r)- (\s -> if S.null s+ (\s -> if null s then go r else go $! feedFunc r s) --------------------------------------------------------------------------------- | Given a 'Parser' yielding values of type @'Maybe' r@, transforms an--- 'InputStream' over byte strings to an 'InputStream' yielding values of type--- @r@.------ If the parser yields @Just x@, then @x@ will be passed along downstream, and--- if the parser yields @Nothing@, that will be interpreted as end-of-stream.------ Upon a parse error, 'parserToInputStream' will throw a 'ParseException'.------ Example:------ @--- ghci> import "Control.Applicative"--- ghci> import "Data.Attoparsec.ByteString.Char8"--- ghci> is <- 'System.IO.Streams.fromList' [\"1 2 3 4 5\" :: 'ByteString']--- ghci> let parser = ('Data.Attoparsec.ByteString.Char8.endOfInput' >> 'Control.Applicative.pure' 'Nothing') \<|\> (Just \<$\> ('Data.Attoparsec.ByteString.Char8.skipWhile' 'Data.Attoparsec.ByteString.Char8.isSpace' *> 'Data.Attoparsec.ByteString.Char8.decimal'))--- ghci> 'parserToInputStream' parser is >>= 'System.IO.Streams.toList'--- [1,2,3,4,5]--- ghci> is' \<- 'System.IO.Streams.fromList' [\"1 2xx3 4 5\" :: 'ByteString'] >>= 'parserToInputStream' parser--- ghci> 'read' is'--- Just 1--- ghci> 'read' is'--- Just 2--- ghci> 'read' is'--- *** Exception: Parse exception: Failed reading: takeWhile1--- @-parserToInputStream :: Parser (Maybe r)- -> InputStream ByteString- -> IO (InputStream r)-parserToInputStream = (Streams.makeInputStream .) . parseFromStream-{-# INLINE parserToInputStream #-}--------------------------------------------------------------------------------- -- A replacement for attoparsec's 'eitherResult', which discards information -- about the context of the failed parse.-eitherResult :: Result r -> Either (ByteString, [String], String) r+eitherResult :: IsString i => IResult i r -> Either (i, [String], String) r eitherResult (Done _ r) = Right r eitherResult (Fail residual ctx msg) = Left (residual, ctx, msg) eitherResult _ = Left ("", [], "Result: incomplete input")
src/System/IO/Streams/Vector.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE CPP #-} -- | Vector conversions and utilities. @@ -29,7 +30,7 @@ import Control.Concurrent.MVar (modifyMVar, modifyMVar_, newMVar) import Control.Monad (liftM, (>=>)) import Control.Monad.IO.Class (MonadIO (..))-import Control.Monad.Primitive (PrimState (..))+import Control.Monad.Primitive (PrimState (..), RealWorld) import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Data.Vector.Generic (Vector (..)) import qualified Data.Vector.Generic as V@@ -38,7 +39,17 @@ import System.IO.Streams.Internal (InputStream, OutputStream, fromGenerator, yield) import qualified System.IO.Streams.Internal as S +#if MIN_VERSION_vector(0,13,0)+import Control.Monad.ST (stToIO)+#endif +basicUnsafeFreezeCompat :: Vector v a => V.Mutable v RealWorld a -> IO (v a)+#if MIN_VERSION_vector(0,13,0)+basicUnsafeFreezeCompat = stToIO . V.basicUnsafeFreeze+#else+basicUnsafeFreezeCompat = V.basicUnsafeFreeze+#endif+ ------------------------------------------------------------------------------ -- | Transforms a vector into an 'InputStream' that yields each of the values -- in the vector in turn.@@ -77,7 +88,7 @@ -- | Like 'toVector', but allows control over how large the vector buffer is to -- start with. toVectorSized :: Vector v a => Int -> InputStream a -> IO (v a)-toVectorSized n = toMutableVectorSized n >=> V.basicUnsafeFreeze+toVectorSized n = toMutableVectorSized n >=> basicUnsafeFreezeCompat {-# INLINE toVectorSized #-} @@ -136,7 +147,7 @@ vectorOutputStreamSized :: Vector v c => Int -> IO (OutputStream c, IO (v c)) vectorOutputStreamSized n = do (os, flush) <- mutableVectorOutputStreamSized n- return $! (os, flush >>= V.basicUnsafeFreeze)+ return $! (os, flush >>= basicUnsafeFreezeCompat) ------------------------------------------------------------------------------@@ -291,7 +302,7 @@ Int -> (OutputStream a -> IO b) -> IO (v a)-outputToVectorSized n = outputToMutableVectorSized n >=> V.basicUnsafeFreeze+outputToVectorSized n = outputToMutableVectorSized n >=> basicUnsafeFreezeCompat {-# INLINE outputToVectorSized #-}
− test/System/IO/Streams/Tests/Attoparsec.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module System.IO.Streams.Tests.Attoparsec (tests) where---------------------------------------------------------------------------------import Control.Monad-import Data.Attoparsec.ByteString.Char8 hiding (eitherResult)-import Data.ByteString.Char8 (ByteString)-import Prelude hiding (takeWhile)-import System.IO.Streams-import System.IO.Streams.Internal.Attoparsec-import System.IO.Streams.Tests.Common-import Test.Framework-import Test.Framework.Providers.HUnit-import Test.HUnit hiding (Test)---------------------------------------------------------------------------------tests :: [Test]-tests = [ testParseFromStream- , testParseFromStreamError- , testParseFromStreamError2- , testPartialParse- , testEmbeddedNull- , testTrivials- ]----------------------------------------------------------------------------------testParser :: Parser (Maybe Int)-testParser = do- end <- atEnd- if end- then return Nothing- else do- _ <- takeWhile (\c -> isSpace c || c == ',')- liftM Just decimal----------------------------------------------------------------------------------testParser2 :: Parser (Maybe ByteString)-testParser2 = do- end <- atEnd- if end- then return Nothing- else liftM Just $ string "bork"----------------------------------------------------------------------------------testParseFromStream :: Test-testParseFromStream = testCase "attoparsec/parseFromStream" $ do- is <- fromList ["1", "23", ", 4", ", 5, 6, 7"]- x0 <- parseFromStream testParser is-- assertEqual "first parse" (Just 123) x0-- l <- parserToInputStream testParser is >>= toList-- assertEqual "rest" [4, 5, 6, 7] l- toList is >>= assertEqual "double eof" []----------------------------------------------------------------------------------testParseFromStreamError :: Test-testParseFromStreamError = testCase "attoparsec/parseFromStreamError" $ do- is <- fromList ["1", "23", ", 4", ",xxxx 5, 6, 7"] >>=- parserToInputStream testParser-- expectExceptionH $ toList is----------------------------------------------------------------------------------testParseFromStreamError2 :: Test-testParseFromStreamError2 = testCase "attoparsec/parseFromStreamError2" $ do- l <- fromList ["borkbork", "bork"] >>= p- assertEqual "ok" ["bork", "bork", "bork"] l-- expectExceptionH $ fromList ["bork", "bo"] >>= p- expectExceptionH $ fromList ["xxxxx"] >>= p-- where- p = parserToInputStream ((testParser2 <?> "foo") <?> "bar") >=> toList----------------------------------------------------------------------------------testPartialParse :: Test-testPartialParse = testCase "attoparsec/partialParse" $ do- is <- fromList ["1,", "2,", "3"]- expectExceptionH $ parseFromStreamInternal parseFunc feedFunc testParser is-- where- result = Partial (const result)- parseFunc = const $ const $ result- feedFunc = const $ const $ result---------------------------------------------------------------------------------testTrivials :: Test-testTrivials = testCase "attoparsec/trivials" $ do- coverTypeableInstance (undefined :: ParseException)- let (Right x) = eitherResult $ Done undefined (4 :: Int)- assertEqual "eitherResult" 4 x---------------------------------------------------------------------------------testEmbeddedNull :: Test-testEmbeddedNull = testCase "attoparsec/embeddedNull" $ do- is <- fromList ["", "1", "23", "", ", 4", ", 5, 6, 7"]- x0 <- parseFromStream testParser is-- assertEqual "first parse" (Just 123) x0-- l <- parserToInputStream testParser is >>= toList-- assertEqual "rest" [4, 5, 6, 7] l
+ test/System/IO/Streams/Tests/Attoparsec/ByteString.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE OverloadedStrings #-}++module System.IO.Streams.Tests.Attoparsec.ByteString (tests) where++------------------------------------------------------------------------------+import Control.Monad+import Data.Attoparsec.ByteString.Char8 hiding (eitherResult)+import Data.ByteString.Char8 (ByteString)+import Prelude hiding (takeWhile)+import System.IO.Streams+import System.IO.Streams.Attoparsec.ByteString+import System.IO.Streams.Internal.Attoparsec (eitherResult, parseFromStreamInternal)+import System.IO.Streams.Tests.Common+import Test.Framework+import Test.Framework.Providers.HUnit+import Test.HUnit hiding (Test)+------------------------------------------------------------------------------++tests :: [Test]+tests = [ testParseFromStream+ , testParseFromStreamError+ , testParseFromStreamError2+ , testPartialParse+ , testEmbeddedNull+ , testTrivials+ ]+++------------------------------------------------------------------------------+testParser :: Parser (Maybe Int)+testParser = do+ end <- atEnd+ if end+ then return Nothing+ else do+ _ <- takeWhile (\c -> isSpace c || c == ',')+ liftM Just decimal+++------------------------------------------------------------------------------+testParser2 :: Parser (Maybe ByteString)+testParser2 = do+ end <- atEnd+ if end+ then return Nothing+ else liftM Just $ string "bork"+++------------------------------------------------------------------------------+testParseFromStream :: Test+testParseFromStream = testCase "attoparsec/parseFromStream" $ do+ is <- fromList ["1", "23", ", 4", ", 5, 6, 7"]+ x0 <- parseFromStream testParser is++ assertEqual "first parse" (Just 123) x0++ l <- parserToInputStream testParser is >>= toList++ assertEqual "rest" [4, 5, 6, 7] l+ toList is >>= assertEqual "double eof" []+++------------------------------------------------------------------------------+testParseFromStreamError :: Test+testParseFromStreamError = testCase "attoparsec/parseFromStreamError" $ do+ is <- fromList ["1", "23", ", 4", ",xxxx 5, 6, 7"] >>=+ parserToInputStream testParser++ expectExceptionH $ toList is+++------------------------------------------------------------------------------+testParseFromStreamError2 :: Test+testParseFromStreamError2 = testCase "attoparsec/parseFromStreamError2" $ do+ l <- fromList ["borkbork", "bork"] >>= p+ assertEqual "ok" ["bork", "bork", "bork"] l++ expectExceptionH $ fromList ["bork", "bo"] >>= p+ expectExceptionH $ fromList ["xxxxx"] >>= p++ where+ p = parserToInputStream ((testParser2 <?> "foo") <?> "bar") >=> toList+++------------------------------------------------------------------------------+testPartialParse :: Test+testPartialParse = testCase "attoparsec/partialParse" $ do+ is <- fromList ["1,", "2,", "3"]+ expectExceptionH $ parseFromStreamInternal parseFunc feedFunc testParser is++ where+ result = Partial (const result)+ parseFunc = const $ const $ result+ feedFunc = const $ const $ result++------------------------------------------------------------------------------+testTrivials :: Test+testTrivials = testCase "attoparsec/trivials" $ do+ coverTypeableInstance (undefined :: ParseException)+ let (Right x) = eitherResult $ Done undefined 4 :: Either (ByteString, [String], String) Int+ assertEqual "eitherResult" 4 x++------------------------------------------------------------------------------+testEmbeddedNull :: Test+testEmbeddedNull = testCase "attoparsec/embeddedNull" $ do+ is <- fromList ["", "1", "23", "", ", 4", ", 5, 6, 7"]+ x0 <- parseFromStream testParser is++ assertEqual "first parse" (Just 123) x0++ l <- parserToInputStream testParser is >>= toList++ assertEqual "rest" [4, 5, 6, 7] l
+ test/System/IO/Streams/Tests/Attoparsec/Text.hs view
@@ -0,0 +1,140 @@+{-# LANGUAGE OverloadedStrings #-}++module System.IO.Streams.Tests.Attoparsec.Text (tests, testParserU) where++------------------------------------------------------------------------------+import Control.Monad+import Data.Attoparsec.Text hiding (eitherResult)+import Data.Char (isAlpha, isSpace)+import Data.Text (Text)+import Prelude hiding (takeWhile)+import System.IO.Streams+import System.IO.Streams.Attoparsec.Text+import System.IO.Streams.Internal.Attoparsec (eitherResult, parseFromStreamInternal)+import System.IO.Streams.Tests.Common+import Test.Framework+import Test.Framework.Providers.HUnit+import Test.HUnit hiding (Test)+------------------------------------------------------------------------------++tests :: [Test]+tests = [ testParseFromStream+ , testParseFromStreamError+ , testParseFromStreamError2+ , testPartialParse+ , testEmbeddedNull+ , testTrivials+ , testParseFromStreamU+ ]+++------------------------------------------------------------------------------+testParser :: Parser (Maybe Int)+testParser = do+ end <- atEnd+ if end+ then return Nothing+ else do+ _ <- takeWhile (\c -> isSpace c || c == ',')+ liftM Just decimal+++------------------------------------------------------------------------------+testParser2 :: Parser (Maybe Text)+testParser2 = do+ end <- atEnd+ if end+ then return Nothing+ else liftM Just $ string "bork"+++------------------------------------------------------------------------------+testParserU :: Parser (Maybe Text)+testParserU = do+ end <- atEnd+ if end+ then return Nothing+ else do+ _ <- takeWhile (not . isAlpha)+ liftM Just (takeWhile isAlpha)+++------------------------------------------------------------------------------+testParseFromStream :: Test+testParseFromStream = testCase "attoparsec/parseFromStream" $ do+ is <- fromList ["1", "23", ", 4", ", 5, 6, 7"]+ x0 <- parseFromStream testParser is++ assertEqual "first parse" (Just 123) x0++ l <- parserToInputStream testParser is >>= toList++ assertEqual "rest" [4, 5, 6, 7] l+ toList is >>= assertEqual "double eof" []+++------------------------------------------------------------------------------+testParseFromStreamError :: Test+testParseFromStreamError = testCase "attoparsec/parseFromStreamError" $ do+ is <- fromList ["1", "23", ", 4", ",xxxx 5, 6, 7"] >>=+ parserToInputStream testParser++ expectExceptionH $ toList is+++------------------------------------------------------------------------------+testParseFromStreamError2 :: Test+testParseFromStreamError2 = testCase "attoparsec/parseFromStreamError2" $ do+ l <- fromList ["borkbork", "bork"] >>= p+ assertEqual "ok" ["bork", "bork", "bork"] l++ expectExceptionH $ fromList ["bork", "bo"] >>= p+ expectExceptionH $ fromList ["xxxxx"] >>= p++ where+ p = parserToInputStream ((testParser2 <?> "foo") <?> "bar") >=> toList+++------------------------------------------------------------------------------+testPartialParse :: Test+testPartialParse = testCase "attoparsec/partialParse" $ do+ is <- fromList ["1,", "2,", "3"]+ expectExceptionH $ parseFromStreamInternal parseFunc feedFunc testParser is++ where+ result = Partial (const result)+ parseFunc = const $ const $ result+ feedFunc = const $ const $ result++------------------------------------------------------------------------------+testTrivials :: Test+testTrivials = testCase "attoparsec/trivials" $ do+ coverTypeableInstance (undefined :: ParseException)+ let (Right x) = eitherResult $ Done undefined 4 :: Either (Text, [String], String) Int+ assertEqual "eitherResult" 4 x++------------------------------------------------------------------------------+testEmbeddedNull :: Test+testEmbeddedNull = testCase "attoparsec/embeddedNull" $ do+ is <- fromList ["", "1", "23", "", ", 4", ", 5, 6, 7"]+ x0 <- parseFromStream testParser is++ assertEqual "first parse" (Just 123) x0++ l <- parserToInputStream testParser is >>= toList++ assertEqual "rest" [4, 5, 6, 7] l++------------------------------------------------------------------------------+testParseFromStreamU :: Test+testParseFromStreamU = testCase "attoparsec/parseFromStreamU" $ do+ is <- fromList ["123æø", "å", "💻⛇⛄☃Š", "š5ŧđ6naå7"]+ x0 <- parseFromStream testParserU is++ assertEqual "first parse" (Just "æøå") x0++ l <- parserToInputStream testParserU is >>= toList++ assertEqual "rest" ["Šš", "ŧđ", "naå", ""] l+ toList is >>= assertEqual "double eof" []+
test/System/IO/Streams/Tests/ByteString.hs view
@@ -8,18 +8,12 @@ import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as S import qualified Data.ByteString.Lazy.Char8 as L-import Data.List hiding (lines,- takeWhile, unlines,- unwords, words)+import Data.List hiding (lines, takeWhile, unlines, unwords, words) import Data.Maybe (isJust) import Data.Monoid-import Prelude hiding (lines, read,- take, takeWhile,- unlines, unwords,- words)+import Prelude hiding (lines, read, take, takeWhile, unlines, unwords, words) import qualified Prelude-import System.IO.Streams hiding (filter,- intersperse, mapM_)+import System.IO.Streams hiding (filter, intersperse, mapM_) import System.IO.Streams.Tests.Common import System.Timeout import Test.Framework@@ -625,6 +619,8 @@ fromList ["th", "e\nquick\nbrown", "\n", "", "fox"] >>= lines >>= toList >>= assertEqual "lines" ["the", "quick", "brown", "fox"] fromList [] >>= lines >>= toList >>= assertEqual "empty lines" []+ fromList ["a\nb\nc\n"] >>= lines >>= toList+ >>= assertEqual "ending in delimiter" ["a","b","c"] fromList ["ok", "cool"] >>= \is -> outputToList (\os -> unlines os >>= connect is) >>=
test/System/IO/Streams/Tests/Combinators.hs view
@@ -56,6 +56,7 @@ , testZipWith , testZipWithM , testUnzip+ , testContraunzip , testTake , testDrop , testGive@@ -358,6 +359,26 @@ toList is3 >>= assertEqual "unzip2-a" (fst $ Prelude.unzip l) read is4 >>= assertEqual "unzip2-read-b" Nothing read is3 >>= assertEqual "unzip2-read" Nothing+++------------------------------------------------------------------------------+testContraunzip :: Test+testContraunzip = testProperty "combinators/contrazip" $ monadicIO $ forAllM arbitrary prop+ where+ prop :: [Int] -> PropertyM IO ( )+ prop xs = liftQ $ do+ let ys = fmap show xs+ xsStream <- fromList xs+ ysStream <- fromList ys+ (xsSink, getXs') <- listOutputStream+ (ysSink, getYs') <- listOutputStream+ xysStream <- zip xsStream ysStream+ xysSink <- contraunzip xsSink ysSink+ connect xysStream xysSink+ xs' <- getXs'+ ys' <- getYs'+ assertEqual "numbers" xs xs'+ assertEqual "strings" ys ys' ------------------------------------------------------------------------------
test/System/IO/Streams/Tests/Concurrent.hs view
@@ -47,7 +47,7 @@ chans inputs <- mapM Streams.chanToInput chans resultMVar <- newEmptyMVar- forkIO (Streams.concurrentMerge inputs >>= Streams.toList+ _ <- forkIO (Streams.concurrentMerge inputs >>= Streams.toList >>= putMVar resultMVar) putMVar firstMVar 0 result <- takeMVar resultMVar
test/System/IO/Streams/Tests/Handle.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module System.IO.Streams.Tests.Handle (tests) where@@ -148,13 +149,13 @@ is <- Streams.fromList ["foo", "bar", "baz" :: S.ByteString] (os, getList) <- Streams.listOutputStream let sp = Streams.SP is (os :: OutputStream S.ByteString)- expectExceptionH $ H.write is undefined undefined- expectExceptionH $ H.writeNonBlocking is undefined undefined+ expectExceptionH $ withZeroOffset H.write is undefined undefined+ expectExceptionH $ withZeroOffset H.writeNonBlocking is undefined undefined expectExceptionH $ H.flushWriteBuffer is undefined expectExceptionH $ H.flushWriteBuffer0 is undefined - expectExceptionH $ H.read os undefined undefined- expectExceptionH $ H.writeNonBlocking os undefined undefined+ expectExceptionH $ withZeroOffset H.read os undefined undefined+ expectExceptionH $ withZeroOffset H.writeNonBlocking os undefined undefined expectExceptionH $ H.fillReadBuffer0 is undefined expectExceptionH $ H.fillReadBuffer0 os undefined@@ -168,17 +169,17 @@ H.devType os >>= assertBool "devtype output" . (== H.Stream) H.devType sp >>= assertBool "devtype pair" . (== H.Stream) - expectExceptionH $ H.readNonBlocking is undefined undefined- expectExceptionH $ H.readNonBlocking os undefined undefined- expectExceptionH $ H.readNonBlocking sp undefined undefined- expectExceptionH $ H.writeNonBlocking is undefined undefined- expectExceptionH $ H.writeNonBlocking os undefined undefined- expectExceptionH $ H.writeNonBlocking sp undefined undefined+ expectExceptionH $ withZeroOffset H.readNonBlocking is undefined undefined+ expectExceptionH $ withZeroOffset H.readNonBlocking os undefined undefined+ expectExceptionH $ withZeroOffset H.readNonBlocking sp undefined undefined+ expectExceptionH $ withZeroOffset H.writeNonBlocking is undefined undefined+ expectExceptionH $ withZeroOffset H.writeNonBlocking os undefined undefined+ expectExceptionH $ withZeroOffset H.writeNonBlocking sp undefined undefined S.useAsCStringLen "foo" $ \(cstr, l) -> do- H.write os (castPtr cstr) l+ withZeroOffset H.write os (castPtr cstr) l liftM S.concat getList >>= assertEqual "H.write 1" "foo"- H.write sp (castPtr cstr) l+ withZeroOffset H.write sp (castPtr cstr) l liftM S.concat getList >>= assertEqual "H.write 2" "foo" buf <- H.newBuffer sp HB.WriteBuffer HB.withBuffer buf $ \ptr -> copyBytes ptr (castPtr cstr) 3@@ -189,10 +190,18 @@ allocaBytes 3 $ \buf -> do- l <- H.read is buf 3+ l <- withZeroOffset H.read is buf 3 assertEqual "3 byte read" 3 l S.packCStringLen (castPtr buf, l) >>= assertEqual "first read" "foo"- l' <- H.read sp buf 3+ l' <- withZeroOffset H.read sp buf 3 assertEqual "3 byte read #2" 3 l' S.packCStringLen (castPtr buf, l') >>= assertEqual "second read" "bar"- expectExceptionH $ H.read os buf 3+ expectExceptionH $ withZeroOffset H.read os buf 3+ where+#if MIN_VERSION_base(4,15,0)+ withZeroOffset :: Num off => (a -> ptr -> off -> n -> ioint) -> a -> ptr -> n -> ioint+ withZeroOffset f a ptr n = f a ptr 0 n+#else+ withZeroOffset :: a -> a+ withZeroOffset = id+#endif
test/System/IO/Streams/Tests/Network.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module System.IO.Streams.Tests.Network (tests) where @@ -13,6 +14,10 @@ import Test.Framework import Test.Framework.Providers.HUnit import Test.HUnit hiding (Test)+#if MIN_VERSION_network(2,7,0)+#else+import Data.List (intercalate)+#endif ------------------------------------------------------------------------------ import qualified System.IO.Streams.Internal as Streams import qualified System.IO.Streams.Internal.Network as Streams@@ -32,10 +37,23 @@ assertEqual "ok" (Just ()) x where+ -- compats+#if MIN_VERSION_network(2,7,0)+ mkAddr = return . N.tupleToHostAddress+ defaultPort = N.defaultPort+ close = N.close+ bind = N.bind+#else+ mkAddr (o1,o2,o3,o4) = N.inet_addr . intercalate "." $ map show [o1,o2,o3,o4]+ defaultPort = N.aNY_PORT+ close = N.sClose+ bind = N.bindSocket+#endif+ go = do portMVar <- newEmptyMVar resultMVar <- newEmptyMVar- forkIO $ client portMVar resultMVar+ _ <- forkIO $ client portMVar resultMVar server portMVar l <- takeMVar resultMVar assertEqual "testSocket" l ["ok"]@@ -43,28 +61,28 @@ client mvar resultMVar = do port <- takeMVar mvar sock <- N.socket N.AF_INET N.Stream N.defaultProtocol- addr <- N.inet_addr "127.0.0.1"+ addr <- mkAddr (127, 0, 0, 1) let saddr = N.SockAddrInet port addr N.connect sock saddr (is, os) <- Streams.socketToStreams sock Streams.fromList ["", "ok"] >>= Streams.connectTo os N.shutdown sock N.ShutdownSend Streams.toList is >>= putMVar resultMVar- N.sClose sock+ close sock server mvar = do sock <- N.socket N.AF_INET N.Stream N.defaultProtocol- addr <- N.inet_addr "127.0.0.1"- let saddr = N.SockAddrInet N.aNY_PORT addr- N.bindSocket sock saddr+ addr <- mkAddr (127, 0, 0, 1)+ let saddr = N.SockAddrInet defaultPort addr+ bind sock saddr N.listen sock 5 port <- N.socketPort sock putMVar mvar port (csock, _) <- N.accept sock (is, os) <- Streams.socketToStreams csock Streams.toList is >>= flip Streams.writeList os- N.sClose csock- N.sClose sock+ close csock+ close sock testSocketWithError :: Test testSocketWithError = testCase "network/socket-error" $ N.withSocketsDo $ do
test/System/IO/Streams/Tests/Process.hs view
@@ -40,7 +40,7 @@ ------------------------------------------------------------------------------ testInteractiveProcess :: Test testInteractiveProcess = testCase "process/interactiveProcess" $ do- (out, err) <- Streams.runInteractiveProcess "/usr/bin/tr" ["a-z", "A-Z"]+ (out, err) <- Streams.runInteractiveProcess "tr" ["a-z", "A-Z"] Nothing Nothing >>= run [inputdata] assertEqual "interactiveProcess" expected out
test/TestSuite.hs view
@@ -1,28 +1,36 @@+{-# LANGUAGE CPP #-}+ module Main where -import qualified System.IO.Streams.Tests.Attoparsec as Attoparsec-import qualified System.IO.Streams.Tests.Builder as Builder-import qualified System.IO.Streams.Tests.ByteString as ByteString-import qualified System.IO.Streams.Tests.Combinators as Combinators-import qualified System.IO.Streams.Tests.Concurrent as Concurrent-import qualified System.IO.Streams.Tests.Debug as Debug-import qualified System.IO.Streams.Tests.File as File-import qualified System.IO.Streams.Tests.Handle as Handle-import qualified System.IO.Streams.Tests.Internal as Internal-import qualified System.IO.Streams.Tests.List as List-import qualified System.IO.Streams.Tests.Network as Network-import qualified System.IO.Streams.Tests.Process as Process-import qualified System.IO.Streams.Tests.Text as Text-import qualified System.IO.Streams.Tests.Vector as Vector-import qualified System.IO.Streams.Tests.Zlib as Zlib-import Test.Framework (defaultMain, testGroup)+import qualified System.IO.Streams.Tests.Attoparsec.ByteString as AttoparsecByteString+import qualified System.IO.Streams.Tests.Attoparsec.Text as AttoparsecText+import qualified System.IO.Streams.Tests.Builder as Builder+import qualified System.IO.Streams.Tests.ByteString as ByteString+import qualified System.IO.Streams.Tests.Combinators as Combinators+import qualified System.IO.Streams.Tests.Concurrent as Concurrent+import qualified System.IO.Streams.Tests.Debug as Debug+import qualified System.IO.Streams.Tests.File as File+import qualified System.IO.Streams.Tests.Handle as Handle+import qualified System.IO.Streams.Tests.Internal as Internal+import qualified System.IO.Streams.Tests.List as List+#ifdef ENABLE_NETWORK+import qualified System.IO.Streams.Tests.Network as Network+#endif+import qualified System.IO.Streams.Tests.Process as Process+import qualified System.IO.Streams.Tests.Text as Text+import qualified System.IO.Streams.Tests.Vector as Vector+#ifdef ENABLE_ZLIB+import qualified System.IO.Streams.Tests.Zlib as Zlib+#endif+import Test.Framework (defaultMain, testGroup) ------------------------------------------------------------------------------ main :: IO () main = defaultMain tests where- tests = [ testGroup "Tests.Attoparsec" Attoparsec.tests+ tests = [ testGroup "Tests.Attoparsec.ByteString" AttoparsecByteString.tests+ , testGroup "Tests.Attoparsec.Text" AttoparsecText.tests , testGroup "Tests.Builder" Builder.tests , testGroup "Tests.ByteString" ByteString.tests , testGroup "Tests.Debug" Debug.tests@@ -32,9 +40,13 @@ , testGroup "Tests.Handle" Handle.tests , testGroup "Tests.Internal" Internal.tests , testGroup "Tests.List" List.tests+#ifdef ENABLE_NETWORK , testGroup "Tests.Network" Network.tests+#endif , testGroup "Tests.Process" Process.tests , testGroup "Tests.Text" Text.tests , testGroup "Tests.Vector" Vector.tests+#ifdef ENABLE_ZLIB , testGroup "Tests.Zlib" Zlib.tests+#endif ]