diff --git a/mutable-iter.cabal b/mutable-iter.cabal
--- a/mutable-iter.cabal
+++ b/mutable-iter.cabal
@@ -1,8 +1,8 @@
 Name:                mutable-iter
-Version:             0.5
+Version:             0.6
 Synopsis:            iteratees based upon mutable buffers
 Description:         Provides iteratees backed by mutable buffers.  This enables iteratees to run without any extra memory allocations.
-Homepage:            http://tanimoto.us/~jwlato/haskell/mutable-iter
+Homepage:            http://jwlato.webfactional.com/haskell/mutable-iter
 License:             BSD3
 License-file:        LICENSE
 Author:              John W. Lato
@@ -26,9 +26,10 @@
   Exposed-modules:     Data.MutableIter
                       ,Data.MutableIter.Binary
                       ,Data.MutableIter.IOBuffer
+  ghc-options:        -funfolding-use-threshold=64
   Build-depends:
     base                      >= 4         && < 6,
-    iteratee                  >= 0.5       && < 0.8,
+    iteratee                  >= 0.5       && < 0.9,
     MonadCatchIO-transformers >= 0.2       && < 0.3,
     transformers              >= 0.2       && < 0.3,
     vector                    >= 0.4       && < 0.9
diff --git a/src/Data/MutableIter.hs b/src/Data/MutableIter.hs
--- a/src/Data/MutableIter.hs
+++ b/src/Data/MutableIter.hs
@@ -17,6 +17,7 @@
   ,idone
   ,icont
   ,guardNull
+  ,isStreamFinished
   ,head
   ,heads
   ,peek
@@ -24,9 +25,11 @@
   ,dropWhile
   ,foldl'
   ,mapStream
+  ,mapChunk
   ,mapAccum
   ,convStream
   ,takeUpTo
+  ,fromUVector
   ,enumHandleRandom
   ,fileDriverRandom
   ,newFp
@@ -42,8 +45,9 @@
 
 import qualified Data.Iteratee as I
 import Data.Maybe
+import qualified Data.Vector.Unboxed as U
 
-import Control.Exception (SomeException, IOException)
+import Control.Exception (SomeException, IOException, toException)
 import Control.Monad
 import Control.Monad.CatchIO as CIO
 import Control.Monad.IO.Class
@@ -95,7 +99,7 @@
 mapIteratee f = lift . f . I.run . unwrap
 
 joinIob :: (MonadCatchIO m, Storable el) =>
-  MIteratee (IOBuffer r el) m (MIteratee (IOBuffer r el') m a)
+  MIteratee (IOBuffer r el) m (MIteratee s m a)
   -> MIteratee (IOBuffer r el) m a
 joinIob outer = outer >>= \inner -> MIteratee $ I.Iteratee $ \od oc ->
   let onDone  x _        = od x (I.Chunk empty)
@@ -133,22 +137,35 @@
 guardNull buf onEmpty onFull = do
   isNull <- liftIO $ null buf
   if isNull then onEmpty else onFull
+{-# INLINE guardNull #-}
 
+isStreamFinished ::
+ (MonadCatchIO m, Storable el) =>
+  MIteratee (IOBuffer r el) m (Maybe SomeException)
+isStreamFinished = liftI step
+  where
+    step s@(I.Chunk buf) = guardNull buf (liftI step) (idone Nothing s)
+    step s@(I.EOF e) =
+      idone (Just $ fromMaybe (toException I.EofException) e) s
+{-# INLINE isStreamFinished #-}
+
 head :: (MonadCatchIO m, Storable el) => MIteratee (IOBuffer r el) m el
 head = liftI step
   where
-    step (I.Chunk buf) = guardNull buf (icont step Nothing) $ do
+    step (I.Chunk buf) = guardNull buf (liftI step) $ do
       x <- liftIO $ pop buf
       idone x (I.Chunk buf)
     step str = MIteratee . I.throwErr . toException $ I.EofException
+{-# INLINE head #-}
 
 peek :: (MonadCatchIO m, Storable el) => MIteratee (IOBuffer r el) m (Maybe el)
 peek = liftI step
   where
-    step c@(I.Chunk buf) = guardNull buf (icont step Nothing) $ do
+    step c@(I.Chunk buf) = guardNull buf (liftI step) $ do
       x <- liftIO $ IB.lookAtHead buf
       idone x c
     step str = idone Nothing str
+{-# INLINE peek #-}
 
 heads :: (MonadCatchIO m, Storable el, Eq el) =>
   [el]
@@ -159,32 +176,35 @@
     loop cnt str = liftI (step cnt str)
     step cnt s@(x:xs) (I.Chunk buf) = do
       mx <- liftIO $ IB.lookAtHead buf
-      maybe (icont (step cnt s) Nothing) (\h -> if h == x
+      maybe (liftI (step cnt s)) (\h -> if h == x
         then liftIO (pop buf) >> step (succ cnt) xs (I.Chunk buf)
         else idone cnt (I.Chunk buf)) mx
     step cnt s str = idone cnt str
+{-# INLINE heads #-}
 
 drop :: (MonadCatchIO m, Storable el) => Int -> MIteratee (IOBuffer r el) m ()
 drop n = liftI (step n)
   where
     step 0  str           = idone () str
-    step n' (I.Chunk buf) = guardNull buf (icont (step n') Nothing) $ do
+    step n' (I.Chunk buf) = guardNull buf (liftI (step n')) $ do
       l <- liftIO $ IB.length buf
       if n' < l
         then liftIO (IB.drop n' buf) >> idone () (I.Chunk buf)
         else liftIO (IB.drop l buf) >> liftI (step (n' - l))
     step _ str = idone () str
+{-# INLINE drop #-}
 
 dropWhile :: (MonadCatchIO m, Storable el) =>
   (el -> Bool)
   -> MIteratee (IOBuffer r el) m ()
 dropWhile pred = liftI step
   where
-    step (I.Chunk buf) = guardNull buf (icont step Nothing) $ do
+    step (I.Chunk buf) = guardNull buf (liftI step) $ do
       liftIO $ IB.dropWhile pred buf
       l <- liftIO $ IB.length buf
-      if l == 0 then icont step Nothing else idone () (I.Chunk buf)
+      if l == 0 then liftI step else idone () (I.Chunk buf)
     step str = idone () str
+{-# INLINE dropWhile #-}
 
 foldl' :: (MonadCatchIO m, Storable el, Show a) =>
   (a -> el -> a)
@@ -194,8 +214,9 @@
   where
     step acc (I.Chunk buf) = guardNull buf (liftI (step acc)) $ do
       newacc <- liftIO $ IB.foldl' f acc buf
-      icont (step newacc) Nothing
+      liftI (step newacc)
     step acc str = idone acc str
+{-# INLINE foldl' #-}
 
 
 -- -----------------------------------------------------------
@@ -213,14 +234,12 @@
       onCont k Nothing  = I.runIter (unwrap $ f (MIteratee . k)) od oc
       onCont _ (Just e) = I.runIter (I.throwErr e) od oc
   in I.runIter (unwrap inner) onDone (onCont)
+{-# INLINE eneeCheckIfDone #-}
 
 mapStream :: (MonadCatchIO pr, Storable elo, Storable eli) =>
   Int
   -> (eli -> elo)
-  -> MEnumeratee (IOBuffer r eli)
-                 (IOBuffer r elo)
-                 pr
-                 a
+  -> MEnumeratee (IOBuffer r eli) (IOBuffer r elo) pr a
 mapStream maxlen f i = do
   offp <- liftIO $ newFp 0
   bufp <- liftIO $ mallocForeignPtrArray maxlen
@@ -233,6 +252,17 @@
         goMap offp bufp $ k (I.Chunk newIOBuf)
     step _    _    k s             = idone (liftI k) s
 
+mapChunk :: (Storable el, MonadCatchIO m) =>
+  (IOBuffer r el -> m s2)
+   -> MEnumeratee (IOBuffer r el) s2 m a
+mapChunk f i = go i
+ where
+  go = eneeCheckIfDone (liftI . step)
+  step k (I.Chunk buf) = lift (f buf) >>= go . k . I.Chunk
+  step k s             = idone (liftI k) s
+{-# INLINE mapChunk #-}
+
+
 mapAccum :: (MonadCatchIO pr, Storable eli, Storable elo) =>
   Int
   -> (b -> eli -> (b,elo))
@@ -252,13 +282,10 @@
 
 convStream :: (MonadCatchIO pr, Storable elo, Storable eli) =>
   MIteratee (IOBuffer r eli) pr (IOBuffer r elo)
-  -> MEnumeratee (IOBuffer r eli)
-                 (IOBuffer r elo)
-                 pr
-                 a
+  -> MEnumeratee (IOBuffer r eli) (IOBuffer r elo) pr a
 convStream fi = eneeCheckIfDone check
   where
-    check k = MIteratee (I.isStreamFinished) >>=
+    check k = isStreamFinished >>=
               maybe (step k) (idone (liftI k) . I.EOF . Just)
     step k = fi >>= convStream fi . k . I.Chunk
 
@@ -284,6 +311,13 @@
 
 -- ---------------------------------------------
 -- drivers and enumerators
+
+-- So users don't need to manually work with IOBuffers all the time
+fromUVector :: (U.Unbox el, Storable el, MonadCatchIO m) =>
+  I.Iteratee (U.Vector el) m a
+  -> MIteratee (IOBuffer r el) m a
+fromUVector = joinIob . mapChunk (liftIO . IB.freeze) . MIteratee
+{-# INLINE fromUVector #-}
 
 makeHandleCallback :: (MonadCatchIO m, Storable el) =>
   ForeignPtr Int
diff --git a/src/Data/MutableIter/IOBuffer.hs b/src/Data/MutableIter/IOBuffer.hs
--- a/src/Data/MutableIter/IOBuffer.hs
+++ b/src/Data/MutableIter/IOBuffer.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
+{-# LANGUAGE BangPatterns, ScopedTypeVariables, FlexibleContexts #-}
 
 module Data.MutableIter.IOBuffer (
   IOBuffer
@@ -19,6 +19,7 @@
   ,foldl'
   ,castBuffer
   ,freeze
+  ,thaw
   ,hPut
   ,unsafeToForeignPtr
 )
@@ -27,7 +28,7 @@
 
 import Prelude hiding (length, take, drop, null, splitAt, dropWhile)
 
-import qualified Data.Vector.Storable as V
+import qualified Data.Vector.Generic as G
 import qualified Data.Iteratee as I
 import Control.Monad
 import Control.Monad.CatchIO
@@ -193,12 +194,27 @@
   return $ IOBuffer len po pb))
 
 -- |Safely convert an IOBuffer to a Vector.
--- TODO: finish this implementation, look at Vector docs.
-freeze :: (Storable el) => IOBuffer r el -> IO (V.Vector el)
-freeze (IOBuffer 0 _ _) = return V.empty
+freeze :: (Storable el, G.Vector v el, G.Vector v Int) =>
+  IOBuffer r el
+  -> IO (v el)
+freeze (IOBuffer 0 _ _) = return G.empty
 freeze buf = withBuf buf $ \l po pb -> do
+  len <- length buf
   off <- peek po
-  return undefined
+  let vIx = G.enumFromN 0 len
+  vRes <- G.forM vIx (\ix -> peekElemOff (pb `advancePtr` off) ix)
+  return vRes
+{-# INLINE freeze #-}
+
+-- |Safely convert a Vector to an IOBuffer
+thaw :: (Storable el, G.Vector v el) => v el -> IO (IOBuffer r el)
+thaw vec = do
+  offp <- newFp 0
+  bufp <- mallocForeignPtrArray (G.length vec)
+  withForeignPtr bufp $ \p ->
+    G.foldM' (\ix el -> pokeElemOff p ix el >> return (ix+1)) 0 vec
+  return $ createIOBuffer (G.length vec) offp bufp
+{-# INLINE thaw #-}
 
 -- |Write out the contents of the IOBuffer to a handle.  This operation
 -- drains the buffer.
