packages feed

pipes-zlib 0.1.0 → 0.4.4.2

raw patch · 10 files changed

Files

− Control/Pipe/Zlib.hs
@@ -1,59 +0,0 @@-module Control.Pipe.Zlib (-  gzip,-  gunzip,-  decompress,-  compress-  ) where--import Codec.Zlib-import Control.Monad-import Control.Monad.IO.Class-import Control.Pipe-import Control.Pipe.Combinators-import qualified Data.ByteString as B-import Prelude hiding (catch)---- | Gzip compression with default parameters.-gzip :: MonadIO m => Pipe B.ByteString B.ByteString m r-gzip = compress 1 (WindowBits 31)---- | Gzip decompression with default parameters.-gunzip :: MonadIO m => Pipe B.ByteString B.ByteString m r-gunzip = decompress (WindowBits 31)--decompress-    :: MonadIO m-    => WindowBits-    -> Pipe B.ByteString B.ByteString m r-decompress config = do-    inf <- liftIO $ initInflate config-    let finalize = do chunk <- liftIO $ finishInflate inf-                      unless (B.null chunk) $ yield chunk-    forP' finalize $ \x -> do-      popper <- liftIO $ feedInflate inf x-      yieldPopper popper--compress-    :: MonadIO m-    => Int-    -> WindowBits-    -> Pipe B.ByteString B.ByteString m r-compress level config = do-    def <- liftIO $ initDeflate level config-    let finalize = yieldPopper (finishDeflate def)-    forP' finalize $ \x -> do-      popper <- liftIO $ feedDeflate def x-      yieldPopper popper--forP' :: Monad m-      => Pipe a b m r2-      -> (a -> Pipe a b m r1)-      -> Pipe a b m r-forP' p f = forP f >> p >> discard--yieldPopper :: MonadIO m => Popper -> Pipe a B.ByteString m ()-yieldPopper pop = do-  x <- liftIO pop-  case x of-    Nothing -> return ()-    Just chunk -> yield chunk >> yieldPopper pop
LICENSE view
@@ -1,4 +1,5 @@-Copyright (c) 2012 Paolo Capriotti <p.capriotti@gmail.com>,+Copyright (c) 2012 Paolo Capriotti <p.capriotti@gmail.com>+Copyright (c) 2013-2018 Renzo Carbonara <renλren.zone>  All rights reserved. 
+ PEOPLE view
@@ -0,0 +1,8 @@+The following people have participated in creating this library, either+by directly contributing code or by providing thoughtful input in+discussions about the library design.++Renzo Carbonara+Paolo Capriotti+Oliver Charles+Gabriel Gonzalez
+ README.md view
@@ -0,0 +1,12 @@+# pipes-zlib++Utilities to deal with zlib compressed streams the **pipes** and libraries.++Check the source or rendered Haddocks for extensive documentation.++This code is licensed under the terms of the so called **3-clause BSD+license**. Read the file named ``LICENSE`` found in this same directory+for details.++See the ``PEOPLE`` file to learn about the people involved in this+effort.
Setup.hs view
@@ -1,2 +1,4 @@+#! /usr/bin/env nix-shell+#! nix-shell ./shell.nix -i runghc import Distribution.Simple main = defaultMain
+ changelog.md view
@@ -0,0 +1,77 @@+# Version 0.4.4.2++* Remove upper bound from all dependencies except `base`.+++# Version 0.4.4.1++* Bump upper bound dependency on `pipes`.+++# Version 0.4.4++* Depend on `streaming-commons` instead of `zlib` and `zlib-bindings`,+  as the latter are deprecated.++* Add `Pipes.Zlib.decompress'` and `Pipes.GZip.decompress'`.++* Bump upper bound dependency on `transformers`.++* Add tests.+++# Version 0.4.3++* Fix usage of the `Producer'` type synonym (#14).+++# Version 0.4.2.1++* Fix “Codec.Compression.Zlib: premature end of compressed stream” (#13)+++# Version 0.4.2++* Added the `Pipes/GZip.hs` file that was missing in 0.4.1.+++# Version 0.4.1++* Added `Pipes.GZip` module.+++# Version 0.4.0.1++* Bump upper bound dependency on `transformers`.+++# Version 0.4.0++* Backwards incompatible API. `compress` and `decompress` are now+  functions of `Producer'`s as they need to perform actions at the+  beginning and end of input. (Issue #3)+++# Version 0.3.1++* Dependency upper bounds.+++# Version 0.3.0++* Upgraded to work with pipes-4.0.0, creating a new backwards+  incompatible API.++* Generalize base `IO` monad to `MonadIO`.+++# Version 0.2.0.0++* New backwards incompatible API.++* Based on pipes-3.3 and zlib-bindings.+++# Up to version 0.1.0++* Based on pipes-core and zlib-bindings.
pipes-zlib.cabal view
@@ -1,27 +1,53 @@-Name: pipes-zlib-Version: 0.1.0-License: BSD3-License-file: LICENSE-Author: Paolo Capriotti-Maintainer: p.capriotti@gmail.com-Stability: Experimental-Homepage: https://github.com/pcapriotti/pipes-extra-Category: Control, Enumerator, Compression-Build-type: Simple-Synopsis: Pipes to deal with zipped data.-Description: Pipes to deal with zipped data.-Cabal-version: >=1.8+name:               pipes-zlib+version:            0.4.4.2+license:            BSD3+license-file:       LICENSE+Copyright:          Copyright (c) Paolo Capriotti 2012, Renzo Carbonara 2013-2018+author:             Renzo Carbonara, Paolo Capriotti+maintainer:         renλren.zone+stability:          Experimental+homepage:           https://github.com/k0001/pipes-zlib+bug-reports:        https://github.com/k0001/pipes-zlib/issues+category:           Pipes, Compression+build-type:         Simple+synopsis:           Zlib and GZip compression and decompression for Pipes streams+description:        Zlib and GZip compression and decompression for Pipes streams+cabal-version:      >=1.10+extra-source-files: README.md PEOPLE changelog.md -Source-Repository head-    Type: git-    Location: https://github.com/pcapriotti/pipes-extra+source-repository head+    type: git+    location: git://github.com/k0001/pipes-zlib.git -Library-    Build-Depends:-        base (== 4.*),-        transformers (>= 0.2 && < 0.4),-        pipes-core (== 0.1.*),-        bytestring (== 0.9.*),-        zlib-bindings (== 0.1.*)-    Exposed-Modules:-        Control.Pipe.Zlib+library+    hs-source-dirs:  src+    exposed-modules: Pipes.Zlib+                     Pipes.GZip+    build-depends:   base >= 4.5 && < 5.0+                   , transformers >= 0.2+                   , pipes >= 4.0+                   , bytestring >= 0.9.2.1+                   , streaming-commons >= 0.1.15+    ghc-options: -Wall -O2+    default-language:    Haskell2010++test-suite test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Main.hs+  build-depends:       base+                     , pipes-zlib+                     , pipes+                     , bytestring+                     , HUnit+                     , QuickCheck+                     , quickcheck-instances+                     , tasty+                     , tasty-quickcheck+                     , tasty-hunit+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/githubuser/twio
+ src/Pipes/GZip.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE RankNTypes #-}++-- | This module exports utilities to compress and decompress GZip @pipes@+-- streams.++module Pipes.GZip (+  -- * Streams+    decompress+  , decompress'+  , compress++  -- * Compression level+  , Pipes.Zlib.CompressionLevel+  , Pipes.Zlib.defaultCompression+  , Pipes.Zlib.noCompression+  , Pipes.Zlib.bestSpeed+  , Pipes.Zlib.bestCompression+  , Pipes.Zlib.compressionLevel+  ) where++import qualified Data.Streaming.Zlib       as Zlib+import qualified Data.ByteString           as B+import           Pipes+import qualified Pipes.Zlib++--------------------------------------------------------------------------------++-- | Decompress bytes flowing from a 'Producer'.+--+-- @+-- 'decompress' :: 'MonadIO' m+--            => 'Producer' 'B.ByteString' m r+--            -> 'Producer' 'B.ByteString' m r+-- @+decompress+  :: MonadIO m+  => Proxy x' x () B.ByteString m r -- ^ Compressed stream+  -> Proxy x' x () B.ByteString m r -- ^ Decompressed stream+decompress = Pipes.Zlib.decompress gzWindowBits+{-# INLINABLE decompress #-}++-- | Decompress bytes flowing from a 'Producer', returning any leftover input+-- that follows the compressed stream.+decompress'+  :: MonadIO m+  => Producer B.ByteString m r -- ^ Compressed stream+  -> Producer B.ByteString m (Either (Producer B.ByteString m r) r)+     -- ^ Decompressed stream, returning either a 'Producer' of the leftover input+     -- or the return value from the input 'Producer'.+decompress' = Pipes.Zlib.decompress' gzWindowBits+{-# INLINABLE decompress' #-}+++-- | Compress bytes flowing from a 'Producer'.+--+-- @+-- 'compress' :: 'MonadIO' m+--          => 'ZC.CompressionLevel'+--          -> 'Producer' 'B.ByteString' m r+--          -> 'Producer' 'B.ByteString' m r+-- @+compress+  :: MonadIO m+  => Pipes.Zlib.CompressionLevel+  -> Proxy x' x () B.ByteString m r -- ^ Decompressed stream+  -> Proxy x' x () B.ByteString m r -- ^ Compressed stream+compress clevel = Pipes.Zlib.compress clevel gzWindowBits+{-# INLINABLE compress #-}++gzWindowBits :: Zlib.WindowBits+gzWindowBits = Zlib.WindowBits 31
+ src/Pipes/Zlib.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | This module exports utilities to compress and decompress @pipes@ streams+-- using the zlib compression codec.+--+-- If you want to compress or decompress GZip streams, use the "Pipes.GZip"+-- module instead.++module Pipes.Zlib (+  -- * Streams+    decompress+  , decompress'+  , compress++  -- * Compression levels+  , CompressionLevel+  , defaultCompression+  , noCompression+  , bestSpeed+  , bestCompression+  , compressionLevel++  -- * Window size+  -- $ccz-re-export+  , Z.defaultWindowBits+  , windowBits+  ) where++import           Data.Streaming.Zlib       as Z+import           Control.Exception         (throwIO)+import           Control.Monad             (unless)+import qualified Data.ByteString           as B+import           Pipes++--------------------------------------------------------------------------------++-- | Decompress bytes flowing from a 'Producer'.+--+-- See the "Codec.Compression.Zlib" module for details about 'Z.WindowBits'.+--+-- @+-- 'decompress' :: 'MonadIO' m+--            => 'Z.WindowBits'+--            => 'Producer' 'B.ByteString' m r+--            -> 'Producer' 'B.ByteString' m r+-- @+decompress+  :: MonadIO m+  => Z.WindowBits+  -> Proxy x' x () B.ByteString m r -- ^ Compressed stream+  -> Proxy x' x () B.ByteString m r -- ^ Decompressed stream+decompress wbits p0 = do+    inf <- liftIO $ Z.initInflate wbits+    r <- for p0 $ \bs -> do+       popper <- liftIO (Z.feedInflate inf bs)+       fromPopper popper+    bs <- liftIO $ Z.finishInflate inf+    unless (B.null bs) (yield bs)+    return r+{-# INLINABLE decompress #-}++-- | Decompress bytes flowing from a 'Producer', returning any leftover input+-- that follows the compressed stream.+decompress'+  :: MonadIO m+  => Z.WindowBits+  -> Producer B.ByteString m r -- ^ Compressed stream+  -> Producer B.ByteString m (Either (Producer B.ByteString m r) r)+     -- ^ Decompressed stream, ending with either leftovers or a result+decompress' wbits p0 = go p0 =<< liftIO (Z.initInflate wbits)+  where+    flush inf = do+      bs <- liftIO $ Z.flushInflate inf+      unless (B.null bs) (yield bs)+    go p inf = do+      res <- lift (next p)+      case res of+         Left r -> return $ Right r+         Right (bs, p') -> do+            fromPopper =<< liftIO (Z.feedInflate inf bs)+            flush inf+            leftover <- liftIO $ Z.getUnusedInflate inf+            if B.null leftover+               then go p' inf+               else return $ Left (yield leftover >> p')+{-# INLINABLE decompress' #-}++-- | Compress bytes flowing from a 'Producer'.+--+-- See the "Codec.Compression.Zlib" module for details about+-- 'Z.CompressionLevel' and 'Z.WindowBits'.+--+-- @+-- 'compress' :: 'MonadIO' m+--          => 'Z.CompressionLevel'+--          -> 'Z.WindowBits'+--          -> 'Producer' 'B.ByteString' m r+--          -> 'Producer' 'B.ByteString' m r+-- @+compress+  :: MonadIO m+  => CompressionLevel+  -> Z.WindowBits+  -> Proxy x' x () B.ByteString m r -- ^ Decompressed stream+  -> Proxy x' x () B.ByteString m r -- ^ Compressed stream+compress (CompressionLevel clevel) wbits p0 = do+    def <- liftIO $ Z.initDeflate clevel wbits+    r <- for p0 $ \bs -> do+       popper <- liftIO (Z.feedDeflate def bs)+       fromPopper popper+    fromPopper $ Z.finishDeflate def+    return r+{-# INLINABLE compress #-}++--------------------------------------------------------------------------------++-- $ccz-re-export+--+-- The following are re-exported from "Codec.Compression.Zlib" for your+-- convenience.++--------------------------------------------------------------------------------+-- Compression Levels++-- | How hard should we try to compress?+newtype CompressionLevel = CompressionLevel Int+                         deriving (Show, Read, Eq, Ord)++defaultCompression, noCompression, bestSpeed, bestCompression :: CompressionLevel+defaultCompression = CompressionLevel (-1)+noCompression      = CompressionLevel 0+bestSpeed          = CompressionLevel 1+bestCompression    = CompressionLevel 9++-- | A specific compression level between 0 and 9.+compressionLevel :: Int -> CompressionLevel+compressionLevel n+  | n >= 0 && n <= 9 = CompressionLevel n+  | otherwise        = error "CompressionLevel must be in the range 0..9"++windowBits :: Int -> WindowBits+windowBits = WindowBits++--------------------------------------------------------------------------------+-- Internal stuff++-- | Produce values from the given 'Z.Popper' until exhausted.+fromPopper :: MonadIO m+           => Z.Popper+           -> Producer' B.ByteString m ()+fromPopper pop = loop+  where+    loop = do+      mbs <- liftIO pop+      case mbs of+          PRDone     -> return ()+          PRError e  -> liftIO $ throwIO e+          PRNext bs  -> yield bs >> loop+{-# INLINABLE fromPopper #-}
+ test/Main.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE OverloadedStrings #-}+import           Control.Arrow+import qualified Data.ByteString.Char8 as B8+import           Data.List+import           Data.Ord+import           Test.Tasty+import           Test.Tasty.QuickCheck as QC+import           Test.QuickCheck.Instances ()+import           Test.Tasty.HUnit++import qualified Pipes as P+import qualified Pipes.Prelude as P+import qualified Pipes.Zlib as PZ+import qualified Pipes.GZip as PGZ++main = defaultMain tests++--------------------------------------------------------------------------------+tests :: TestTree+tests = testGroup "Tests" [properties, unitTests]++properties :: TestTree+properties = testGroup "Properties" [qcProps]++qcProps = testGroup "(checked by QuickCheck)"+ [ QC.testProperty "id == decompress . compress" $ \bs -> QC.ioProperty $ do+     let pc = PZ.compress PZ.defaultCompression PZ.defaultWindowBits (P.yield bs)+         pd = PZ.decompress PZ.defaultWindowBits pc+     bs' <- B8.concat <$> P.toListM pd+     return (bs QC.=== bs')++ , QC.testProperty "id == decompress' . compress" $ \bs bsl -> QC.ioProperty $ do+     let pc = PZ.compress PZ.defaultCompression PZ.defaultWindowBits (P.yield bs)+         pd = PZ.decompress' PZ.defaultWindowBits (pc >> P.yield bsl)+     (bs', elr) <- first B8.concat <$> P.toListM' pd+     case elr of+        Left pl -> do+           bsl' <- B8.concat <$> P.toListM pl+           return $ (bs QC.=== bs') QC..&&. (bsl QC.=== bsl')+        Right () -> do+           return $ (bs QC.=== bs') QC..&&. (bsl QC.=== B8.empty)+ ]++unitTests = testGroup "Unit tests"+  [ testCase "Zlib compression default" $ do+      let pc = PZ.compress PZ.defaultCompression PZ.defaultWindowBits+                   (P.yield bsUncompressed)+      bs <- B8.concat <$> P.toListM pc+      bs @?= bsCompressedZlibDefault+  , testCase "Zlib decompression default" $ do+      let pd = PZ.decompress PZ.defaultWindowBits+                   (P.yield bsCompressedZlibDefault)+      bs <- B8.concat <$> P.toListM pd+      bs @?= bsUncompressed+  , testCase "GZip compression default" $ do+      let pd = PGZ.compress PGZ.defaultCompression (P.yield bsUncompressed)+      bs <- B8.concat <$> P.toListM pd+      bs @?= bsCompressedGZipDefault+  , testCase "GZip decompression default" $ do+      let pd = PGZ.decompress (P.yield bsCompressedGZipDefault)+      bs <- B8.concat <$> P.toListM pd+      bs @?= bsUncompressed+  ]++bsUncompressed :: B8.ByteString+bsUncompressed = "foo"++bsCompressedZlibDefault :: B8.ByteString+bsCompressedZlibDefault = "x\156K\203\207\a\NUL\STX\130\SOHE"++bsCompressedGZipDefault :: B8.ByteString+bsCompressedGZipDefault =+  "\US\139\b\NUL\NUL\NUL\NUL\NUL\NUL\ETXK\203\207\a\NUL!es\140\ETX\NUL\NUL\NUL"