conduit-extra-1.3.5/Data/0000755000000000000000000000000013626670615013361 5ustar0000000000000000conduit-extra-1.3.5/Data/Conduit/0000755000000000000000000000000013626670615014766 5ustar0000000000000000conduit-extra-1.3.5/Data/Conduit/ByteString/0000755000000000000000000000000013626670615017060 5ustar0000000000000000conduit-extra-1.3.5/Data/Conduit/Network/0000755000000000000000000000000013626670615016417 5ustar0000000000000000conduit-extra-1.3.5/Data/Conduit/Process/0000755000000000000000000000000013634620704016375 5ustar0000000000000000conduit-extra-1.3.5/bench/0000755000000000000000000000000013626670615013567 5ustar0000000000000000conduit-extra-1.3.5/test/0000755000000000000000000000000013626670615013467 5ustar0000000000000000conduit-extra-1.3.5/test/Data/0000755000000000000000000000000013626670615014340 5ustar0000000000000000conduit-extra-1.3.5/test/Data/Conduit/0000755000000000000000000000000013626670615015745 5ustar0000000000000000conduit-extra-1.3.5/test/Data/Conduit/ByteString/0000755000000000000000000000000013626670615020037 5ustar0000000000000000conduit-extra-1.3.5/test/Data/Conduit/Process/0000755000000000000000000000000013626670615017363 5ustar0000000000000000conduit-extra-1.3.5/test/filesystem/0000755000000000000000000000000013626670615015653 5ustar0000000000000000conduit-extra-1.3.5/test/filesystem/bin/0000755000000000000000000000000013626670615016423 5ustar0000000000000000conduit-extra-1.3.5/Data/Conduit/Attoparsec.hs0000644000000000000000000001754013626670615017436 0ustar0000000000000000{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} -- | -- Copyright: 2011 Michael Snoyman, 2010 John Millikin -- License: MIT -- -- Consume attoparsec parsers via conduit. -- -- This code was taken from attoparsec-enumerator and adapted for conduits. module Data.Conduit.Attoparsec ( -- * Sink sinkParser , sinkParserEither -- * Conduit , conduitParser , conduitParserEither -- * Types , ParseError (..) , Position (..) , PositionRange (..) -- * Classes , AttoparsecInput ) where import Control.Exception (Exception) import Control.Monad (unless) import qualified Data.ByteString as B import qualified Data.Text as T import qualified Data.Text.Internal as TI import Data.Typeable (Typeable) import Prelude hiding (lines) import qualified Data.Attoparsec.ByteString import qualified Data.Attoparsec.Text import qualified Data.Attoparsec.Types as A import Data.Conduit import Control.Monad.Trans.Resource (MonadThrow, throwM) -- | The context and message from a 'A.Fail' value. data ParseError = ParseError { errorContexts :: [String] , errorMessage :: String , errorPosition :: Position } | DivergentParser deriving (Show, Typeable) instance Exception ParseError data Position = Position { posLine :: {-# UNPACK #-} !Int , posCol :: {-# UNPACK #-} !Int , posOffset :: {-# UNPACK #-} !Int -- ^ @since 1.2.0 } deriving (Eq, Ord) instance Show Position where show (Position l c off) = show l ++ ':' : show c ++ " (" ++ show off ++ ")" data PositionRange = PositionRange { posRangeStart :: {-# UNPACK #-} !Position , posRangeEnd :: {-# UNPACK #-} !Position } deriving (Eq, Ord) instance Show PositionRange where show (PositionRange s e) = show s ++ '-' : show e -- | A class of types which may be consumed by an Attoparsec parser. class AttoparsecInput a where parseA :: A.Parser a b -> a -> A.IResult a b feedA :: A.IResult a b -> a -> A.IResult a b empty :: a isNull :: a -> Bool getLinesCols :: a -> Position -- | Return the beginning of the first input with the length of -- the second input removed. Assumes the second string is shorter -- than the first. stripFromEnd :: a -> a -> a instance AttoparsecInput B.ByteString where parseA = Data.Attoparsec.ByteString.parse feedA = Data.Attoparsec.ByteString.feed empty = B.empty isNull = B.null getLinesCols = B.foldl' f (Position 0 0 0) where f (Position l c o) ch | ch == 10 = Position (l + 1) 0 (o + 1) | otherwise = Position l (c + 1) (o + 1) stripFromEnd b1 b2 = B.take (B.length b1 - B.length b2) b1 instance AttoparsecInput T.Text where parseA = Data.Attoparsec.Text.parse feedA = Data.Attoparsec.Text.feed empty = T.empty isNull = T.null getLinesCols = T.foldl' f (Position 0 0 0) where f (Position l c o) ch | ch == '\n' = Position (l + 1) 0 (o + 1) | otherwise = Position l (c + 1) (o + 1) stripFromEnd (TI.Text arr1 off1 len1) (TI.Text _ _ len2) = TI.text arr1 off1 (len1 - len2) -- | Convert an Attoparsec 'A.Parser' into a 'Sink'. The parser will -- be streamed bytes until it returns 'A.Done' or 'A.Fail'. -- -- If parsing fails, a 'ParseError' will be thrown with 'throwM'. -- -- Since 0.5.0 sinkParser :: (AttoparsecInput a, MonadThrow m) => A.Parser a b -> ConduitT a o m b sinkParser = fmap snd . sinkParserPosErr (Position 1 1 0) -- | Same as 'sinkParser', but we return an 'Either' type instead -- of raising an exception. -- -- Since 1.1.5 sinkParserEither :: (AttoparsecInput a, Monad m) => A.Parser a b -> ConduitT a o m (Either ParseError b) sinkParserEither = (fmap.fmap) snd . sinkParserPos (Position 1 1 0) -- | Consume a stream of parsed tokens, returning both the token and -- the position it appears at. This function will raise a 'ParseError' -- on bad input. -- -- Since 0.5.0 conduitParser :: (AttoparsecInput a, MonadThrow m) => A.Parser a b -> ConduitT a (PositionRange, b) m () conduitParser parser = conduit $ Position 1 1 0 where conduit !pos = await >>= maybe (return ()) go where go x = do leftover x (!pos', !res) <- sinkParserPosErr pos parser yield (PositionRange pos pos', res) conduit pos' {-# SPECIALIZE conduitParser :: MonadThrow m => A.Parser T.Text b -> ConduitT T.Text (PositionRange, b) m () #-} {-# SPECIALIZE conduitParser :: MonadThrow m => A.Parser B.ByteString b -> ConduitT B.ByteString (PositionRange, b) m () #-} -- | Same as 'conduitParser', but we return an 'Either' type instead -- of raising an exception. conduitParserEither :: (Monad m, AttoparsecInput a) => A.Parser a b -> ConduitT a (Either ParseError (PositionRange, b)) m () conduitParserEither parser = conduit $ Position 1 1 0 where conduit !pos = await >>= maybe (return ()) go where go x = do leftover x eres <- sinkParserPos pos parser case eres of Left e -> yield $ Left e Right (!pos', !res) -> do yield $! Right (PositionRange pos pos', res) conduit pos' {-# SPECIALIZE conduitParserEither :: Monad m => A.Parser T.Text b -> ConduitT T.Text (Either ParseError (PositionRange, b)) m () #-} {-# SPECIALIZE conduitParserEither :: Monad m => A.Parser B.ByteString b -> ConduitT B.ByteString (Either ParseError (PositionRange, b)) m () #-} sinkParserPosErr :: (AttoparsecInput a, MonadThrow m) => Position -> A.Parser a b -> ConduitT a o m (Position, b) sinkParserPosErr pos0 p = sinkParserPos pos0 p >>= f where f (Left e) = throwM e f (Right a) = return a {-# INLINE sinkParserPosErr #-} sinkParserPos :: (AttoparsecInput a, Monad m) => Position -> A.Parser a b -> ConduitT a o m (Either ParseError (Position, b)) sinkParserPos pos0 p = sink empty pos0 (parseA p) where sink prev pos parser = await >>= maybe close push where push c | isNull c = sink prev pos parser | otherwise = go False c $ parser c close = go True prev (feedA (parser empty) empty) go end c (A.Done lo x) = do let pos' | end = pos | otherwise = addLinesCols prev pos y = stripFromEnd c lo pos'' = addLinesCols y pos' unless (isNull lo) $ leftover lo pos'' `seq` return $! Right (pos'', x) go end c (A.Fail rest contexts msg) = let x = stripFromEnd c rest pos' | end = pos | otherwise = addLinesCols prev pos pos'' = addLinesCols x pos' in pos'' `seq` return $! Left (ParseError contexts msg pos'') go end c (A.Partial parser') | end = return $! Left DivergentParser | otherwise = pos' `seq` sink c pos' parser' where pos' = addLinesCols prev pos addLinesCols :: AttoparsecInput a => a -> Position -> Position addLinesCols x (Position lines cols off) = lines' `seq` cols' `seq` off' `seq` Position lines' cols' off' where Position dlines dcols doff = getLinesCols x lines' = lines + dlines cols' = (if dlines > 0 then 1 else cols) + dcols off' = off + doff {-# INLINE sinkParserPos #-} conduit-extra-1.3.5/Data/Conduit/Binary.hs0000644000000000000000000003402513626670615016552 0ustar0000000000000000{-# LANGUAGE CPP, RankNTypes #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ScopedTypeVariables #-} -- | /NOTE/ It is recommended to start using "Data.Conduit.Combinators" instead -- of this module. -- -- Functions for interacting with bytes. -- -- For many purposes, it's recommended to use the conduit-combinators library, -- which provides a more complete set of functions. module Data.Conduit.Binary ( -- * Files and @Handle@s -- | Note that most of these functions live in the @MonadResource@ monad -- to ensure resource finalization even in the presence of exceptions. In -- order to run such code, you will need to use @runResourceT@. -- ** Sources CC.sourceFile , CC.sourceHandle , CC.sourceHandleUnsafe , CC.sourceIOHandle , sourceFileRange , sourceHandleRange , sourceHandleRangeWithBuffer , CC.withSourceFile -- ** Sinks , CC.sinkFile , CC.sinkFileCautious , CC.sinkTempFile , CC.sinkSystemTempFile , CC.sinkHandle , CC.sinkIOHandle , CC.sinkHandleBuilder , CC.sinkHandleFlush , CC.withSinkFile , CC.withSinkFileBuilder , CC.withSinkFileCautious -- ** Conduits , conduitFile , conduitHandle -- * Utilities -- ** Sources , sourceLbs -- ** Sinks , head , dropWhile , take , drop , sinkCacheLength , sinkLbs , mapM_ -- *** Storable , sinkStorable , sinkStorableEx -- ** Conduits , isolate , takeWhile , Data.Conduit.Binary.lines ) where import qualified Data.Conduit.Combinators as CC import Prelude hiding (head, take, drop, takeWhile, dropWhile, mapM_) import qualified Data.ByteString as S import Data.ByteString.Unsafe (unsafeUseAsCString) import qualified Data.ByteString.Lazy as L import Data.Conduit import Data.Conduit.List (sourceList, consume) import Control.Exception (assert, finally) import Control.Monad (unless) import Control.Monad.IO.Class (liftIO, MonadIO) import Control.Monad.Trans.Resource (allocate, release, MonadThrow (..)) import Control.Monad.Trans.Class (lift) import qualified System.IO as IO import Data.Word (Word8, Word64) #if (__GLASGOW_HASKELL__ < 710) import Control.Applicative ((<$>)) #endif import System.Directory (getTemporaryDirectory, removeFile) import Data.ByteString.Lazy.Internal (defaultChunkSize) import Data.ByteString.Internal (ByteString (PS), accursedUnutterablePerformIO) import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) import Foreign.ForeignPtr (touchForeignPtr) import Foreign.Ptr (plusPtr, castPtr) import Foreign.Storable (Storable, peek, sizeOf) import Control.Monad.Trans.Resource (MonadResource) import Control.Exception (Exception) import Data.Typeable (Typeable) import Foreign.Ptr (Ptr) #ifndef ALLOW_UNALIGNED_ACCESS import Foreign.Marshal (alloca, copyBytes) #endif -- | Stream the contents of a file as binary data, starting from a certain -- offset and only consuming up to a certain number of bytes. -- -- Since 0.3.0 sourceFileRange :: MonadResource m => FilePath -> Maybe Integer -- ^ Offset -> Maybe Integer -- ^ Maximum count -> ConduitT i S.ByteString m () sourceFileRange fp offset count = bracketP (IO.openBinaryFile fp IO.ReadMode) IO.hClose (\h -> sourceHandleRange h offset count) -- | Stream the contents of a handle as binary data, starting from a certain -- offset and only consuming up to a certain number of bytes. -- -- Since 1.0.8 sourceHandleRange :: MonadIO m => IO.Handle -> Maybe Integer -- ^ Offset -> Maybe Integer -- ^ Maximum count -> ConduitT i S.ByteString m () sourceHandleRange handle offset count = sourceHandleRangeWithBuffer handle offset count defaultChunkSize -- | Stream the contents of a handle as binary data, starting from a certain -- offset and only consuming up to a certain number of bytes. This function -- consumes chunks as specified by the buffer size. -- -- Since 1.1.8 sourceHandleRangeWithBuffer :: MonadIO m => IO.Handle -> Maybe Integer -- ^ Offset -> Maybe Integer -- ^ Maximum count -> Int -- ^ Buffer size -> ConduitT i S.ByteString m () sourceHandleRangeWithBuffer handle offset count buffer = do case offset of Nothing -> return () Just off -> liftIO $ IO.hSeek handle IO.AbsoluteSeek off case count of Nothing -> pullUnlimited Just c -> pullLimited (fromInteger c) where pullUnlimited = do bs <- liftIO $ S.hGetSome handle buffer if S.null bs then return () else do yield bs pullUnlimited pullLimited c = do bs <- liftIO $ S.hGetSome handle (min c buffer) let c' = c - S.length bs assert (c' >= 0) $ if S.null bs then return () else do yield bs pullLimited c' -- | Stream the contents of the input to a file, and also send it along the -- pipeline. Similar in concept to the Unix command @tee@. -- -- Since 0.3.0 conduitFile :: MonadResource m => FilePath -> ConduitT S.ByteString S.ByteString m () conduitFile fp = bracketP (IO.openBinaryFile fp IO.WriteMode) IO.hClose conduitHandle -- | Stream the contents of the input to a @Handle@, and also send it along the -- pipeline. Similar in concept to the Unix command @tee@. Like @sourceHandle@, -- does not close the handle on completion. Related to: @conduitFile@. -- -- Since 1.0.9 conduitHandle :: MonadIO m => IO.Handle -> ConduitT S.ByteString S.ByteString m () conduitHandle h = awaitForever $ \bs -> liftIO (S.hPut h bs) >> yield bs -- | Ensure that only up to the given number of bytes are consumed by the inner -- sink. Note that this does /not/ ensure that all of those bytes are in fact -- consumed. -- -- Since 0.3.0 isolate :: Monad m => Int -> ConduitT S.ByteString S.ByteString m () isolate = loop where loop 0 = return () loop count = do mbs <- await case mbs of Nothing -> return () Just bs -> do let (a, b) = S.splitAt count bs case count - S.length a of 0 -> do unless (S.null b) $ leftover b yield a count' -> assert (S.null b) $ yield a >> loop count' -- | Return the next byte from the stream, if available. -- -- Since 0.3.0 head :: Monad m => ConduitT S.ByteString o m (Maybe Word8) head = do mbs <- await case mbs of Nothing -> return Nothing Just bs -> case S.uncons bs of Nothing -> head Just (w, bs') -> leftover bs' >> return (Just w) -- | Return all bytes while the predicate returns @True@. -- -- Since 0.3.0 takeWhile :: Monad m => (Word8 -> Bool) -> ConduitT S.ByteString S.ByteString m () takeWhile p = loop where loop = await >>= maybe (return ()) go go bs | S.null x = next | otherwise = yield x >> next where next = if S.null y then loop else leftover y (x, y) = S.span p bs -- | Ignore all bytes while the predicate returns @True@. -- -- Since 0.3.0 dropWhile :: Monad m => (Word8 -> Bool) -> ConduitT S.ByteString o m () dropWhile p = loop where loop = do mbs <- await case S.dropWhile p <$> mbs of Nothing -> return () Just bs | S.null bs -> loop | otherwise -> leftover bs -- | Take the given number of bytes, if available. -- -- Since 0.3.0 take :: Monad m => Int -> ConduitT S.ByteString o m L.ByteString take 0 = return L.empty take n0 = go n0 id where go n front = await >>= maybe (return $ L.fromChunks $ front []) go' where go' bs = case S.length bs `compare` n of LT -> go (n - S.length bs) (front . (bs:)) EQ -> return $ L.fromChunks $ front [bs] GT -> let (x, y) = S.splitAt n bs in assert (not $ S.null y) $ leftover y >> return (L.fromChunks $ front [x]) -- | Drop up to the given number of bytes. -- -- Since 0.5.0 drop :: Monad m => Int -> ConduitT S.ByteString o m () drop 0 = return () drop n0 = go n0 where go n = await >>= maybe (return ()) go' where go' bs = case S.length bs `compare` n of LT -> go (n - S.length bs) EQ -> return () GT -> let y = S.drop n bs in assert (not $ S.null y) $ leftover y >> return () -- | Split the input bytes into lines. In other words, split on the LF byte -- (10), and strip it from the output. -- -- Since 0.3.0 lines :: Monad m => ConduitT S.ByteString S.ByteString m () lines = loop [] where loop acc = await >>= maybe (finish acc) (go acc) finish acc = let final = S.concat $ reverse acc in unless (S.null final) (yield final) go acc more = case S.uncons second of Just (_, second') -> yield (S.concat $ reverse $ first:acc) >> go [] second' Nothing -> loop $ more:acc where (first, second) = S.break (== 10) more -- | Stream the chunks from a lazy bytestring. -- -- Since 0.5.0 sourceLbs :: Monad m => L.ByteString -> ConduitT i S.ByteString m () sourceLbs = sourceList . L.toChunks -- | Stream the input data into a temp file and count the number of bytes -- present. When complete, return a new @Source@ reading from the temp file -- together with the length of the input in bytes. -- -- All resources will be cleaned up automatically. -- -- Since 1.0.5 sinkCacheLength :: (MonadResource m1, MonadResource m2) => ConduitT S.ByteString o m1 (Word64, ConduitT i S.ByteString m2 ()) sinkCacheLength = do tmpdir <- liftIO getTemporaryDirectory (releaseKey, (fp, h)) <- allocate (IO.openBinaryTempFile tmpdir "conduit.cache") (\(fp, h) -> IO.hClose h `finally` removeFile fp) len <- sinkHandleLen h liftIO $ IO.hClose h return (len, CC.sourceFile fp >> release releaseKey) where sinkHandleLen :: MonadResource m => IO.Handle -> ConduitT S.ByteString o m Word64 sinkHandleLen h = loop 0 where loop x = await >>= maybe (return x) go where go bs = do liftIO $ S.hPut h bs loop $ x + fromIntegral (S.length bs) -- | Consume a stream of input into a lazy bytestring. Note that no lazy I\/O -- is performed, but rather all content is read into memory strictly. -- -- Since 1.0.5 sinkLbs :: Monad m => ConduitT S.ByteString o m L.ByteString sinkLbs = fmap L.fromChunks consume mapM_BS :: Monad m => (Word8 -> m ()) -> S.ByteString -> m () mapM_BS f (PS fptr offset len) = do let start = unsafeForeignPtrToPtr fptr `plusPtr` offset end = start `plusPtr` len loop ptr | ptr >= end = accursedUnutterablePerformIO (touchForeignPtr fptr) `seq` return () | otherwise = do f (accursedUnutterablePerformIO (peek ptr)) loop (ptr `plusPtr` 1) loop start {-# INLINE mapM_BS #-} -- | Perform a computation on each @Word8@ in a stream. -- -- Since 1.0.10 mapM_ :: Monad m => (Word8 -> m ()) -> ConduitT S.ByteString o m () mapM_ f = awaitForever (lift . mapM_BS f) {-# INLINE mapM_ #-} -- | Consume some instance of @Storable@ from the incoming byte stream. In the -- event of insufficient bytes in the stream, returns a @Nothing@ and returns -- all unused input as leftovers. -- -- @since 1.1.13 sinkStorable :: (Monad m, Storable a) => ConduitT S.ByteString o m (Maybe a) sinkStorable = sinkStorableHelper Just (return Nothing) -- | Same as 'sinkStorable', but throws a 'SinkStorableInsufficientBytes' -- exception (via 'throwM') in the event of insufficient bytes. This can be -- more efficient to use than 'sinkStorable' as it avoids the need to -- construct/deconstruct a @Maybe@ wrapper in the success case. -- -- @since 1.1.13 sinkStorableEx :: (MonadThrow m, Storable a) => ConduitT S.ByteString o m a sinkStorableEx = sinkStorableHelper id (throwM SinkStorableInsufficientBytes) sinkStorableHelper :: forall m a b o. (Monad m, Storable a) => (a -> b) -> (ConduitT S.ByteString o m b) -> ConduitT S.ByteString o m b sinkStorableHelper wrap failure = do start where size = sizeOf (undefined :: a) -- try the optimal case: next chunk has all the data we need start = do mbs <- await case mbs of Nothing -> failure Just bs | S.null bs -> start | otherwise -> case compare (S.length bs) size of LT -> do -- looks like we're stuck concating leftover bs lbs <- take size let bs' = S.concat $ L.toChunks lbs case compare (S.length bs') size of LT -> do leftover bs' failure EQ -> process bs' GT -> assert False (process bs') EQ -> process bs GT -> do let (x, y) = S.splitAt size bs leftover y process x -- Given a bytestring of exactly the correct size, grab the value process bs = return $! wrap $! accursedUnutterablePerformIO $! unsafeUseAsCString bs (safePeek undefined . castPtr) safePeek :: a -> Ptr a -> IO a #ifdef ALLOW_UNALIGNED_ACCESS safePeek _ = peek #else safePeek val ptr = alloca (\t -> copyBytes t ptr (sizeOf val) >> peek t) #endif {-# INLINE sinkStorableHelper #-} data SinkStorableException = SinkStorableInsufficientBytes deriving (Show, Typeable) instance Exception SinkStorableException conduit-extra-1.3.5/Data/Conduit/ByteString/Builder.hs0000644000000000000000000000161613626670615021006 0ustar0000000000000000{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE RankNTypes #-} -- | Convert a stream of blaze-builder @Builder@s into a stream of @ByteString@s. -- -- Works with both blaze-builder < 0.4's @Builder@s and -- 'Data.ByteString.Builder.Builder'. -- -- Adapted from blaze-builder-enumerator, written by myself and Simon Meier. -- -- Note that the functions here can work in any monad built on top of @IO@ or -- @ST@. -- -- Since 1.1.7.0 -- module Data.Conduit.ByteString.Builder ( -- * Conduits from builders to bytestrings CC.builderToByteString , CC.unsafeBuilderToByteString , CC.builderToByteStringWith -- ** Flush , CC.builderToByteStringFlush , CC.builderToByteStringWithFlush -- * Buffer allocation strategies , CC.BufferAllocStrategy , CC.allNewBuffersStrategy , CC.reuseBufferStrategy ) where import qualified Data.Conduit.Combinators as CC conduit-extra-1.3.5/Data/Conduit/Filesystem.hs0000644000000000000000000000042113626670615017443 0ustar0000000000000000{-# LANGUAGE RankNTypes #-} -- | /NOTE/ It is recommended to start using "Data.Conduit.Combinators" instead -- of this module. module Data.Conduit.Filesystem ( CC.sourceDirectory , CC.sourceDirectoryDeep ) where import qualified Data.Conduit.Combinators as CC conduit-extra-1.3.5/Data/Conduit/Foldl.hs0000644000000000000000000000172013626670615016362 0ustar0000000000000000{-# LANGUAGE RankNTypes #-} -- | Adapter module to work with the package. -- -- @since 1.1.16 module Data.Conduit.Foldl where import Data.Conduit import Control.Monad.Trans.Class (lift) import qualified Data.Conduit.List as CL -- | Convert a left fold into a 'Consumer'. This function is intended -- to be used with @purely@ from the -- package. -- -- @since 1.1.16 sinkFold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> ConduitT a o m b sinkFold combine seed extract = fmap extract (CL.fold combine seed) -- | Convert a monadic left fold into a 'Consumer'. This function is -- intended to be used with @impurely@ from the -- package. -- -- @since 1.1.16 sinkFoldM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> ConduitT a o m b sinkFoldM combine seed extract = lift . extract =<< CL.foldM combine =<< lift seed conduit-extra-1.3.5/Data/Conduit/Lazy.hs0000644000000000000000000000772113626670615016250 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-deprecations #-} -- Suppress warnings around Control.Monad.Trans.Error -- | Use lazy I\/O for consuming the contents of a source. Warning: All normal -- warnings of lazy I\/O apply. In particular, if you are using this with a -- @ResourceT@ transformer, you must force the list to be evaluated before -- exiting the @ResourceT@. module Data.Conduit.Lazy ( lazyConsume , MonadActive (..) ) where import Data.Conduit import Data.Conduit.Internal (Pipe (..), ConduitT (..)) import System.IO.Unsafe (unsafeInterleaveIO) import Control.Monad.Trans.Class (lift) import Control.Monad.IO.Unlift (MonadIO, liftIO, MonadUnliftIO, withUnliftIO, unliftIO) import Control.Monad.Trans.Identity ( IdentityT) import Control.Monad.Trans.List ( ListT ) import Control.Monad.Trans.Maybe ( MaybeT ) import Control.Monad.Trans.Error ( ErrorT, Error) import Control.Monad.Trans.Reader ( ReaderT ) import Control.Monad.Trans.State ( StateT ) import Control.Monad.Trans.Writer ( WriterT ) import Control.Monad.Trans.RWS ( RWST ) import qualified Control.Monad.Trans.RWS.Strict as Strict ( RWST ) import qualified Control.Monad.Trans.State.Strict as Strict ( StateT ) import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT ) #if (__GLASGOW_HASKELL__ < 710) import Data.Monoid (Monoid) #endif import Control.Monad.ST (ST) import qualified Control.Monad.ST.Lazy as Lazy import Data.Functor.Identity (Identity) import Control.Monad.Trans.Resource.Internal (ResourceT (ResourceT), ReleaseMap (ReleaseMapClosed)) import qualified Data.IORef as I -- | Use lazy I\/O to consume all elements from a @Source@. -- -- This function relies on 'monadActive' to determine if the underlying monadic -- state has been closed. -- -- Since 0.3.0 lazyConsume :: forall m a. (MonadUnliftIO m, MonadActive m) => Source m a -> m [a] lazyConsume (ConduitT f0) = withUnliftIO $ \u -> let go :: Pipe () () a () m () -> IO [a] go (Done _) = return [] go (HaveOutput src x) = do xs <- unsafeInterleaveIO $ go src return $ x : xs go (PipeM msrc) = unsafeInterleaveIO $ do a <- unliftIO u monadActive if a then unliftIO u msrc >>= go else return [] go (NeedInput _ c) = go (c ()) go (Leftover p _) = go p in go (f0 Done) -- | Determine if some monad is still active. This is intended to prevent usage -- of a monadic state after it has been closed. This is necessary for such -- cases as lazy I\/O, where an unevaluated thunk may still refer to a -- closed @ResourceT@. -- -- Since 0.3.0 class Monad m => MonadActive m where monadActive :: m Bool instance (MonadIO m, MonadActive m) => MonadActive (ResourceT m) where monadActive = ResourceT $ \rmMap -> do rm <- liftIO $ I.readIORef rmMap case rm of ReleaseMapClosed -> return False _ -> monadActive -- recurse instance MonadActive Identity where monadActive = return True instance MonadActive IO where monadActive = return True instance MonadActive (ST s) where monadActive = return True instance MonadActive (Lazy.ST s) where monadActive = return True #define GO(T) instance MonadActive m => MonadActive (T m) where monadActive = lift monadActive #define GOX(X, T) instance (X, MonadActive m) => MonadActive (T m) where monadActive = lift monadActive GO(IdentityT) GO(ListT) GO(MaybeT) GOX(Error e, ErrorT e) GO(ReaderT r) GO(StateT s) GOX(Monoid w, WriterT w) GOX(Monoid w, RWST r w s) GOX(Monoid w, Strict.RWST r w s) GO(Strict.StateT s) GOX(Monoid w, Strict.WriterT w) #undef GO #undef GOX instance MonadActive m => MonadActive (Pipe l i o u m) where monadActive = lift monadActive instance MonadActive m => MonadActive (ConduitT i o m) where monadActive = lift monadActive conduit-extra-1.3.5/Data/Conduit/Network.hs0000644000000000000000000001106213626670615016753 0ustar0000000000000000{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE CPP #-} module Data.Conduit.Network ( -- * Basic utilities sourceSocket , sinkSocket -- * Simple TCP server/client interface. , SN.AppData , appSource , appSink , SN.appSockAddr , SN.appLocalAddr -- ** Server , SN.ServerSettings , serverSettings , SN.runTCPServer , SN.runTCPServerWithHandle , forkTCPServer , runGeneralTCPServer -- ** Client , SN.ClientSettings , clientSettings , SN.runTCPClient , runGeneralTCPClient -- ** Getters , SN.getPort , SN.getHost , SN.getAfterBind , SN.getNeedLocalAddr -- ** Setters , SN.setPort , SN.setHost , SN.setAfterBind , SN.setNeedLocalAddr -- * Types , SN.HostPreference ) where import Prelude import Data.Conduit import Network.Socket (Socket) import Network.Socket.ByteString (sendAll) import Data.ByteString (ByteString) import qualified GHC.Conc as Conc (yield) import qualified Data.ByteString as S import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad (unless) import Control.Monad.Trans.Class (lift) import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar, MVar, ThreadId) import qualified Data.Streaming.Network as SN import Control.Monad.IO.Unlift (MonadUnliftIO, withRunInIO) -- | Stream data from the socket. -- -- This function does /not/ automatically close the socket. -- -- Since 0.0.0 sourceSocket :: MonadIO m => Socket -> ConduitT i ByteString m () sourceSocket socket = loop where loop = do bs <- lift $ liftIO $ SN.safeRecv socket 4096 if S.null bs then return () else yield bs >> loop -- | Stream data to the socket. -- -- This function does /not/ automatically close the socket. -- -- Since 0.0.0 sinkSocket :: MonadIO m => Socket -> ConduitT ByteString o m () sinkSocket socket = loop where loop = await >>= maybe (return ()) (\bs -> lift (liftIO $ sendAll socket bs) >> loop) serverSettings :: Int -> SN.HostPreference -> SN.ServerSettings serverSettings = SN.serverSettingsTCP clientSettings :: Int -> ByteString -> SN.ClientSettings clientSettings = SN.clientSettingsTCP appSource :: (SN.HasReadWrite ad, MonadIO m) => ad -> ConduitT i ByteString m () appSource ad = loop where read' = SN.appRead ad loop = do bs <- liftIO read' unless (S.null bs) $ do yield bs loop appSink :: (SN.HasReadWrite ad, MonadIO m) => ad -> ConduitT ByteString o m () appSink ad = awaitForever $ \d -> liftIO $ SN.appWrite ad d >> Conc.yield addBoundSignal::MVar ()-> SN.ServerSettings -> SN.ServerSettings addBoundSignal isBound set = SN.setAfterBind ( \socket -> originalAfterBind socket >> signalBound socket) set where originalAfterBind :: Socket -> IO () originalAfterBind = SN.getAfterBind set signalBound :: Socket -> IO () signalBound _socket = putMVar isBound () -- | Fork a TCP Server -- -- Will fork the runGeneralTCPServer function but will only return from -- this call when the server is bound to the port and accepting incoming -- connections. Will return the thread id of the server -- -- Since 1.1.4 forkTCPServer :: MonadUnliftIO m => SN.ServerSettings -> (SN.AppData -> m ()) -> m ThreadId forkTCPServer set f = withRunInIO $ \run -> do isBound <- newEmptyMVar let setWithWaitForBind = addBoundSignal isBound set threadId <- forkIO . run $ runGeneralTCPServer setWithWaitForBind f takeMVar isBound return threadId -- | Run a general TCP server -- -- Same as 'SN.runTCPServer', except monad can be any instance of -- 'MonadUnliftIO'. -- -- Note that any changes to the monadic state performed by individual -- client handlers will be discarded. If you have mutable state you want -- to share among multiple handlers, you need to use some kind of mutable -- variables. -- -- Since 1.1.3 runGeneralTCPServer :: MonadUnliftIO m => SN.ServerSettings -> (SN.AppData -> m ()) -> m a runGeneralTCPServer set f = withRunInIO $ \run -> SN.runTCPServer set $ run . f -- | Run a general TCP client -- -- Same as 'SN.runTCPClient', except monad can be any instance of 'MonadUnliftIO'. -- -- Since 1.1.3 runGeneralTCPClient :: MonadUnliftIO m => SN.ClientSettings -> (SN.AppData -> m a) -> m a runGeneralTCPClient set f = withRunInIO $ \run -> SN.runTCPClient set $ run . f conduit-extra-1.3.5/Data/Conduit/Network/UDP.hs0000644000000000000000000000553613626670615017414 0ustar0000000000000000{-# LANGUAGE RankNTypes #-} module Data.Conduit.Network.UDP ( -- * UDP message representation SN.Message (..) -- * Basic utilities , sourceSocket , sinkSocket , sinkAllSocket , sinkToSocket , sinkAllToSocket -- * Helper Utilities , SN.HostPreference ) where import Data.Conduit import Network.Socket (Socket) import Network.Socket.ByteString (recvFrom, send, sendAll, sendTo, sendAllTo) import Data.ByteString (ByteString) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad (void) import Control.Monad.Trans.Class (lift) import qualified Data.Streaming.Network as SN -- | Stream messages from the socket. -- -- The given @len@ defines the maximum packet size. Every produced item -- contains the message payload and the origin address. -- -- This function does /not/ automatically close the socket. sourceSocket :: MonadIO m => Socket -> Int -> ConduitT i SN.Message m () sourceSocket socket len = loop where loop = do (bs, addr) <- lift $ liftIO $ recvFrom socket len yield (SN.Message bs addr) >> loop -- | Stream messages to the connected socket. -- -- The payload is sent using @send@, so some of it might be lost. -- -- This function does /not/ automatically close the socket. sinkSocket :: MonadIO m => Socket -> ConduitT ByteString o m () sinkSocket = sinkSocketHelper (\sock bs -> void $ send sock bs) -- | Stream messages to the connected socket. -- -- The payload is sent using @sendAll@, so it might end up in multiple packets. -- -- This function does /not/ automatically close the socket. sinkAllSocket :: MonadIO m => Socket -> ConduitT ByteString o m () sinkAllSocket = sinkSocketHelper sendAll -- | Stream messages to the socket. -- -- Every handled item contains the message payload and the destination -- address. The payload is sent using @sendTo@, so some of it might be -- lost. -- -- This function does /not/ automatically close the socket. sinkToSocket :: MonadIO m => Socket -> ConduitT SN.Message o m () sinkToSocket = sinkSocketHelper (\sock (SN.Message bs addr) -> void $ sendTo sock bs addr) -- | Stream messages to the socket. -- -- Every handled item contains the message payload and the destination -- address. The payload is sent using @sendAllTo@, so it might end up in -- multiple packets. -- -- This function does /not/ automatically close the socket. sinkAllToSocket :: MonadIO m => Socket -> ConduitT SN.Message o m () sinkAllToSocket = sinkSocketHelper (\sock (SN.Message bs addr) -> sendAllTo sock bs addr) -- Internal sinkSocketHelper :: MonadIO m => (Socket -> a -> IO ()) -> Socket -> ConduitT a o m () sinkSocketHelper act socket = loop where loop = await >>= maybe (return ()) (\a -> lift (liftIO $ act socket a) >> loop) {-# INLINE sinkSocketHelper #-} conduit-extra-1.3.5/Data/Conduit/Process.hs0000644000000000000000000001720413626670615016744 0ustar0000000000000000{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | A full tutorial for this module is available at: -- . -- -- Note that this is a very thin layer around the @Data.Streaming.Process@ module. In particular, it: -- -- * Provides orphan instances for conduit -- -- * Provides some useful helper functions module Data.Conduit.Process ( -- * Functions sourceCmdWithConsumer , sourceProcessWithConsumer , sourceCmdWithStreams , sourceProcessWithStreams , withCheckedProcessCleanup -- * InputSource types , FlushInput(..) , BuilderInput(..) -- * Reexport , module Data.Streaming.Process ) where import Data.Streaming.Process import Data.Streaming.Process.Internal import System.Exit (ExitCode (..)) import Control.Monad.IO.Unlift (MonadIO, liftIO, MonadUnliftIO, withRunInIO, withUnliftIO, unliftIO) import System.IO (hClose, BufferMode (NoBuffering), hSetBuffering) import Data.Conduit import Data.Functor (($>)) import Data.Conduit.Binary (sourceHandle, sinkHandle, sinkHandleBuilder, sinkHandleFlush) import Data.ByteString (ByteString) import Data.ByteString.Builder (Builder) import Control.Concurrent.Async (runConcurrently, Concurrently(..)) import Control.Exception (onException, throwIO, finally, bracket) #if (__GLASGOW_HASKELL__ < 710) import Control.Applicative ((<$>), (<*>)) #endif instance (r ~ (), MonadIO m, i ~ ByteString) => InputSource (ConduitM i o m r) where isStdStream = (\(Just h) -> hSetBuffering h NoBuffering $> sinkHandle h, Just CreatePipe) instance (r ~ (), r' ~ (), MonadIO m, MonadIO n, i ~ ByteString) => InputSource (ConduitM i o m r, n r') where isStdStream = (\(Just h) -> hSetBuffering h NoBuffering $> (sinkHandle h, liftIO $ hClose h), Just CreatePipe) -- | Wrapper for input source which accepts 'Data.ByteString.Builder.Builder's. -- You can pass 'Data.ByteString.Builder.Extra.flush' to flush the input. Note -- that the pipe will /not/ automatically close when the processing completes. -- -- @since 1.3.2 newtype BuilderInput o m r = BuilderInput (ConduitM Builder o m r) -- | Wrapper for input source which accepts @Flush@es. Note that the pipe -- will /not/ automatically close then processing completes. -- -- @since 1.3.2 newtype FlushInput o m r = FlushInput (ConduitM (Flush ByteString) o m r) instance (MonadIO m, r ~ ()) => InputSource (BuilderInput o m r) where isStdStream = (\(Just h) -> return $ BuilderInput $ sinkHandleBuilder h, Just CreatePipe) instance (MonadIO m, MonadIO n, r ~ (), r' ~ ()) => InputSource (BuilderInput o m r, n r') where isStdStream = (\(Just h) -> return (BuilderInput $ sinkHandleBuilder h, liftIO $ hClose h), Just CreatePipe) instance (MonadIO m, r ~ ()) => InputSource (FlushInput o m r) where isStdStream = (\(Just h) -> return $ FlushInput $ sinkHandleFlush h, Just CreatePipe) instance (MonadIO m, MonadIO n, r ~ (), r' ~ ()) => InputSource (FlushInput o m r, n r') where isStdStream = (\(Just h) -> return (FlushInput $ sinkHandleFlush h, liftIO $ hClose h), Just CreatePipe) instance (r ~ (), MonadIO m, o ~ ByteString) => OutputSink (ConduitM i o m r) where osStdStream = (\(Just h) -> hSetBuffering h NoBuffering $> sourceHandle h, Just CreatePipe) instance (r ~ (), r' ~ (), MonadIO m, MonadIO n, o ~ ByteString) => OutputSink (ConduitM i o m r, n r') where osStdStream = (\(Just h) -> hSetBuffering h NoBuffering $> (sourceHandle h, liftIO $ hClose h), Just CreatePipe) -- | Given a @CreateProcess@, run the process, with its output being used as a -- @Source@ to feed the provided @Consumer@. Once the process has completed, -- return a tuple of the @ExitCode@ from the process and the output collected -- from the @Consumer@. -- -- Note that, if an exception is raised by the consumer, the process is /not/ -- terminated. This behavior is different from 'sourceProcessWithStreams' due -- to historical reasons. -- -- Since 1.1.2 sourceProcessWithConsumer :: MonadIO m => CreateProcess -> ConduitT ByteString Void m a -- ^ stdout -> m (ExitCode, a) sourceProcessWithConsumer cp consumer = do (ClosedStream, (source, close), ClosedStream, cph) <- streamingProcess cp res <- runConduit $ source .| consumer close ec <- waitForStreamingProcess cph return (ec, res) -- | Like @sourceProcessWithConsumer@ but providing the command to be run as -- a @String@. -- -- Since 1.1.2 sourceCmdWithConsumer :: MonadIO m => String -- ^command -> ConduitT ByteString Void m a -- ^stdout -> m (ExitCode, a) sourceCmdWithConsumer cmd = sourceProcessWithConsumer (shell cmd) -- | Given a @CreateProcess@, run the process -- and feed the provided @Producer@ -- to the stdin @Sink@ of the process. -- Use the process outputs (stdout, stderr) as @Source@s -- and feed it to the provided @Consumer@s. -- Once the process has completed, -- return a tuple of the @ExitCode@ from the process -- and the results collected from the @Consumer@s. -- -- If an exception is raised by any of the streams, -- the process is terminated. -- -- IO is required because the streams are run concurrently -- using the package -- -- @since 1.1.12 sourceProcessWithStreams :: MonadUnliftIO m => CreateProcess -> ConduitT () ByteString m () -- ^stdin -> ConduitT ByteString Void m a -- ^stdout -> ConduitT ByteString Void m b -- ^stderr -> m (ExitCode, a, b) sourceProcessWithStreams cp producerStdin consumerStdout consumerStderr = withUnliftIO $ \u -> do ( (sinkStdin, closeStdin) , (sourceStdout, closeStdout) , (sourceStderr, closeStderr) , sph) <- streamingProcess cp (_, resStdout, resStderr) <- runConcurrently ( (,,) <$> Concurrently ((unliftIO u $ runConduit $ producerStdin .| sinkStdin) `finally` closeStdin) <*> Concurrently (unliftIO u $ runConduit $ sourceStdout .| consumerStdout) <*> Concurrently (unliftIO u $ runConduit $ sourceStderr .| consumerStderr)) `finally` (closeStdout >> closeStderr) `onException` terminateStreamingProcess sph ec <- waitForStreamingProcess sph return (ec, resStdout, resStderr) -- | Like @sourceProcessWithStreams@ but providing the command to be run as -- a @String@. -- -- @since 1.1.12 sourceCmdWithStreams :: MonadUnliftIO m => String -- ^command -> ConduitT () ByteString m () -- ^stdin -> ConduitT ByteString Void m a -- ^stdout -> ConduitT ByteString Void m b -- ^stderr -> m (ExitCode, a, b) sourceCmdWithStreams cmd = sourceProcessWithStreams (shell cmd) -- | Same as 'withCheckedProcess', but kills the child process in the case of -- an exception being thrown by the provided callback function. -- -- @since 1.1.11 withCheckedProcessCleanup :: ( InputSource stdin , OutputSink stderr , OutputSink stdout , MonadUnliftIO m ) => CreateProcess -> (stdin -> stdout -> stderr -> m b) -> m b withCheckedProcessCleanup cp f = withRunInIO $ \run -> bracket (streamingProcess cp) (\(_, _, _, sph) -> closeStreamingProcessHandle sph) $ \(x, y, z, sph) -> do res <- run (f x y z) `onException` terminateStreamingProcess sph ec <- waitForStreamingProcess sph if ec == ExitSuccess then return res else throwIO $ ProcessExitedUnsuccessfully cp ec terminateStreamingProcess :: MonadIO m => StreamingProcessHandle -> m () terminateStreamingProcess = liftIO . terminateProcess . streamingProcessHandleRaw conduit-extra-1.3.5/Data/Conduit/Process/Typed.hs0000644000000000000000000000761113634620702020021 0ustar0000000000000000{-# LANGUAGE DataKinds #-} -- | The "System.Process.Typed" module from @typed-process@, but with -- added conduit helpers. module Data.Conduit.Process.Typed ( -- * Conduit specific stuff createSink , createSinkClose , createSource -- * Running a process with logging , withLoggedProcess_ -- * Reexports , module System.Process.Typed ) where import System.Process.Typed import qualified System.Process.Typed as P import Data.Conduit (ConduitM, (.|), runConduit) import qualified Data.Conduit.Binary as CB import Control.Monad.IO.Unlift import qualified Data.ByteString as S import qualified Data.Conduit.List as CL import qualified Data.ByteString.Lazy as BL import Data.IORef (IORef, newIORef, readIORef, modifyIORef) import Control.Exception (throwIO, catch) import Control.Concurrent.Async (concurrently) import System.IO (hSetBuffering, BufferMode (NoBuffering), hClose) -- | Provide input to a process by writing to a conduit. The sink provided here -- will leave the pipe to the child open after the stream ends. This allows the -- sink to be used multiple times, but may result in surprising behavior. You -- may prefer 'createSinkClose', see -- . -- -- @since 1.2.1 createSink :: MonadIO m => StreamSpec 'STInput (ConduitM S.ByteString o m ()) createSink = (\h -> liftIO (hSetBuffering h NoBuffering) >> CB.sinkHandle h) `fmap` createPipe -- | Like 'createSink', but closes the pipe to the child process as soon as it -- runs out of data. -- -- @since 1.3.5 createSinkClose :: MonadIO m => StreamSpec 'STInput (ConduitM S.ByteString o m ()) createSinkClose = (\h -> liftIO (hSetBuffering h NoBuffering) >> CB.sinkHandle h >> liftIO (hClose h)) `fmap` createPipe -- | Read output from a process by read from a conduit. -- -- @since 1.2.1 createSource :: MonadIO m => StreamSpec 'STOutput (ConduitM i S.ByteString m ()) createSource = (\h -> liftIO (hSetBuffering h NoBuffering) >> CB.sourceHandle h) `fmap` createPipe -- | Internal function: like 'createSource', but stick all chunks into -- the 'IORef'. createSourceLogged :: MonadIO m => IORef ([S.ByteString] -> [S.ByteString]) -> StreamSpec 'STOutput (ConduitM i S.ByteString m ()) createSourceLogged ref = -- We do not add a cleanup action to close the handle, since in -- withLoggedProcess_ we attempt to read from the handle twice (\h -> ( CB.sourceHandle h .| CL.iterM (\bs -> liftIO $ modifyIORef ref (. (bs:)))) ) `fmap` createPipe -- | Run a process, throwing an exception on a failure exit code. This -- will store all output from stdout and stderr in memory for better -- error messages. Note that this will require unbounded memory usage, -- so caveat emptor. -- -- This will ignore any previous settings for the stdout and stderr -- streams, and instead force them to use 'createSource'. -- -- @since 1.2.3 withLoggedProcess_ :: MonadUnliftIO m => ProcessConfig stdin stdoutIgnored stderrIgnored -> (Process stdin (ConduitM () S.ByteString m ()) (ConduitM () S.ByteString m ()) -> m a) -> m a withLoggedProcess_ pc inner = withUnliftIO $ \u -> do stdoutBuffer <- newIORef id stderrBuffer <- newIORef id let pc' = setStdout (createSourceLogged stdoutBuffer) $ setStderr (createSourceLogged stderrBuffer) pc -- withProcessWait vs Term doesn't actually matter here, since we -- call checkExitCode inside regardless. But still, Wait is the -- safer function to use in general. P.withProcessWait pc' $ \p -> do a <- unliftIO u $ inner p let drain src = unliftIO u (runConduit (src .| CL.sinkNull)) ((), ()) <- drain (getStdout p) `concurrently` drain (getStderr p) checkExitCode p `catch` \ece -> do stdout <- readIORef stdoutBuffer stderr <- readIORef stderrBuffer throwIO ece { eceStdout = BL.fromChunks $ stdout [] , eceStderr = BL.fromChunks $ stderr [] } return a conduit-extra-1.3.5/Data/Conduit/Text.hs0000644000000000000000000003047413626670615016256 0ustar0000000000000000{-# LANGUAGE DeriveDataTypeable, RankNTypes #-} -- | /NOTE/ It is recommended to start using "Data.Conduit.Combinators" instead -- of this module. -- -- Copyright: 2011 Michael Snoyman, 2010-2011 John Millikin -- License: MIT -- -- Handle streams of text. -- -- Parts of this code were taken from enumerator and adapted for conduits. -- -- For many purposes, it's recommended to use the conduit-combinators library, -- which provides a more complete set of functions. module Data.Conduit.Text ( -- * Text codecs Codec , encode , decode , utf8 , utf16_le , utf16_be , utf32_le , utf32_be , ascii , iso8859_1 , lines , linesBounded , TextException (..) , takeWhile , dropWhile , take , drop , foldLines , withLine , CC.decodeUtf8 , CC.decodeUtf8Lenient , CC.encodeUtf8 , detectUtf ) where import Prelude hiding (head, drop, takeWhile, lines, zip, zip3, zipWith, zipWith3, take, dropWhile) import qualified Control.Exception as Exc import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as B8 import Data.Char (ord) import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Data.Word (Word8) import Data.Typeable (Typeable) import Data.Conduit import qualified Data.Conduit.List as CL import qualified Data.Conduit.Combinators as CC import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Resource (MonadThrow, throwM) import Control.Monad (unless) import Data.Streaming.Text -- | A specific character encoding. -- -- Since 0.3.0 data Codec = Codec { _codecName :: T.Text , codecEncode :: T.Text -> (B.ByteString, Maybe (TextException, T.Text)) , codecDecode :: B.ByteString -> (T.Text, Either (TextException, B.ByteString) B.ByteString) } | NewCodec T.Text (T.Text -> B.ByteString) (B.ByteString -> DecodeResult) instance Show Codec where showsPrec d c = let (cnst, name) = case c of Codec t _ _ -> ("Codec ", t) NewCodec t _ _ -> ("NewCodec ", t) in showParen (d > 10) $ showString cnst . shows name -- | Emit each line separately -- -- Since 0.4.1 lines :: Monad m => ConduitT T.Text T.Text m () lines = awaitText id where awaitText front = await >>= maybe (finish front) (process front) finish front = let t = T.concat $ front [] in unless (T.null t) (yield t) process front text = let (line, rest) = T.break (== '\n') text in case T.uncons rest of Just (_, rest') -> do yield (T.concat $ front [line]) process id rest' Nothing -> Exc.assert (line == text) $ awaitText $ front . (line:) -- | Variant of the lines function with an integer parameter. -- The text length of any emitted line -- never exceeds the value of the parameter. Whenever -- this is about to happen a LengthExceeded exception -- is thrown. This function should be used instead -- of the lines function whenever we are dealing with -- user input (e.g. a file upload) because we can't be sure that -- user input won't have extraordinarily large lines which would -- require large amounts of memory if consumed. linesBounded :: MonadThrow m => Int -> ConduitT T.Text T.Text m () linesBounded maxLineLen = awaitText 0 T.empty where awaitText len buf = await >>= maybe (finish buf) (process len buf) finish buf = unless (T.null buf) (yield buf) process len buf text = let (line, rest) = T.break (== '\n') text len' = len + T.length line in if len' > maxLineLen then lift $ throwM (LengthExceeded maxLineLen) else case T.uncons rest of Just (_, rest') -> yield (buf `T.append` line) >> process 0 T.empty rest' _ -> awaitText len' $ buf `T.append` text -- | Convert text into bytes, using the provided codec. If the codec is -- not capable of representing an input character, an exception will be thrown. -- -- Since 0.3.0 encode :: MonadThrow m => Codec -> ConduitT T.Text B.ByteString m () encode (NewCodec _ enc _) = CL.map enc encode codec = CL.mapM $ \t -> do let (bs, mexc) = codecEncode codec t maybe (return bs) (throwM . fst) mexc decodeNew :: Monad m => (Int -> B.ByteString -> T.Text -> B.ByteString -> ConduitT B.ByteString T.Text m ()) -> t -> Int -> (B.ByteString -> DecodeResult) -> ConduitT B.ByteString T.Text m () decodeNew onFailure _name = loop where loop consumed dec = await >>= maybe finish go where finish = case dec B.empty of DecodeResultSuccess _ _ -> return () DecodeResultFailure t rest -> onFailure consumed B.empty t rest {-# INLINE finish #-} go bs | B.null bs = loop consumed dec go bs = case dec bs of DecodeResultSuccess t dec' -> do let consumed' = consumed + B.length bs next = do unless (T.null t) (yield t) loop consumed' dec' in consumed' `seq` next DecodeResultFailure t rest -> onFailure consumed bs t rest -- | Convert bytes into text, using the provided codec. If the codec is -- not capable of decoding an input byte sequence, an exception will be thrown. -- -- Since 0.3.0 decode :: MonadThrow m => Codec -> ConduitT B.ByteString T.Text m () decode (NewCodec name _ start) = decodeNew onFailure name 0 start where onFailure consumed bs t rest = do unless (T.null t) (yield t) leftover rest -- rest will never be null, no need to check let consumed' = consumed + B.length bs - B.length rest throwM $ NewDecodeException name consumed' (B.take 4 rest) {-# INLINE onFailure #-} decode codec = loop id where loop front = await >>= maybe (finish front) (go front) finish front = case B.uncons $ front B.empty of Nothing -> return () Just (w, _) -> lift $ throwM $ DecodeException codec w go front bs' = case extra of Left (exc, _) -> lift $ throwM exc Right bs'' -> yield text >> loop (B.append bs'') where (text, extra) = codecDecode codec bs bs = front bs' -- | -- Since 0.3.0 data TextException = DecodeException Codec Word8 | EncodeException Codec Char | LengthExceeded Int | TextException Exc.SomeException | NewDecodeException !T.Text !Int !B.ByteString deriving Typeable instance Show TextException where show (DecodeException codec w) = concat [ "Error decoding legacy Data.Conduit.Text codec " , show codec , " when parsing byte: " , show w ] show (EncodeException codec c) = concat [ "Error encoding legacy Data.Conduit.Text codec " , show codec , " when parsing char: " , show c ] show (LengthExceeded i) = "Data.Conduit.Text.linesBounded: line too long: " ++ show i show (TextException se) = "Data.Conduit.Text.TextException: " ++ show se show (NewDecodeException codec consumed next) = concat [ "Data.Conduit.Text.decode: Error decoding stream of " , T.unpack codec , " bytes. Error encountered in stream at offset " , show consumed , ". Encountered at byte sequence " , show next ] instance Exc.Exception TextException -- | -- Since 0.3.0 utf8 :: Codec utf8 = NewCodec (T.pack "UTF-8") TE.encodeUtf8 Data.Streaming.Text.decodeUtf8 -- | -- Since 0.3.0 utf16_le :: Codec utf16_le = NewCodec (T.pack "UTF-16-LE") TE.encodeUtf16LE decodeUtf16LE -- | -- Since 0.3.0 utf16_be :: Codec utf16_be = NewCodec (T.pack "UTF-16-BE") TE.encodeUtf16BE decodeUtf16BE -- | -- Since 0.3.0 utf32_le :: Codec utf32_le = NewCodec (T.pack "UTF-32-LE") TE.encodeUtf32LE decodeUtf32LE -- | -- Since 0.3.0 utf32_be :: Codec utf32_be = NewCodec (T.pack "UTF-32-BE") TE.encodeUtf32BE decodeUtf32BE -- | -- Since 0.3.0 ascii :: Codec ascii = Codec name enc dec where name = T.pack "ASCII" enc text = (bytes, extra) where (safe, unsafe) = T.span (\c -> ord c <= 0x7F) text bytes = B8.pack (T.unpack safe) extra = if T.null unsafe then Nothing else Just (EncodeException ascii (T.head unsafe), unsafe) dec bytes = (text, extra) where (safe, unsafe) = B.span (<= 0x7F) bytes text = T.pack (B8.unpack safe) extra = if B.null unsafe then Right B.empty else Left (DecodeException ascii (B.head unsafe), unsafe) -- | -- Since 0.3.0 iso8859_1 :: Codec iso8859_1 = Codec name enc dec where name = T.pack "ISO-8859-1" enc text = (bytes, extra) where (safe, unsafe) = T.span (\c -> ord c <= 0xFF) text bytes = B8.pack (T.unpack safe) extra = if T.null unsafe then Nothing else Just (EncodeException iso8859_1 (T.head unsafe), unsafe) dec bytes = (T.pack (B8.unpack bytes), Right B.empty) -- | -- -- Since 1.0.8 takeWhile :: Monad m => (Char -> Bool) -> ConduitT T.Text T.Text m () takeWhile p = loop where loop = await >>= maybe (return ()) go go t = case T.span p t of (x, y) | T.null y -> yield x >> loop | otherwise -> yield x >> leftover y -- | -- -- Since 1.0.8 dropWhile :: Monad m => (Char -> Bool) -> ConduitT T.Text o m () dropWhile p = loop where loop = await >>= maybe (return ()) go go t | T.null x = loop | otherwise = leftover x where x = T.dropWhile p t -- | -- -- Since 1.0.8 take :: Monad m => Int -> ConduitT T.Text T.Text m () take = loop where loop i = await >>= maybe (return ()) (go i) go i t | diff == 0 = yield t | diff < 0 = let (x, y) = T.splitAt i t in yield x >> leftover y | otherwise = yield t >> loop diff where diff = i - T.length t -- | -- -- Since 1.0.8 drop :: Monad m => Int -> ConduitT T.Text o m () drop = loop where loop i = await >>= maybe (return ()) (go i) go i t | diff == 0 = return () | diff < 0 = leftover $ T.drop i t | otherwise = loop diff where diff = i - T.length t -- | -- -- Since 1.0.8 foldLines :: Monad m => (a -> ConduitM T.Text o m a) -> a -> ConduitT T.Text o m a foldLines f = start where start a = CL.peek >>= maybe (return a) (const $ loop $ f a) loop consumer = do a <- takeWhile (/= '\n') .| do a <- CL.map (T.filter (/= '\r')) .| consumer CL.sinkNull return a drop 1 start a -- | -- -- Since 1.0.8 withLine :: Monad m => ConduitT T.Text Void m a -> ConduitT T.Text o m (Maybe a) withLine consumer = toConsumer $ do mx <- CL.peek case mx of Nothing -> return Nothing Just _ -> do x <- takeWhile (/= '\n') .| do x <- CL.map (T.filter (/= '\r')) .| consumer CL.sinkNull return x drop 1 return $ Just x -- | Automatically determine which UTF variant is being used. This function -- checks for BOMs, removing them as necessary. It defaults to assuming UTF-8. -- -- Since 1.1.9 detectUtf :: MonadThrow m => ConduitT B.ByteString T.Text m () detectUtf = go id where go front = await >>= maybe (close front) (push front) push front bs' | B.length bs < 4 = go $ B.append bs | otherwise = leftDecode bs where bs = front bs' close front = leftDecode $ front B.empty leftDecode bs = leftover bsOut >> decode codec where bsOut = B.append (B.drop toDrop x) y (x, y) = B.splitAt 4 bs (toDrop, codec) = case B.unpack x of [0x00, 0x00, 0xFE, 0xFF] -> (4, utf32_be) [0xFF, 0xFE, 0x00, 0x00] -> (4, utf32_le) 0xFE : 0xFF: _ -> (2, utf16_be) 0xFF : 0xFE: _ -> (2, utf16_le) 0xEF : 0xBB: 0xBF : _ -> (3, utf8) _ -> (0, utf8) -- Assuming UTF-8 {-# INLINE detectUtf #-} conduit-extra-1.3.5/Data/Conduit/Zlib.hs0000644000000000000000000002137013626670615016225 0ustar0000000000000000{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} -- | Streaming compression and decompression using conduits. -- -- Parts of this code were taken from zlib-enum and adapted for conduits. module Data.Conduit.Zlib ( -- * Conduits compress, decompress, gzip, ungzip, -- * Flushing compressFlush, decompressFlush, -- * Decompression combinators multiple, -- * Re-exported from zlib-bindings WindowBits (..), defaultWindowBits ) where import Data.Streaming.Zlib import Data.Conduit import Data.ByteString (ByteString) import qualified Data.ByteString as S import Control.Monad (unless, liftM) import Control.Monad.Trans.Class (lift, MonadTrans) import Control.Monad.Primitive (PrimMonad, unsafePrimToPrim) import Control.Monad.Trans.Resource (MonadThrow, throwM) import Data.Function (fix) -- | Gzip compression with default parameters. gzip :: (MonadThrow m, PrimMonad m) => ConduitT ByteString ByteString m () gzip = compress (-1) (WindowBits 31) -- | Gzip decompression with default parameters. ungzip :: (PrimMonad m, MonadThrow m) => ConduitT ByteString ByteString m () ungzip = decompress (WindowBits 31) unsafeLiftIO :: (PrimMonad m, MonadThrow m) => IO a -> m a unsafeLiftIO = unsafePrimToPrim -- | -- Decompress (inflate) a stream of 'ByteString's. For example: -- -- > sourceFile "test.z" $= decompress defaultWindowBits $$ sinkFile "test" decompress :: (PrimMonad m, MonadThrow m) => WindowBits -- ^ Zlib parameter (see the zlib-bindings package as well as the zlib C library) -> ConduitT ByteString ByteString m () decompress = helperDecompress (liftM (fmap Chunk) await) yield' leftover where yield' Flush = return () yield' (Chunk bs) = yield bs -- | Same as 'decompress', but allows you to explicitly flush the stream. decompressFlush :: (PrimMonad m, MonadThrow m) => WindowBits -- ^ Zlib parameter (see the zlib-bindings package as well as the zlib C library) -> ConduitT (Flush ByteString) (Flush ByteString) m () decompressFlush = helperDecompress await yield (leftover . Chunk) helperDecompress :: (Monad (t m), PrimMonad m, MonadThrow m, MonadTrans t) => t m (Maybe (Flush ByteString)) -> (Flush ByteString -> t m ()) -> (ByteString -> t m ()) -> WindowBits -> t m () helperDecompress await' yield' leftover' config = do -- Initialize the stateful inflater, which will be used below -- This inflater is never exposed outside of this function inf <- lift $ unsafeLiftIO $ initInflate config -- Some helper functions used by the main feeder loop below let -- Flush any remaining inflated bytes downstream flush = do chunk <- lift $ unsafeLiftIO $ flushInflate inf unless (S.null chunk) $ yield' $ Chunk chunk -- Get any input which is unused by the inflater getUnused = lift $ unsafeLiftIO $ getUnusedInflate inf -- If there is any unused data, return it as leftovers to the stream unused = do rem' <- getUnused unless (S.null rem') $ leftover' rem' -- Main loop: feed data from upstream into the inflater fix $ \feeder -> do mnext <- await' case mnext of -- No more data is available from upstream Nothing -> do -- Flush any remaining uncompressed data flush -- Return the rest of the unconsumed data as leftovers unused -- Another chunk of compressed data arrived Just (Chunk x) -> do -- Feed the compressed data into the inflater, returning a -- "popper" which will return chunks of decompressed data popper <- lift $ unsafeLiftIO $ feedInflate inf x -- Loop over the popper grabbing decompressed chunks and -- yielding them downstream fix $ \pop -> do mbs <- lift $ unsafeLiftIO popper case mbs of -- No more data from this popper PRDone -> do rem' <- getUnused if S.null rem' -- No data was unused by the inflater, so let's -- fill it up again and get more data out of it then feeder -- In this case, there is some unconsumed data, -- meaning the compressed stream is complete. -- At this point, we need to stop feeding, -- return the unconsumed data as leftovers, and -- flush any remaining content (which should be -- nothing) else do flush leftover' rem' -- Another chunk available, yield it downstream and -- loop again PRNext bs -> do yield' (Chunk bs) pop -- An error occurred inside zlib, throw it PRError e -> lift $ throwM e -- We've been asked to flush the stream Just Flush -> do -- Get any uncompressed data waiting for us flush -- Put a Flush in the stream yield' Flush -- Feed in more data feeder -- | -- Compress (deflate) a stream of 'ByteString's. The 'WindowBits' also control -- the format (zlib vs. gzip). compress :: (PrimMonad m, MonadThrow m) => Int -- ^ Compression level -> WindowBits -- ^ Zlib parameter (see the zlib-bindings package as well as the zlib C library) -> ConduitT ByteString ByteString m () compress = helperCompress (liftM (fmap Chunk) await) yield' where yield' Flush = return () yield' (Chunk bs) = yield bs -- | Same as 'compress', but allows you to explicitly flush the stream. compressFlush :: (PrimMonad m, MonadThrow m) => Int -- ^ Compression level -> WindowBits -- ^ Zlib parameter (see the zlib-bindings package as well as the zlib C library) -> ConduitT (Flush ByteString) (Flush ByteString) m () compressFlush = helperCompress await yield helperCompress :: (Monad (t m), PrimMonad m, MonadThrow m, MonadTrans t) => t m (Maybe (Flush ByteString)) -> (Flush ByteString -> t m ()) -> Int -> WindowBits -> t m () helperCompress await' yield' level config = await' >>= maybe (return ()) start where start input = do def <- lift $ unsafeLiftIO $ initDeflate level config push def input continue def = await' >>= maybe (close def) (push def) goPopper popper = do mbs <- lift $ unsafeLiftIO popper case mbs of PRDone -> return () PRNext bs -> yield' (Chunk bs) >> goPopper popper PRError e -> lift $ throwM e push def (Chunk x) = do popper <- lift $ unsafeLiftIO $ feedDeflate def x goPopper popper continue def push def Flush = do mchunk <- lift $ unsafeLiftIO $ flushDeflate def case mchunk of PRDone -> return () PRNext x -> yield' $ Chunk x PRError e -> lift $ throwM e yield' Flush continue def close def = do mchunk <- lift $ unsafeLiftIO $ finishDeflate def case mchunk of PRDone -> return () PRNext chunk -> yield' (Chunk chunk) >> close def PRError e -> lift $ throwM e -- | The standard 'decompress' and 'ungzip' functions will only decompress a -- single compressed entity from the stream. This combinator will exhaust the -- stream completely of all individual compressed entities. This is useful for -- cases where you have a concatenated archive, e.g. @cat file1.gz file2.gz > -- combined.gz@. -- -- Usage: -- -- > sourceFile "combined.gz" $$ multiple ungzip =$ consume -- -- This combinator will not fail on an empty stream. If you want to ensure that -- at least one compressed entity in the stream exists, consider a usage such -- as: -- -- > sourceFile "combined.gz" $$ (ungzip >> multiple ungzip) =$ consume -- -- @since 1.1.10 multiple :: Monad m => ConduitT ByteString a m () -> ConduitT ByteString a m () multiple inner = loop where loop = do mbs <- await case mbs of Nothing -> return () Just bs | S.null bs -> loop | otherwise -> do leftover bs inner loop conduit-extra-1.3.5/Data/Conduit/Network/Unix.hs0000644000000000000000000000164513626670615017704 0ustar0000000000000000{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} module Data.Conduit.Network.Unix ( -- * Basic utilities sourceSocket , sinkSocket -- * Simple server/client interface , SN.AppDataUnix , appSource , appSink -- ** Server , SN.ServerSettingsUnix , serverSettings , SN.runUnixServer -- ** Client , SN.ClientSettingsUnix , clientSettings , SN.runUnixClient -- ** Getters , SN.getPath , SN.getAfterBind -- ** Setters , SN.setPath , SN.setAfterBind ) where import Data.Conduit.Network (appSource, appSink, sourceSocket, sinkSocket) import qualified Data.Streaming.Network as SN clientSettings :: FilePath -> SN.ClientSettingsUnix clientSettings = SN.clientSettingsUnix serverSettings :: FilePath -> SN.ServerSettingsUnix serverSettings = SN.serverSettingsUnix conduit-extra-1.3.5/test/Spec.hs0000644000000000000000000000005413626670615014714 0ustar0000000000000000{-# OPTIONS_GHC -F -pgmF hspec-discover #-} conduit-extra-1.3.5/test/Data/Conduit/AttoparsecSpec.hs0000644000000000000000000002001613626670615021220 0ustar0000000000000000{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections #-} {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} module Data.Conduit.AttoparsecSpec (spec) where import Control.Exception (fromException) import Test.Hspec import Control.Applicative ((<*), (<|>)) import Control.Monad import qualified Data.Attoparsec.ByteString.Char8 import qualified Data.Attoparsec.Text import Data.Conduit import Data.Conduit.Attoparsec import qualified Data.Conduit.List as CL spec :: Spec spec = describe "Data.Conduit.AttoparsecSpec" $ do describe "error position" $ do it "works for text" $ do let input = ["aaa\na", "aaa\n\n", "aaa", "aab\n\naaaa"] badLine = 4 badCol = 6 badOff = 15 parser = Data.Attoparsec.Text.endOfInput <|> (Data.Attoparsec.Text.notChar 'b' >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff it "works for bytestring" $ do let input = ["aaa\na", "aaa\n\n", "aaa", "aab\n\naaaa"] badLine = 4 badCol = 6 badOff = 15 parser = Data.Attoparsec.ByteString.Char8.endOfInput <|> (Data.Attoparsec.ByteString.Char8.notChar 'b' >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff it "works in last chunk" $ do let input = ["aaa\na", "aaa\n\n", "aaa", "aab\n\naaaa"] badLine = 6 badCol = 5 badOff = 22 parser = Data.Attoparsec.Text.char 'c' <|> (Data.Attoparsec.Text.anyChar >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff it "works in last chunk" $ do let input = ["aaa\na", "aaa\n\n", "aaa", "aa\n\naaaab"] badLine = 6 badCol = 6 badOff = 22 parser = Data.Attoparsec.Text.string "bc" <|> (Data.Attoparsec.Text.anyChar >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff it "works after new line in text" $ do let input = ["aaa\n", "aaa\n\n", "aaa", "aa\nb\naaaa"] badLine = 5 badCol = 1 badOff = 15 parser = Data.Attoparsec.Text.endOfInput <|> (Data.Attoparsec.Text.notChar 'b' >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff it "works after new line in bytestring" $ do let input = ["aaa\n", "aaa\n\n", "aaa", "aa\nb\naaaa"] badLine = 5 badCol = 1 badOff = 15 parser = Data.Attoparsec.ByteString.Char8.endOfInput <|> (Data.Attoparsec.ByteString.Char8.notChar 'b' >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff it "works for first line" $ do let input = ["aab\na", "aaa\n\n", "aaa", "aab\n\naaaa"] badLine = 1 badCol = 3 badOff = 2 parser = Data.Attoparsec.Text.endOfInput <|> (Data.Attoparsec.Text.notChar 'b' >> parser) sink = sinkParser parser sink' = sinkParserEither parser ea = runConduit $ CL.sourceList input .| sink case ea of Left e -> case fromException e of Just pe -> do errorPosition pe `shouldBe` Position badLine badCol badOff ea' <- runConduit $ CL.sourceList input .| sink' case ea' of Left pe -> errorPosition pe `shouldBe` Position badLine badCol badOff describe "conduitParser" $ do it "parses a repeated stream" $ do let input = ["aaa\n", "aaa\naaa\n", "aaa\n"] parser = Data.Attoparsec.Text.string "aaa" <* Data.Attoparsec.Text.endOfLine sink = conduitParserEither parser .| CL.consume (Right !ea) = runConduit $ CL.sourceList input .| sink let chk a = case a of Left{} -> False Right (_, xs) -> xs == "aaa" chkp l = PositionRange (Position l 1 ((l - 1) * 4)) (Position (l+1) 1 (l * 4)) forM_ ea $ \ a -> a `shouldSatisfy` chk :: Expectation forM_ (zip ea [1..]) $ \ (Right (pos, _), l) -> pos `shouldBe` chkp l length ea `shouldBe` 4 it "positions on first line" $ do results <- runConduit $ yield "hihihi\nhihi" .| conduitParser (Data.Attoparsec.Text.string "\n" <|> Data.Attoparsec.Text.string "hi") .| CL.consume let f (a, b, c, d, e, f', g) = (PositionRange (Position a b c) (Position d e f'), g) results `shouldBe` map f [ (1, 1, 0, 1, 3, 2, "hi") , (1, 3, 2, 1, 5, 4, "hi") , (1, 5, 4, 1, 7, 6, "hi") , (1, 7, 6, 2, 1, 7, "\n") , (2, 1, 7, 2, 3, 9, "hi") , (2, 3, 9, 2, 5, 11, "hi") ] conduit-extra-1.3.5/test/Data/Conduit/BinarySpec.hs0000644000000000000000000003172413626670615020347 0ustar0000000000000000{-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE OverloadedStrings #-} module Data.Conduit.BinarySpec (spec) where import Data.Conduit (runConduit, runConduitRes, (.|), runConduitPure, ConduitT, Void) import qualified Data.Conduit.Binary as CB import qualified Data.Conduit as C import qualified Data.Conduit.List as CL import Control.Monad.Trans.Resource import Control.Monad.IO.Class import Control.Exception (IOException) import qualified Data.ByteString.Lazy as L import Test.Hspec import Test.Hspec.QuickCheck import qualified Data.IORef as I import Control.Monad.Trans.Writer.Strict import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 import Data.Functor.Identity import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) import Test.QuickCheck.Gen (Gen, oneof) import Data.Word (Word8) import Foreign.Storable (Storable, sizeOf, pokeByteOff, alignment) import Data.Typeable (Typeable) import Data.ByteString.Internal (createAndTrim') import Foreign.Ptr (alignPtr, minusPtr) import System.Directory (doesFileExist) import System.IO.Unsafe (unsafePerformIO) import Control.Applicative ((<$>)) import qualified Data.ByteString.Builder as BB spec :: Spec spec = describe "Data.Conduit.Binary" $ do describe "file access" $ do it "read" $ do bs <- S.readFile "conduit-extra.cabal" bss <- runConduitRes $ CB.sourceFile "conduit-extra.cabal" .| CL.consume S.concat bss `shouldBe` bs it "read range" $ do S.writeFile "tmp" "0123456789" bss <- runConduitRes $ CB.sourceFileRange "tmp" (Just 2) (Just 3) .| CL.consume S.concat bss `shouldBe` "234" it "write" $ do runConduitRes $ CB.sourceFile "conduit-extra.cabal" .| CB.sinkFile "tmp" bs1 <- S.readFile "conduit-extra.cabal" bs2 <- S.readFile "tmp" bs2 `shouldBe` bs1 it "write builder (withSinkFileBuilder)" $ do CB.withSinkFileBuilder "tmp" $ \sink -> CB.withSourceFile "conduit-extra.cabal" $ \src -> runConduit $ src .| CL.map BB.byteString .| sink bs1 <- S.readFile "conduit-extra.cabal" bs2 <- S.readFile "tmp" bs2 `shouldBe` bs1 it "conduit" $ do runConduitRes $ CB.sourceFile "conduit-extra.cabal" .| CB.conduitFile "tmp" .| CB.sinkFile "tmp2" bs1 <- S.readFile "conduit-extra.cabal" bs2 <- S.readFile "tmp" bs3 <- S.readFile "tmp2" bs2 `shouldBe` bs1 bs3 `shouldBe` bs1 describe "binary isolate" $ do it "works" $ do bss <- runConduitRes $ CL.sourceList (replicate 1000 "X") .| CB.isolate 6 .| CL.consume S.concat bss `shouldBe` "XXXXXX" describe "properly using binary file reading" $ do it "sourceFile" $ do x <- runConduitRes $ CB.sourceFile "test/random" .| CL.consume lbs <- L.readFile "test/random" L.fromChunks x `shouldBe` lbs describe "binary head" $ do let go lbs = do x <- CB.head case (x, L.uncons lbs) of (Nothing, Nothing) -> return True (Just y, Just (z, lbs')) | y == z -> go lbs' _ -> return False prop "works" $ \bss' -> let bss = map S.pack bss' in runConduitPure $ CL.sourceList bss .| go (L.fromChunks bss) describe "binary takeWhile" $ do prop "works" $ \bss' -> let bss = map S.pack bss' in runIdentity $ do bss2 <- runConduit $ CL.sourceList bss .| CB.takeWhile (>= 5) .| CL.consume return $ L.fromChunks bss2 == L.takeWhile (>= 5) (L.fromChunks bss) prop "leftovers present" $ \bss' -> let bss = map S.pack bss' in runIdentity $ do result <- runConduit $ CL.sourceList bss .| do x <- CB.takeWhile (>= 5) .| CL.consume y <- CL.consume return (S.concat x, S.concat y) let expected = S.span (>= 5) $ S.concat bss if result == expected then return True else error $ show (S.concat bss, result, expected) describe "binary dropWhile" $ do prop "works" $ \bss' -> let bss = map S.pack bss' in runIdentity $ do bss2 <- runConduit $ CL.sourceList bss .| do CB.dropWhile (< 5) CL.consume return $ L.fromChunks bss2 == L.dropWhile (< 5) (L.fromChunks bss) describe "binary take" $ do let go n l = runConduit $ CL.sourceList l .| do a <- CB.take n b <- CL.consume return (a, b) -- Taking nothing should result in an empty Bytestring it "nothing" $ do (a, b) <- runResourceT $ go 0 ["abc", "defg"] a `shouldBe` L.empty L.fromChunks b `shouldBe` "abcdefg" it "normal" $ do (a, b) <- runResourceT $ go 4 ["abc", "defg"] a `shouldBe` "abcd" L.fromChunks b `shouldBe` "efg" -- Taking exactly the data that is available should result in no -- leftover. it "all" $ do (a, b) <- runResourceT $ go 7 ["abc", "defg"] a `shouldBe` "abcdefg" b `shouldBe` [] -- Take as much as possible. it "more" $ do (a, b) <- runResourceT $ go 10 ["abc", "defg"] a `shouldBe` "abcdefg" b `shouldBe` [] describe "binary" $ do prop "lines" $ \bss' -> runIdentity $ do let bss = map S.pack bss' bs = S.concat bss src = CL.sourceList bss res <- runConduit $ src .| CB.lines .| CL.consume return $ S8.lines bs == res describe "sinkCacheLength" $ do it' "works" $ runResourceT $ do lbs <- liftIO $ L.readFile "test/Data/Conduit/BinarySpec.hs" (len, src) <- runConduit $ CB.sourceLbs lbs .| CB.sinkCacheLength lbs' <- runConduit $ src .| CB.sinkLbs liftIO $ do fromIntegral len `shouldBe` L.length lbs lbs' `shouldBe` lbs fromIntegral len `shouldBe` L.length lbs' describe "sinkFileCautious" $ do it' "success" $ do runConduitRes $ CB.sourceFile "conduit-extra.cabal" .| CB.sinkFileCautious "tmp" bs1 <- S.readFile "conduit-extra.cabal" bs2 <- S.readFile "tmp" bs2 `shouldBe` bs1 it' "failure" $ do let bs1 = "This is the original content" S.writeFile "tmp" bs1 runConduitRes ( (CB.sourceFile "conduit-extra.cabal" >> error "FIXME") .| CB.sinkFileCautious "tmp") `shouldThrow` anyException bs2 <- S.readFile "tmp" bs2 `shouldBe` bs1 it "sinkSystemTempFile" $ do let bs = "Hello World!" fp <- runResourceT $ do fp <- runConduit $ C.yield bs .| CB.sinkSystemTempFile "temp-file-test" liftIO $ do actual <- S.readFile fp actual `shouldBe` bs return fp exists <- doesFileExist fp exists `shouldBe` False describe "Data.Conduit.Binary.mapM_" $ do prop "telling works" $ \bytes -> let lbs = L.pack bytes src = CB.sourceLbs lbs sink = CB.mapM_ (tell . return . S.singleton) bss = execWriter $ runConduit $ src .| sink in L.fromChunks bss == lbs describe "exception handling" $ do it "catchC" $ do ref <- I.newIORef 0 let src = do C.catchC (CB.sourceFile "some-file-that-does-not-exist") onErr C.handleC onErr $ CB.sourceFile "conduit-extra.cabal" onErr :: MonadIO m => IOException -> m () onErr _ = liftIO $ I.modifyIORef ref (+ 1) contents <- L.readFile "conduit-extra.cabal" res <- runConduitRes $ src .| CB.sinkLbs res `shouldBe` contents errCount <- I.readIORef ref errCount `shouldBe` (1 :: Int) it "tryC" $ do ref <- I.newIORef undefined let src = do res1 <- C.tryC $ CB.sourceFile "some-file-that-does-not-exist" res2 <- C.tryC $ CB.sourceFile "conduit-extra.cabal" liftIO $ I.writeIORef ref (res1, res2) contents <- L.readFile "conduit-extra.cabal" res <- runConduitRes $ src .| CB.sinkLbs res `shouldBe` contents exc <- I.readIORef ref case exc :: (Either IOException (), Either IOException ()) of (Left _, Right ()) -> return () _ -> error $ show exc describe "normalFuseLeft" $ do it "does not double close conduit" $ do x <- runConduitRes $ let src = CL.sourceList ["foobarbazbin"] in src .| CB.isolate 10 .| CL.head x `shouldBe` Just "foobarbazb" describe "Storable" $ do let test name func = describe name $ do let test' size = prop ("chunk size " ++ show size) $ \stores0 -> do let src = loop (someStorables stores0) where loop bs | S.null bs = return () | otherwise = do let (x, y) = S.splitAt size bs C.yield x loop y sink :: [SomeStorable] -> ConduitT S.ByteString Void IO () sink [] = do mw <- CB.head case mw of Nothing -> return () Just _ -> error "trailing bytes" sink (next:rest) = do withSomeStorable next checkOne sink rest checkOne :: (Storable a, Eq a, Show a) => a -> ConduitT S.ByteString Void IO () checkOne expected = do mactual <- if func then CB.sinkStorable else fmap Just CB.sinkStorableEx actual <- case mactual of Nothing -> error "got Nothing" Just actual -> return actual liftIO $ actual `shouldBe` expected runConduit $ src .| sink stores0 :: IO () mapM_ test' [1, 5, 10, 100] test "sink Maybe" True test "sink exception" False it' "insufficient bytes are leftovers, one chunk" $ do let src = C.yield $ S.singleton 1 runConduit $ src .| do mactual <- CB.sinkStorable liftIO $ mactual `shouldBe` (Nothing :: Maybe Int) lbs <- CB.sinkLbs liftIO $ lbs `shouldBe` L.singleton 1 it' "insufficient bytes are leftovers, multiple chunks" $ do let src = do C.yield $ S.singleton 1 C.yield $ S.singleton 2 runConduit $ src .| do mactual <- CB.sinkStorable liftIO $ mactual `shouldBe` (Nothing :: Maybe Int) lbs <- CB.sinkLbs liftIO $ lbs `shouldBe` L.pack [1, 2] data SomeStorable where SomeStorable :: (Storable a, Eq a, Show a, Typeable a) => a -> SomeStorable instance Show SomeStorable where show (SomeStorable x) = show x instance Arbitrary SomeStorable where arbitrary = oneof [ SomeStorable <$> (arbitrary :: Gen Int) , SomeStorable <$> (arbitrary :: Gen Word8) , SomeStorable <$> (arbitrary :: Gen Double) ] withSomeStorable :: SomeStorable -> (forall a. (Storable a, Eq a, Show a) => a -> b) -> b withSomeStorable (SomeStorable x) f = f x someStorable :: SomeStorable -> S.ByteString someStorable store = fst $ unsafePerformIO $ createAndTrim' (size + align) start where size = withSomeStorable store sizeOf align = withSomeStorable store alignment start ptr = do let off = minusPtr ptr (alignPtr ptr align) withSomeStorable store (pokeByteOff ptr off) return (off, size, ()) someStorables :: [SomeStorable] -> S.ByteString someStorables = S.concat . map someStorable it' :: String -> IO () -> Spec it' = it conduit-extra-1.3.5/test/Data/Conduit/ByteString/BuilderSpec.hs0000644000000000000000000000557613626670615022611 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} module Data.Conduit.ByteString.BuilderSpec (spec) where import Test.Hspec import Test.Hspec.QuickCheck (prop) import Data.Conduit ((.|), runConduit, Flush (..)) import qualified Data.Conduit.List as CL import Data.Conduit.ByteString.Builder (builderToByteString, builderToByteStringFlush) import Control.Monad.ST (runST) import qualified Data.ByteString as S import Data.ByteString.Builder (byteString, toLazyByteString) import Data.ByteString.Builder.Internal (lazyByteStringInsert, flush) import qualified Data.ByteString.Lazy as L spec :: Spec spec = describe "Data.Conduit.ByteString.Builder" $ do prop "idempotent to toLazyByteString" $ \bss' -> runST $ do let bss = map S.pack bss' let builders = map byteString bss let lbs = toLazyByteString $ mconcat builders let src = mconcat $ map (CL.sourceList . return) builders outBss <- runConduit $ src .| builderToByteString .| CL.consume return $ lbs == L.fromChunks outBss it "works for large input" $ do let builders = replicate 10000 (byteString "hello world!") let lbs = toLazyByteString $ mconcat builders let src = mconcat $ map (CL.sourceList . return) builders outBss <- runConduit $ src .| builderToByteString .| CL.consume lbs `shouldBe` L.fromChunks outBss it "works for lazy bytestring insertion" $ do let builders = replicate 10000 (lazyByteStringInsert "hello world!") let lbs = toLazyByteString $ mconcat builders let src = mconcat $ map (CL.sourceList . return) builders outBss <- runConduit $ src .| builderToByteString .| CL.consume lbs `shouldBe` L.fromChunks outBss it "flush shouldn't bring in empty strings." $ do let dat = ["hello", "world"] src = CL.sourceList dat .| CL.map ((`mappend` flush) . byteString) out <- runConduit $ src .| builderToByteString .| CL.consume dat `shouldBe` out prop "flushing" $ \bss' -> runST $ do let bss = concatMap (\bs -> [Chunk $ S.pack bs, Flush]) $ filter (not . null) bss' let chunks = map (fmap byteString) bss let src = CL.sourceList chunks outBss <- runConduit $ src .| builderToByteStringFlush .| CL.consume if bss == outBss then return () else error (show (bss, outBss)) return $ bss == outBss it "large flush input" $ do let lbs = L.pack $ concat $ replicate 100000 [0..255] let chunks = map (Chunk . byteString) (L.toChunks lbs) let src = CL.sourceList chunks bss <- runConduit $ src .| builderToByteStringFlush .| CL.consume let unFlush (Chunk x) = [x] unFlush Flush = [] L.fromChunks (concatMap unFlush bss) `shouldBe` lbs conduit-extra-1.3.5/test/Data/Conduit/ExtraSpec.hs0000644000000000000000000000431713626670615020204 0ustar0000000000000000module Data.Conduit.ExtraSpec where import Data.Conduit import Test.Hspec import Test.Hspec.QuickCheck import Data.Conduit.List (isolate, peek, consume) import qualified Data.Conduit.List as CL import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.ByteString as S import qualified Data.Conduit.Text as CT spec :: Spec spec = describe "Data.Conduit.Extra" $ do it "basic test" $ do let sink2 :: ConduitT a o IO (Maybe a, Maybe a) sink2 = do ma1 <- fuseLeftovers id (isolate 10) peek ma2 <- peek return (ma1, ma2) source = yield 1 >> yield 2 res <- runConduit $ source .| sink2 res `shouldBe` (Just 1, Just (1 :: Int)) it "get leftovers" $ do let sink2 :: ConduitT a o IO ([a], [a], [a]) sink2 = do (x, y) <- fuseReturnLeftovers (isolate 2) peek3 z <- CL.consume return (x, y, z) peek3 = do x <- CL.take 3 mapM_ leftover $ reverse x return x source = mapM_ yield [1..5 :: Int] res <- runConduit $ source .| sink2 res `shouldBe` ([1..2], [1..2], [3..5]) it "multiple values" $ do let sink2 :: ConduitT a o IO ([a], Maybe a) sink2 = do ma1 <- fuseLeftovers id (isolate 10) peek3 ma2 <- peek return (ma1, ma2) peek3 = do x <- CL.take 3 mapM_ leftover $ reverse x return x source = mapM_ yield [1..5] res <- runConduit $ source .| sink2 res `shouldBe` ([1..3], Just (1 :: Int)) prop "more complex" $ \ss cnt -> do let ts = map T.pack ss src = mapM_ (yield . T.encodeUtf8) ts conduit = CL.map T.decodeUtf8 sink = CT.take cnt .| consume undo = return . T.encodeUtf8 . T.concat res <- runConduit $ src .| do x <- fuseLeftovers undo conduit sink y <- consume return (T.concat x, T.decodeUtf8 $ S.concat y) res `shouldBe` T.splitAt cnt (T.concat ts) main :: IO () main = hspec spec conduit-extra-1.3.5/test/Data/Conduit/FilesystemSpec.hs0000644000000000000000000000262113626670615021241 0ustar0000000000000000module Data.Conduit.FilesystemSpec (spec) where import Test.Hspec import Data.Conduit import qualified Data.Conduit.List as CL import Data.Conduit.Filesystem import Data.List (sort, isSuffixOf) import System.FilePath (()) spec :: Spec spec = describe "Data.Conduit.Filesystem" $ do it "sourceDirectory" $ do res <- runConduitRes $ sourceDirectory ("test" "filesystem") .| CL.filter (not . (".swp" `isSuffixOf`)) .| CL.consume sort res `shouldBe` [ "test" "filesystem" "bar.txt" , "test" "filesystem" "baz.txt" , "test" "filesystem" "bin" , "test" "filesystem" "foo.txt" ] it "sourceDirectoryDeep" $ do res1 <- runConduitRes $ sourceDirectoryDeep False ("test" "filesystem") .| CL.filter (not . (".swp" `isSuffixOf`)) .| CL.consume res2 <- runConduitRes $ sourceDirectoryDeep True ("test" "filesystem") .| CL.filter (not . (".swp" `isSuffixOf`)) .| CL.consume sort res1 `shouldBe` [ "test" "filesystem" "bar.txt" , "test" "filesystem" "baz.txt" , "test" "filesystem" "bin" "bin.txt" , "test" "filesystem" "foo.txt" ] sort res1 `shouldBe` sort res2 conduit-extra-1.3.5/test/Data/Conduit/LazySpec.hs0000644000000000000000000000317213626670615020036 0ustar0000000000000000module Data.Conduit.LazySpec (spec) where import qualified Data.Conduit.Lazy as CLazy import Test.Hspec import Control.Monad.IO.Class import qualified Data.Conduit as C import qualified Data.Conduit.Binary as CB import Control.Monad.Trans.Resource import qualified Data.IORef as I import Control.Monad (forever) spec :: Spec spec = describe "Data.Conduit.Lazy" $ do describe "lazy" $ do it' "works inside a ResourceT" $ runResourceT $ do counter <- liftIO $ I.newIORef 0 let incr i = do istate <- liftIO $ I.newIORef $ Just (i :: Int) let loop = do res <- liftIO $ I.atomicModifyIORef istate ((,) Nothing) case res of Nothing -> return () Just x -> do count <- liftIO $ I.atomicModifyIORef counter (\j -> (j + 1, j + 1)) liftIO $ count `shouldBe` i C.yield x loop loop nums <- CLazy.lazyConsume $ mconcat $ map incr [1..10] liftIO $ nums `shouldBe` [1..10] it' "returns nothing outside ResourceT" $ do bss <- runResourceT $ CLazy.lazyConsume $ CB.sourceFile "test/main.hs" bss `shouldBe` [] it' "works with pure sources" $ do nums <- CLazy.lazyConsume $ forever $ C.yield 1 take 100 nums `shouldBe` replicate 100 (1 :: Int) it' :: String -> IO () -> Spec it' = it conduit-extra-1.3.5/test/Data/Conduit/NetworkSpec.hs0000644000000000000000000000342513626670615020551 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} module Data.Conduit.NetworkSpec (spec) where import Data.Conduit import Data.Conduit.Network import Control.Concurrent (forkIO, threadDelay, putMVar, newEmptyMVar, takeMVar, killThread) import Control.Monad (replicateM_) import Test.Hspec spec :: Spec spec = describe "Data.Conduit.Network" $ do describe "run general server" $ do it "running tcp server" $ do _ <- forkIO $ runTCPServer (serverSettings 4009 "*4") echo threadDelay 1000000 replicateM_ 100 $ runTCPClient (clientSettings 4009 "127.0.0.1") doNothing describe "fork server" $ do it "can connect to server" $ do let set = serverSettings 4010 "*4" threadId <- forkTCPServer set echo replicateM_ 100 $ runTCPClient (clientSettings 4010 "127.0.0.1") doNothing killThread threadId it "fork server also executes custom afterBind" $ do assertMVar <- newEmptyMVar let set = serverSettings 4010 "*4" setWithAfterBind = setAfterBind (\_ -> putMVar assertMVar ()) set threadId <- forkTCPServer setWithAfterBind echo takeMVar assertMVar killThread threadId it "fork server really waits for server to be finalized before returning" $ do let set = serverSettings 4010 "*4" setWithAfterBind = setAfterBind (\_ -> threadDelay 1000000) set threadId <- forkTCPServer setWithAfterBind echo replicateM_ 100 $ runTCPClient (clientSettings 4010 "127.0.0.1") doNothing killThread threadId echo :: AppData -> IO () echo ad = runConduit $ appSource ad .| appSink ad doNothing :: AppData -> IO () doNothing _ = return () conduit-extra-1.3.5/test/Data/Conduit/ProcessSpec.hs0000644000000000000000000000760113626670615020536 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Data.Conduit.ProcessSpec (spec, main) where import Test.Hspec import Test.Hspec.QuickCheck (prop) import Data.Conduit import qualified Data.Conduit.List as CL import Data.Conduit.Process import Control.Concurrent.Async (concurrently) import qualified Data.ByteString.Lazy as L import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 import System.Exit import Control.Concurrent (threadDelay) main :: IO () main = hspec spec spec :: Spec spec = describe "Data.Conduit.Process" $ do #ifndef WINDOWS prop "cat" $ \wss -> do let lbs = L.fromChunks $ map S.pack wss ((sink, closeStdin), source, Inherited, cph) <- streamingProcess (shell "cat") ((), bss) <- concurrently (do runConduit $ mapM_ yield (L.toChunks lbs) .| sink closeStdin) (runConduit $ source .| CL.consume) L.fromChunks bss `shouldBe` lbs ec <- waitForStreamingProcess cph ec `shouldBe` ExitSuccess it "closed stream" $ do (ClosedStream, source, Inherited, cph) <- streamingProcess (shell "cat") bss <- runConduit $ source .| CL.consume bss `shouldBe` [] ec <- waitForStreamingProcess cph ec `shouldBe` ExitSuccess it "handles sub-process exit code" $ do (sourceCmdWithConsumer "exit 0" CL.sinkNull) `shouldReturn` (ExitSuccess, ()) (sourceCmdWithConsumer "exit 11" CL.sinkNull) `shouldReturn` (ExitFailure 11, ()) (sourceCmdWithConsumer "exit 12" CL.sinkNull) `shouldReturn` (ExitFailure 12, ()) (sourceCmdWithStreams "exit 0" CL.sourceNull CL.sinkNull CL.sinkNull) `shouldReturn` (ExitSuccess, (), ()) (sourceCmdWithStreams "exit 11" CL.sourceNull CL.sinkNull CL.sinkNull) `shouldReturn` (ExitFailure 11, (), ()) (sourceCmdWithStreams "exit 12" CL.sourceNull CL.sinkNull CL.sinkNull) `shouldReturn` (ExitFailure 12, (), ()) it "consumes stdout" $ do let mystr = "this is a test string" :: String sourceCmdWithStreams ("bash -c \"echo -n " ++ mystr ++ "\"") CL.sourceNull CL.consume -- stdout CL.consume -- stderr `shouldReturn` (ExitSuccess, [S8.pack mystr], []) it "consumes stderr" $ do let mystr = "this is a test string" :: String sourceCmdWithStreams ("bash -c \">&2 echo -n " ++ mystr ++ "\"") CL.sourceNull CL.consume -- stdout CL.consume -- stderr `shouldReturn` (ExitSuccess, [], [S8.pack mystr]) it "feeds stdin" $ do let mystr = "this is a test string" :: S.ByteString sourceCmdWithStreams "cat" (yield mystr) CL.consume -- stdout CL.consume -- stderr `shouldReturn` (ExitSuccess, [mystr], []) #endif it "blocking vs non-blocking" $ do (ClosedStream, ClosedStream, ClosedStream, cph) <- streamingProcess (shell "sleep 1") mec1 <- getStreamingProcessExitCode cph mec1 `shouldBe` Nothing threadDelay 1500000 -- For slow systems where sleep may take longer than 1.5 seconds, do -- this in a loop. let loop 0 = error "Took too long for sleep to exit, your system is acting funny" loop i = do mec2 <- getStreamingProcessExitCode cph case mec2 of Nothing -> do threadDelay 500000 loop (pred i) Just _ -> mec2 `shouldBe` Just ExitSuccess loop (5 :: Int) ec <- waitForStreamingProcess cph ec `shouldBe` ExitSuccess conduit-extra-1.3.5/test/Data/Conduit/Process/TypedSpec.hs0000644000000000000000000000210613626670615021616 0ustar0000000000000000module Data.Conduit.Process.TypedSpec (spec) where import Test.Hspec import Data.Conduit import Data.Conduit.Process.Typed import qualified Data.Conduit.List as CL import qualified Data.ByteString as B spec :: Spec spec = do it "cat works" $ do let fp = "ChangeLog.md" pc = setStdout createSource $ proc "cat" [fp] bs <- B.readFile fp bss <- withProcess_ pc $ \p -> runConduit (getStdout p .| CL.consume) <* waitExitCode p B.concat bss `shouldBe` bs it "cat works with withLoggedProcess_" $ do let fp = "ChangeLog.md" pc = proc "cat" [fp] bs <- B.readFile fp bss <- withLoggedProcess_ pc $ \p -> runConduit (getStdout p .| CL.consume) <* waitExitCode p B.concat bss `shouldBe` bs it "failing process throws" $ do (withLoggedProcess_ (proc "cat" ["does not exist"]) $ \p -> do runConduit $ getStdout p .| CL.mapM_ (error "shouldn't have data")) `shouldThrow` anyException it "failing process throws" $ do (withProcess_ (proc "cat" ["does not exist"]) $ const $ return ()) `shouldThrow` anyException conduit-extra-1.3.5/test/Data/Conduit/TextSpec.hs0000644000000000000000000002564213626670615020051 0ustar0000000000000000{-# LANGUAGE FlexibleContexts, OverloadedStrings #-} module Data.Conduit.TextSpec (spec) where import Data.Conduit ((.|), runConduit, runConduitPure) import Control.Exception (SomeException) import qualified Data.Conduit.Text as CT import qualified Data.Conduit as C import Data.Conduit.Lift (runCatchC, catchCatchC) import Data.Functor.Identity (runIdentity) import qualified Data.Conduit.List as CL import Test.Hspec import Test.Hspec.QuickCheck import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Text.Encoding.Error as TEE import qualified Data.Text.Lazy.Encoding as TLE import Control.Arrow import qualified Data.ByteString as S import qualified Data.Text.Lazy as TL import qualified Data.ByteString.Lazy as L import Control.Monad.Catch.Pure (runCatchT) spec :: Spec spec = describe "Data.Conduit.Text" $ do describe "text" $ do let go enc tenc tdec cenc = describe enc $ do prop "single chunk" $ \chars -> do let tl = TL.pack chars lbs = tenc tl src = CL.sourceList $ L.toChunks lbs ts <- runConduit $ src .| CT.decode cenc .| CL.consume TL.fromChunks ts `shouldBe` tl prop "many chunks" $ \chars -> do let tl = TL.pack chars lbs = tenc tl src = mconcat $ map (CL.sourceList . return . S.singleton) $ L.unpack lbs ts <- runConduit $ src .| CT.decode cenc .| CL.consume TL.fromChunks ts `shouldBe` tl -- Check whether raw bytes are decoded correctly, in -- particular that Text decoding produces an error if -- and only if Conduit does. prop "raw bytes" $ \bytes -> do let lbs = L.pack bytes src = CL.sourceList $ L.toChunks lbs tl' = tdec lbs etl = runConduit $ src .| CT.decode cenc .| CL.consume case etl of (Left _) -> (return $! TL.toStrict tl') `shouldThrow` anyException (Right tl) -> TL.fromChunks tl `shouldBe` tl' prop "encoding" $ \chars -> do let tss = map T.pack chars lbs = tenc $ TL.fromChunks tss src = mconcat $ map (CL.sourceList . return) tss bss <- runConduit $ src .| CT.encode cenc .| CL.consume L.fromChunks bss `shouldBe` lbs prop "valid then invalid" $ \x y chars -> do let tss = map T.pack ([x, y]:chars) ts = T.concat tss lbs = tenc (TL.fromChunks tss) `L.append` "\0\0\0\0\0\0\0" src = mapM_ C.yield $ L.toChunks lbs Just x' <- runConduit $ src .| CT.decode cenc .| C.await (x' `T.isPrefixOf` ts) `shouldBe` True go "utf8" TLE.encodeUtf8 TLE.decodeUtf8 CT.utf8 go "utf16_le" TLE.encodeUtf16LE TLE.decodeUtf16LE CT.utf16_le go "utf16_be" TLE.encodeUtf16BE TLE.decodeUtf16BE CT.utf16_be go "utf32_le" TLE.encodeUtf32LE TLE.decodeUtf32LE CT.utf32_le go "utf32_be" TLE.encodeUtf32BE TLE.decodeUtf32BE CT.utf32_be it "mixed utf16 and utf8" $ do let bs = "8\NUL:\NULu\NUL\215\216\217\218" src = C.yield bs .| CT.decode CT.utf16_le text <- runConduit $ src .| C.await text `shouldBe` Just "8:u" (runConduit $ src .| CL.sinkNull) `shouldThrow` anyException it "invalid utf8" $ do let bs = S.pack [0..255] src = C.yield bs .| CT.decode CT.utf8 text <- runConduit $ src .| C.await text `shouldBe` Just (T.pack $ map toEnum [0..127]) (runConduit $ src .| CL.sinkNull) `shouldThrow` anyException it "catch UTF8 exceptions" $ do let badBS = "this is good\128\128\0that was bad" grabExceptions inner = C.catchC (inner .| CL.map Right) (\e -> C.yield (Left (e :: CT.TextException))) res <- runConduit $ C.yield badBS .| (,) <$> (grabExceptions (CT.decode CT.utf8) .| CL.consume) <*> CL.consume first (map (either (Left . show) Right)) res `shouldBe` ( [ Right "this is good" , Left $ show $ CT.NewDecodeException "UTF-8" 12 "\128\128\0t" ] , ["\128\128\0that was bad"] ) it "catch UTF8 exceptions, pure" $ do let badBS = "this is good\128\128\0that was bad" grabExceptions inner = do res <- runCatchC $ inner .| CL.map Right case res of Left e -> C.yield $ Left e Right () -> return () let res = runConduitPure $ C.yield badBS .| (,) <$> (grabExceptions (CT.decode CT.utf8) .| CL.consume) <*> CL.consume first (map (either (Left . show) Right)) res `shouldBe` ( [ Right "this is good" , Left $ show $ CT.NewDecodeException "UTF-8" 12 "\128\128\0t" ] , ["\128\128\0that was bad"] ) it "catch UTF8 exceptions, catchExceptionC" $ do let badBS = "this is good\128\128\0that was bad" grabExceptions inner = catchCatchC (inner .| CL.map Right) (\e -> C.yield $ Left e) let Right res = runIdentity $ runCatchT $ runConduit $ C.yield badBS .| (,) <$> (grabExceptions (CT.decode CT.utf8) .| CL.consume) <*> CL.consume first (map (either (Left . show) Right)) res `shouldBe` ( [ Right "this is good" , Left $ show $ CT.NewDecodeException "UTF-8" 12 "\128\128\0t" ] , ["\128\128\0that was bad"] ) it "catch UTF8 exceptions, catchExceptionC, decodeUtf8" $ do let badBS = ["this is good", "\128\128\0that was bad"] grabExceptions inner = catchCatchC (inner .| CL.map Right) (\e -> C.yield $ Left e) let Right res = runIdentity $ runCatchT $ runConduit $ mapM_ C.yield badBS .| (,) <$> (grabExceptions CT.decodeUtf8 .| CL.consume) <*> CL.consume first (map (either (Left . const ()) Right)) res `shouldBe` ( [ Right "this is good" , Left () ] , ["\128\128\0that was bad"] ) prop "lenient UTF8 decoding" $ \good1 good2 -> do let bss = [TE.encodeUtf8 $ T.pack good1, "\128\129\130", TE.encodeUtf8 $ T.pack good2] bs = S.concat bss expected = TE.decodeUtf8With TEE.lenientDecode bs actual = runConduitPure $ mapM_ C.yield bss .| CT.decodeUtf8Lenient .| CL.consume T.concat actual `shouldBe` expected describe "text lines" $ do it "yields nothing given nothing" $ (runConduit $ CL.sourceList [] .| CT.lines .| CL.consume) == [[]] it "yields nothing given only empty text" $ (runConduit $ CL.sourceList [""] .| CT.lines .| CL.consume) == [[]] it "works across split lines" $ (runConduit $ CL.sourceList ["abc", "d\nef"] .| CT.lines .| CL.consume) == [["abcd", "ef"]] it "works with multiple lines in an item" $ (runConduit $ CL.sourceList ["ab\ncd\ne"] .| CT.lines .| CL.consume) == [["ab", "cd", "e"]] it "works with ending on a newline" $ (runConduit $ CL.sourceList ["ab\n"] .| CT.lines .| CL.consume) == [["ab"]] it "works with ending a middle item on a newline" $ (runConduit $ CL.sourceList ["ab\n", "cd\ne"] .| CT.lines .| CL.consume) == [["ab", "cd", "e"]] it "works with empty text" $ (runConduit $ CL.sourceList ["ab", "", "cd"] .| CT.lines .| CL.consume) == [["abcd"]] it "works with empty lines" $ (runConduit $ CL.sourceList ["\n\n"] .| CT.lines .| CL.consume) == [["", ""]] describe "text lines bounded" $ do it "yields nothing given nothing" $ (runConduit $ CL.sourceList [] .| CT.linesBounded 80 .| CL.consume) == [[]] it "yields nothing given only empty text" $ (runConduit $ CL.sourceList [""] .| CT.linesBounded 80 .| CL.consume) == [[]] it "works across split lines" $ (runConduit $ CL.sourceList ["abc", "d\nef"] .| CT.linesBounded 80 .| CL.consume) == [["abcd", "ef"]] it "works with multiple lines in an item" $ (runConduit $ CL.sourceList ["ab\ncd\ne"] .| CT.linesBounded 80 .| CL.consume) == [["ab", "cd", "e"]] it "works with ending on a newline" $ (runConduit $ CL.sourceList ["ab\n"] .| CT.linesBounded 80 .| CL.consume) `shouldBe` [["ab"]] it "works with ending a middle item on a newline" $ (runConduit $ CL.sourceList ["ab\n", "cd\ne"] .| CT.linesBounded 80 .| CL.consume) `shouldBe` [["ab", "cd", "e"]] it "works with empty text" $ (runConduit $ CL.sourceList ["ab", "", "cd"] .| CT.linesBounded 80 .| CL.consume) `shouldBe` [["abcd"]] it "works with empty lines" $ (runConduit (CL.sourceList ["\n\n"] .| CT.linesBounded 80 .| CL.consume)) `shouldBe` [["", ""]] it "throws an exception when lines are too long" $ do let x :: Either SomeException [T.Text] x = runConduit $ CL.sourceList ["hello\nworld"] .| CT.linesBounded 4 .| CL.consume show x `shouldBe` show (Left $ CT.LengthExceeded 4 :: Either CT.TextException ()) it "works with infinite input" $ do let x :: Either SomeException [T.Text] x = runConduit $ CL.sourceList (cycle ["hello"]) .| CT.linesBounded 256 .| CL.consume show x `shouldBe` show (Left $ CT.LengthExceeded 256 :: Either CT.TextException ()) describe "text decode" $ do it' "doesn't throw runtime exceptions" $ do let x = runConduit $ C.yield "\x89\x243" .| CT.decode CT.utf8 .| CL.consume case x of Left _ -> return () Right t -> error $ "This should have failed: " ++ show t it "is not too eager" $ do x <- runConduit $ CL.sourceList ["foobarbaz", error "ignore me"] .| CT.decode CT.utf8 .| CL.head x `shouldBe` Just "foobarbaz" it' :: String -> IO () -> Spec it' = it conduit-extra-1.3.5/test/Data/Conduit/ZlibSpec.hs0000644000000000000000000000744113626670615020022 0ustar0000000000000000{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE OverloadedStrings #-} module Data.Conduit.ZlibSpec (spec) where import Test.Hspec import Test.Hspec.QuickCheck (prop) import Data.Conduit ((.|), runConduit) import qualified Data.Conduit as C import qualified Data.Conduit.List as CL import qualified Data.Conduit.Zlib as CZ import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Data.ByteString.Char8 () import Data.ByteString.Lazy.Char8 () import Control.Monad (replicateM_) spec :: Spec spec = describe "Data.Conduit.Zlib" $ do prop "idempotent" $ \bss' -> do let bss = map S.pack bss' lbs = L.fromChunks bss src = mconcat $ map (CL.sourceList . return) bss outBss <- runConduit $ src .| CZ.gzip .| CZ.ungzip .| CL.consume L.fromChunks outBss `shouldBe` lbs prop "flush" $ \bss' -> do let bss = map S.pack $ filter (not . null) bss' bssC = concatMap (\bs -> [C.Chunk bs, C.Flush]) bss src = mconcat $ map (CL.sourceList . return) bssC outBssC <- runConduit $ src .| CZ.compressFlush 5 (CZ.WindowBits 31) .| CZ.decompressFlush (CZ.WindowBits 31) .| CL.consume outBssC `shouldBe` bssC it "compressFlush large data" $ do let content = L.pack $ map (fromIntegral . fromEnum) $ concat $ ["BEGIN"] ++ map show [1..100000 :: Int] ++ ["END"] src = CL.sourceList $ map C.Chunk $ L.toChunks content bssC <- runConduit $ src .| CZ.compressFlush 5 (CZ.WindowBits 31) .| CL.consume let unChunk (C.Chunk x) = [x] unChunk C.Flush = [] bss <- runConduit $ CL.sourceList bssC .| CL.concatMap unChunk .| CZ.ungzip .| CL.consume L.fromChunks bss `shouldBe` content it "uncompressed after compressed" $ do let c = "This data is stored compressed." u = "This data isn't." let src1 = do C.yield c .| CZ.gzip C.yield u encoded <- runConduit $ src1 .| CL.consume let src2 = mapM_ C.yield encoded (c', u') <- runConduit $ src2 .| do c' <- CZ.ungzip .| CL.consume u' <- CL.consume return (S.concat c', S.concat u') c' `shouldBe` c u' `shouldBe` u it "multiple compressed values" $ do let s1 = "hello" s2 = "world" src = do C.yield s1 .| CZ.gzip C.yield s2 .| CZ.gzip actual <- runConduit $ src .| CZ.multiple CZ.ungzip .| CL.consume S.concat actual `shouldBe` S.concat [s1, s2] it "single compressed, multiple uncompressed chunks" $ do let s1 = "hello" s2 = "there" s3 = "world" s1Z <- fmap S.concat $ runConduit $ C.yield s1 .| CZ.gzip .| CL.consume let src = do C.yield $ S.append s1Z s2 C.yield s3 actual <- runConduit $ src .| do x <- fmap S.concat $ CZ.ungzip .| CL.consume y <- CL.consume return (x, y) actual `shouldBe` (s1, [s2, s3]) it "multiple, over 32k" $ do let str = "One line" cnt = 30000 src = replicateM_ cnt $ C.yield str .| CZ.gzip actual <- fmap S.concat $ runConduit $ src .| CZ.multiple CZ.ungzip .| CL.consume let expected = S.concat (replicate cnt str) S.length actual `shouldBe` S.length expected actual `shouldBe` expected conduit-extra-1.3.5/bench/blaze.hs0000644000000000000000000000353213626670615015223 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} import Data.Conduit import qualified Data.Conduit.List as CL import Data.Conduit.ByteString.Builder import Gauge.Main import Data.Monoid import Data.ByteString.Builder count :: Int count = 100000 single :: Builder single = shortByteString "Hello World!\n" oneBuilderLeft :: Builder oneBuilderLeft = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> single) oneBuilderRight :: Builder oneBuilderRight = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> single) builderSource :: Monad m => ConduitT i Builder m () builderSource = CL.replicate count single oneBSBuilderLeft :: Builder oneBSBuilderLeft = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> single) oneBSBuilderRight :: Builder oneBSBuilderRight = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> single) builderBSSource :: Monad m => ConduitT i Builder m () builderBSSource = CL.replicate count single main :: IO () main = defaultMain [ bench "conduit, strict, safe" $ whnfIO $ runConduit $ builderSource .| builderToByteString .| CL.sinkNull , bench "conduit, strict, unsafe" $ whnfIO $ runConduit $ builderSource .| unsafeBuilderToByteString .| CL.sinkNull , bench "one builder, left" $ nf toLazyByteString oneBuilderLeft , bench "one builder, right" $ nf toLazyByteString oneBuilderRight , bench "conduit, lazy" $ flip nf builderSource $ \src -> toLazyByteString $ runConduitPure $ src .| CL.fold (<>) mempty , bench "one bs builder, left" $ nf toLazyByteString oneBSBuilderLeft , bench "one bs builder, right" $ nf toLazyByteString oneBSBuilderRight , bench "conduit BS, lazy" $ flip nf builderBSSource $ \src -> toLazyByteString $ runConduitPure $ src .| CL.fold (<>) mempty ] conduit-extra-1.3.5/LICENSE0000644000000000000000000000207513626670615013521 0ustar0000000000000000Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. conduit-extra-1.3.5/Setup.lhs0000755000000000000000000000016213626670615014322 0ustar0000000000000000#!/usr/bin/env runhaskell > module Main where > import Distribution.Simple > main :: IO () > main = defaultMain conduit-extra-1.3.5/conduit-extra.cabal0000644000000000000000000001026413634353371016261 0ustar0000000000000000Name: conduit-extra Version: 1.3.5 Synopsis: Batteries included conduit: adapters for common libraries. Description: The conduit package itself maintains relative small dependencies. The purpose of this package is to collect commonly used utility functions wrapping other library dependencies, without depending on heavier-weight dependencies. The basic idea is that this package should only depend on haskell-platform packages and conduit. License: MIT License-file: LICENSE Author: Michael Snoyman Maintainer: michael@snoyman.com Category: Data, Conduit Build-type: Simple Cabal-version: >=1.8 Homepage: http://github.com/snoyberg/conduit extra-source-files: test/random test/filesystem/*.txt test/filesystem/bin/*.txt ChangeLog.md README.md Library Exposed-modules: Data.Conduit.Attoparsec Data.Conduit.Binary Data.Conduit.ByteString.Builder Data.Conduit.Filesystem Data.Conduit.Foldl Data.Conduit.Lazy Data.Conduit.Network Data.Conduit.Network.UDP Data.Conduit.Process Data.Conduit.Process.Typed Data.Conduit.Text Data.Conduit.Zlib if !os(windows) Exposed-modules: Data.Conduit.Network.Unix if arch(x86_64) || arch(i386) -- These architectures are able to perform unaligned memory accesses cpp-options: -DALLOW_UNALIGNED_ACCESS Build-depends: base >= 4.9 && < 5 , conduit >= 1.3 && < 1.4 , bytestring >= 0.10.2 , text , transformers , async , attoparsec >= 0.10 , directory , filepath , network >= 2.3 , primitive >= 0.5 , process , resourcet >= 1.1 , stm , streaming-commons >= 0.1.16 , unliftio-core , typed-process >= 0.2.6 ghc-options: -Wall test-suite test hs-source-dirs: test main-is: Spec.hs type: exitcode-stdio-1.0 ghc-options: -threaded cpp-options: -DTEST build-depends: conduit , conduit-extra , base , hspec >= 1.3 , async , attoparsec , bytestring-builder , bytestring , exceptions , process , resourcet , QuickCheck , stm , streaming-commons , text , transformers , transformers-base , directory , filepath ghc-options: -Wall if os(windows) cpp-options: -DWINDOWS other-modules: Data.Conduit.AttoparsecSpec Data.Conduit.BinarySpec Data.Conduit.ByteString.BuilderSpec Data.Conduit.ExtraSpec Data.Conduit.FilesystemSpec Data.Conduit.LazySpec Data.Conduit.NetworkSpec Data.Conduit.ProcessSpec Data.Conduit.Process.TypedSpec Data.Conduit.TextSpec Data.Conduit.ZlibSpec benchmark blaze type: exitcode-stdio-1.0 hs-source-dirs: bench build-depends: base , conduit , conduit-extra , gauge , bytestring , bytestring-builder , transformers main-is: blaze.hs ghc-options: -Wall -O2 -rtsopts source-repository head type: git location: git://github.com/snoyberg/conduit.git conduit-extra-1.3.5/test/random0000644000000000000000000000200013626670615014662 0ustar0000000000000000cnP_t9pJ!ؖ|9UuރHim@B ̅7eŧ/QYѣE >QQ5oa𻵵C/@p:0翏 VE9V˰.z= [@1&e&#b*v\^XXW$ījrv+4 Aϲ )|;ٔE^59g'1uJ'k5|UKπ@Xˠ Dޑ0ȜfkI^<켏3M[#tpJRkQg)@ߘ6Q?Z͖; 3C?dIAE*9&xJ42N