diff --git a/PEOPLE b/PEOPLE
--- a/PEOPLE
+++ b/PEOPLE
@@ -4,3 +4,4 @@
 
 Renzo Carbonara
 Paolo Capriotti
+Oliver Charles
diff --git a/pipes-zlib.cabal b/pipes-zlib.cabal
--- a/pipes-zlib.cabal
+++ b/pipes-zlib.cabal
@@ -1,5 +1,5 @@
 name:               pipes-zlib
-version:            0.2.0.0
+version:            0.3.0
 license:            BSD3
 license-file:       LICENSE
 Copyright:          Copyright (c) Paolo Capriotti 2012,
@@ -11,8 +11,8 @@
 bug-reports:        https://github.com/k0001/pipes-zlib/issues
 category:           Pipes, Compression
 build-type:         Simple
-synopsis:           Pipes to deal with zlib compressed data.
-description:        Pipes to deal with zlib compressed data.
+synopsis:           Zlib compression and decompression for Pipes streams
+description:        Zlib compression and decompression for Pipes streams
 cabal-version:      >=1.8
 extra-source-files: README.md PEOPLE
 
@@ -22,11 +22,11 @@
 
 library
     hs-source-dirs:  src
-    exposed-modules: Control.Proxy.Zlib
+    exposed-modules: Pipes.Zlib
     build-depends:   base             (>= 4.5 && < 5.0)
                    , transformers     (>= 0.2 && < 0.4)
-                   , pipes            (>= 3.3 && < 3.4)
+                   , pipes            (>= 4.0 && < 4.1)
                    , bytestring       (>= 0.9.2.1)
                    , zlib             (>= 0.5 && < 0.7)
                    , zlib-bindings    (>= 0.1 && < 0.2)
-    ghc-options: -Wall
+    ghc-options: -Wall -O2
diff --git a/src/Control/Proxy/Zlib.hs b/src/Control/Proxy/Zlib.hs
deleted file mode 100644
--- a/src/Control/Proxy/Zlib.hs
+++ /dev/null
@@ -1,95 +0,0 @@
--- | This module exports utilities to compress and decompress @pipes@ streams
--- using the zlib compression codec.
-
-module Control.Proxy.Zlib (
-  -- * Streams
-    decompressD
-  , compressD
-
-  -- * Compression level
-  -- $ccz-re-export
-  , ZC.defaultCompression
-  , ZC.noCompression
-  , ZC.bestSpeed
-  , ZC.bestCompression
-  , ZC.compressionLevel
-
-  -- * Window size
-  -- $ccz-re-export
-  , ZC.defaultWindowBits
-  , ZC.windowBits
-  ) where
-
-import qualified Codec.Zlib                as Z
-import qualified Codec.Compression.Zlib    as ZC
-import           Control.Monad             (forever, unless)
-import           Control.Monad.Trans.Class (lift)
-import           Control.Proxy             ((>->))
-import qualified Control.Proxy             as P
-import qualified Data.ByteString           as B
-import           Data.Traversable          (mapM)
-import           Prelude                   hiding (mapM)
-
---------------------------------------------------------------------------------
-
--- | Decompress bytes flowing downstream using the given 'Z.WindowBits'.
---
--- See the "Codec.Zlib" module for details about this values.
-decompressD
-  :: P.Proxy p
-  => Z.WindowBits
-  -> () -> P.Pipe p B.ByteString B.ByteString IO r
-decompressD config () = P.runIdentityP . forever $ do
-    inf <- lift (Z.initInflate config)
-    popper <- lift . Z.feedInflate inf =<< P.request ()
-    (P.unitD >-> fromPopperS popper) ()
-    bs <- lift (Z.finishInflate inf)
-    unless (B.null bs) $ P.respond bs
-
--- | Compress bytes flowing downstream.
---
--- See the "Codec.Zlib" module for details about these values.
-compressD
-  :: P.Proxy p
-  => ZC.CompressionLevel
-  -> Z.WindowBits
-  -> () -> P.Pipe p B.ByteString B.ByteString IO r
-compressD level config () = P.runIdentityP loop where
-    loop = forever $ do
-        def <- lift (Z.initDeflate level' config)
-        popper <- lift . Z.feedDeflate def =<< P.request ()
-        (P.unitD >-> fromPopperS popper) ()
-        mapM P.respond =<< lift (Z.finishDeflate def)
-    level' = fromCompressionLevel level
-
---------------------------------------------------------------------------------
-
--- $ccz-re-export
---
--- The following are re-exported from "Codec.Compression.Zlib" for your
--- convenience.
-
---------------------------------------------------------------------------------
--- Internal stuff
-
--- | Produce values from the given 'Z.Poppler' until exhausted.
-fromPopperS :: P.Proxy p => Z.Popper -> () -> P.Producer p B.ByteString IO ()
-fromPopperS pop () = P.runIdentityP loop where
-    loop = do
-        mbs <- lift pop
-        case mbs of
-          Nothing -> return ()
-          Just bs -> P.respond bs >> loop
-
--- We need this function until the @zlib@ library hides the
--- 'ZC.CompressionLevel' constructors in future version 0.7.
-fromCompressionLevel :: ZC.CompressionLevel -> Int
-fromCompressionLevel level = case level of
-    ZC.DefaultCompression   -> -1
-    ZC.NoCompression        -> 0
-    ZC.BestSpeed            -> 1
-    ZC.BestCompression      -> 9
-    ZC.CompressionLevel n
-         | n >= 0 && n <= 9 -> fromIntegral n
-    _  -> error "CompressLevel must be in the range 1..9"
-
diff --git a/src/Pipes/Zlib.hs b/src/Pipes/Zlib.hs
new file mode 100644
--- /dev/null
+++ b/src/Pipes/Zlib.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE RankNTypes #-}
+
+-- | This module exports utilities to compress and decompress @pipes@ streams
+-- using the zlib compression codec.
+
+module Pipes.Zlib (
+  -- * Streams
+    decompress
+  , compress
+
+  -- * Compression level
+  -- $ccz-re-export
+  , ZC.defaultCompression
+  , ZC.noCompression
+  , ZC.bestSpeed
+  , ZC.bestCompression
+  , ZC.compressionLevel
+
+  -- * Window size
+  -- $ccz-re-export
+  , ZC.defaultWindowBits
+  , ZC.windowBits
+  ) where
+
+import qualified Codec.Zlib                as Z
+import qualified Codec.Compression.Zlib    as ZC
+import           Control.Monad             (forever)
+import           Pipes
+import qualified Data.ByteString           as B
+
+--------------------------------------------------------------------------------
+
+-- | Decompress bytes flowing downstream.
+--
+-- See the "Codec.Compression.Zlib" module for details about 'Z.WindowBits'.
+decompress :: MonadIO m => ZC.WindowBits -> Pipe B.ByteString B.ByteString m r
+decompress config = forever $ do
+    inf <- liftIO (Z.initInflate config)
+    a <- awaitNonEmpty
+    popper <- liftIO (Z.feedInflate inf a)
+    fromPopper popper
+    bs <- liftIO (Z.finishInflate inf)
+    if B.null bs
+        then return ()
+        else yield bs
+{-# INLINABLE decompress #-}
+
+-- | Compress bytes flowing downstream.
+--
+-- See the "Codec.Compression.Zlib" module for details about
+-- 'ZC.CompressionLevel' and 'ZC.WindowBits'.
+compress
+  :: MonadIO m
+  => ZC.CompressionLevel -> ZC.WindowBits -> Pipe B.ByteString B.ByteString m r
+compress level config = forever $ do
+    def <- liftIO (Z.initDeflate level' config)
+    a <- awaitNonEmpty
+    popper <- liftIO (Z.feedDeflate def a)
+    fromPopper popper
+    mbs <- liftIO (Z.finishDeflate def)
+    case mbs of
+        Just bs -> yield bs
+        Nothing -> return ()
+  where
+    level' = fromCompressionLevel level
+{-# INLINABLE compress #-}
+
+--------------------------------------------------------------------------------
+
+-- $ccz-re-export
+--
+-- The following are re-exported from "Codec.Compression.Zlib" for your
+-- convenience.
+
+--------------------------------------------------------------------------------
+-- Internal stuff
+
+awaitNonEmpty :: Monad m => Consumer' B.ByteString m B.ByteString
+awaitNonEmpty = loop
+  where
+    loop = do
+        bs <- await
+        if B.null bs
+            then loop
+            else return bs
+{-# INLINABLE awaitNonEmpty #-}
+
+-- | Produce values from the given 'Z.Poppler' until exhausted.
+fromPopper :: MonadIO m => Z.Popper -> Producer' B.ByteString m ()
+fromPopper pop = loop
+  where
+    loop = do
+        mbs <- liftIO pop
+        case mbs of
+            Nothing -> return ()
+            Just bs -> yield bs >> loop
+{-# INLINABLE fromPopper #-}
+
+-- We need this function until the @zlib@ library hides the
+-- 'ZC.CompressionLevel' constructors in future version 0.7.
+fromCompressionLevel :: ZC.CompressionLevel -> Int
+fromCompressionLevel level = case level of
+    ZC.DefaultCompression   -> -1
+    ZC.NoCompression        -> 0
+    ZC.BestSpeed            -> 1
+    ZC.BestCompression      -> 9
+    ZC.CompressionLevel n
+         | n >= 0 && n <= 9 -> fromIntegral n
+    _  -> error "CompressLevel must be in the range 1..9"
+
