diff --git a/Control/Proxy/Vector.hs b/Control/Proxy/Vector.hs
deleted file mode 100644
--- a/Control/Proxy/Vector.hs
+++ /dev/null
@@ -1,47 +0,0 @@
-module Control.Proxy.Vector ( toVectorD, runToVectorK, runToVectorP ) where
-
-import           Control.Applicative
-import           Control.Monad
-import           Control.Monad.Primitive
-import           Control.Proxy
-import           Control.Proxy.Trans.State as S
-import qualified Data.Vector.Unboxed.Mutable as MVU
-import qualified Data.Vector.Generic as V
-import qualified Data.Vector.Generic.Mutable as M
-import qualified Data.Vector.Unboxed as VU
-
-data ToVectorState v m e = ToVecS { result :: v (PrimState m) e
-                                  , idx    :: Int
-                                  }
-
-maxChunkSize = 8*1024*1024
-
-toVectorD
-    :: (PrimMonad m, Proxy p, M.MVector v e)
-    => () -> Consumer (S.StateP (ToVectorState v m e) p) e m r
-toVectorD () = forever $ do
-     length <- M.length . result <$> get
-     pos <- idx `liftM` get
-     when (pos >= length) $ do
-         v <- result `liftM` get
-         v' <- lift $ M.unsafeGrow v (min length maxChunkSize)
-         modify $ \(ToVecS r i) -> ToVecS v' i
-     r <- request ()
-     v <- result `liftM` get
-     lift $ M.unsafeWrite v pos r
-     modify $ \(ToVecS r i) -> ToVecS r (pos+1)
-
-runToVectorK
-    :: (PrimMonad m, MVU.Unbox e, Monad (p a' a b' b m), Proxy p, MonadTrans (p a' a b' b))
-    => (q -> StateP (ToVectorState VU.MVector m e) p a' a b' b m r)
-    -> (q -> p a' a b' b m (VU.Vector e))
-runToVectorK k q = runToVectorP (k q)
-
-runToVectorP
-    :: (PrimMonad m, MVU.Unbox e, Monad (p a' a b' b m), Proxy p, MonadTrans (p a' a b' b))
-    => StateP (ToVectorState VU.MVector m e) p a' a b' b m r -> p a' a b' b m (VU.Vector e)
-runToVectorP x = do
-    v <- lift $ MVU.new 10
-    s <- execStateP (ToVecS v 0) x
-    frozen <- lift $ V.freeze (result s)
-    return $ VU.take (idx s) frozen
diff --git a/Pipes/Vector.hs b/Pipes/Vector.hs
new file mode 100644
--- /dev/null
+++ b/Pipes/Vector.hs
@@ -0,0 +1,84 @@
+{-# LANGUAGE RankNTypes, FlexibleContexts, GeneralizedNewtypeDeriving #-}
+
+{-| Pipes for interfacing with "Data.Vector".
+
+    Note that this only provides functionality for building @Vectors@
+    from Pipes; as @Vectors@ are @Foldable@ the inverse can be
+    accomplished with "Pipes.each".
+-}
+
+module Pipes.Vector (
+    -- * Usage
+    -- $usage
+    -- * Building Vectors from Pipes
+    toVector,
+    runToVectorP,
+    runToVector,
+    ToVector
+    ) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans.State.Strict as S
+import Control.Monad.Primitive
+import Pipes
+import Pipes.Internal (unsafeHoist)
+import Pipes.Lift
+import qualified Data.Vector.Generic as V
+import qualified Data.Vector.Generic.Mutable as M
+
+data ToVectorState v e m = ToVecS { result :: V.Mutable v (PrimState m) e
+                                  , idx :: Int
+                                  }
+
+newtype ToVector v e m r = TV {unTV :: S.StateT (ToVectorState v e m) m r}
+                         deriving (Functor, Applicative, Monad)
+
+maxChunkSize :: Int
+maxChunkSize = 8*1024*1024
+
+-- | Consume items from a Pipe and place them into a vector
+--
+-- For efficient filling, the vector is grown geometrically up to a
+-- maximum chunk size.
+toVector
+     :: (PrimMonad m, M.MVector (V.Mutable v) e)
+     => Consumer e (ToVector v e m) r
+toVector = forever $ do
+      length <- M.length . result <$> lift (TV get)
+      pos <- idx `liftM` lift (TV get)
+      lift $ TV $ when (pos >= length) $ do
+          v <- result `liftM` get
+          v' <- lift $ M.unsafeGrow v (min length maxChunkSize)
+          modify $ \(ToVecS r i) -> ToVecS v' i
+      r <- await
+      lift $ TV $ do
+          v <- result `liftM` get
+          lift $ M.unsafeWrite v pos r
+          modify $ \(ToVecS r i) -> ToVecS r (pos+1)
+
+-- | Extract and freeze the constructed vector
+runToVectorP
+     :: (PrimMonad m, V.Vector v e)
+     => Proxy a' a b' b (ToVector v e m) r
+     -> Proxy a' a b' b m (v e)
+runToVectorP x = do
+     v <- lift $ M.new 10
+     s <- execStateP (ToVecS v 0) (hoist unTV x)
+     frozen <- lift $ V.freeze (result s)
+     return $ V.take (idx s) frozen
+
+runToVector :: (PrimMonad m, V.Vector v e)
+            => ToVector v e m r -> m (v e)
+runToVector (TV a) = do
+     v <- M.new 10
+     s <- execStateT a (ToVecS v 0)
+     frozen <- V.freeze (result s)
+     return $ V.take (idx s) frozen
+
+{- $usage
+
+   >>> run $ runToVectorP $ each [1..5::Int] >-> toVector
+   fromList [1,2,3,4,5]
+
+-}
diff --git a/pipes-vector.cabal b/pipes-vector.cabal
--- a/pipes-vector.cabal
+++ b/pipes-vector.cabal
@@ -1,7 +1,7 @@
 name:                pipes-vector
-version:             0.3.0.0
-synopsis:            Various proxies for streaming data into and out of vectors
-description:         Proxies for streaming data into and out of vectors.        
+version:             0.5.1
+synopsis:            Various proxies for streaming data into vectors
+description:         Proxies for streaming data into vectors.        
 license:             BSD3
 license-file:        LICENSE
 author:              Ben Gamari
@@ -12,10 +12,10 @@
 cabal-version:       >=1.10
 
 library
-  exposed-modules:     Control.Proxy.Vector
+  exposed-modules:     Pipes.Vector
   build-depends:       base >=3.0 && <5,
-                       transformers >= 0.3 && < 1.0,
+                       transformers >= 0.2 && < 1.0,
                        primitive >=0.4 && <1.0,
-                       pipes >=3.3 && <3.4,
+                       pipes >=4.0 && <5.0,
                        vector >=0.9 && <1.0
   default-language:    Haskell2010
