diff --git a/iteratee.cabal b/iteratee.cabal
--- a/iteratee.cabal
+++ b/iteratee.cabal
@@ -1,5 +1,5 @@
 name:          iteratee
-version:       0.8.7.6
+version:       0.8.8.0
 synopsis:      Iteratee-based I/O
 description:
   The Iteratee monad provides strict, safe, and functional I/O. In addition
diff --git a/src/Data/Iteratee/Binary.hs b/src/Data/Iteratee/Binary.hs
--- a/src/Data/Iteratee/Binary.hs
+++ b/src/Data/Iteratee/Binary.hs
@@ -14,61 +14,67 @@
   ,endianRead3i
   ,endianRead4
   ,endianRead8
+  -- ** bytestring specializations
+  ,readWord16be_bs
+  ,readWord16le_bs
+  ,readWord32be_bs
+  ,readWord32le_bs
+  ,readWord64be_bs
+  ,readWord64le_bs
 )
 where
 
 import Data.Iteratee.Base
 import qualified Data.Iteratee.ListLike as I
 import qualified Data.ListLike as LL
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Unsafe as B
 import Data.Word
 import Data.Bits
 import Data.Int
 
-
 -- ------------------------------------------------------------------------
 -- Binary Random IO Iteratees
 
 -- Iteratees to read unsigned integers written in Big- or Little-endian ways
 
--- |Indicate endian-ness.
+-- | Indicate endian-ness.
 data Endian = MSB -- ^ Most Significant Byte is first (big-endian)
   | LSB           -- ^ Least Significan Byte is first (little-endian)
   deriving (Eq, Ord, Show, Enum)
 
 endianRead2
-  :: (Nullable s, LL.ListLike s Word8, Monad m) =>
-     Endian
-     -> Iteratee s m Word16
+  :: (Nullable s, LL.ListLike s Word8, Monad m)
+  => Endian
+  -> Iteratee s m Word16
 endianRead2 e = do
   c1 <- I.head
   c2 <- I.head
   case e of
-    MSB -> return $ (fromIntegral c1 `shiftL` 8) .|. fromIntegral c2
-    LSB -> return $ (fromIntegral c2 `shiftL` 8) .|. fromIntegral c1
+    MSB -> return $ word16 c1 c2
+    LSB -> return $ word16 c2 c1
+{-# INLINE endianRead2 #-}
 
 endianRead3
-  :: (Nullable s, LL.ListLike s Word8, Monad m) =>
-     Endian
-     -> Iteratee s m Word32
+  :: (Nullable s, LL.ListLike s Word8, Monad m)
+  => Endian
+  -> Iteratee s m Word32
 endianRead3 e = do
   c1 <- I.head
   c2 <- I.head
   c3 <- I.head
   case e of
-    MSB -> return $ (((fromIntegral c1
-                        `shiftL` 8) .|. fromIntegral c2)
-                        `shiftL` 8) .|. fromIntegral c3
-    LSB -> return $ (((fromIntegral c3
-                        `shiftL` 8) .|. fromIntegral c2)
-                        `shiftL` 8) .|. fromIntegral c1
+    MSB -> return $ word32 0 c1 c2 c3
+    LSB -> return $ word32 0 c3 c2 c1
+{-# INLINE endianRead3 #-}
 
 -- |Read 3 bytes in an endian manner.  If the first bit is set (negative),
 -- set the entire first byte so the Int32 will be negative as
 -- well.
 endianRead3i
-  :: (Nullable s, LL.ListLike s Word8, Monad m) =>
-     Endian
-     -> Iteratee s m Int32
+  :: (Nullable s, LL.ListLike s Word8, Monad m)
+  => Endian
+  -> Iteratee s m Int32
 endianRead3i e = do
   c1 <- I.head
   c2 <- I.head
@@ -83,57 +89,227 @@
      in return $ (((fromIntegral c3
                         `shiftL` 8) .|. fromIntegral c2)
                         `shiftL` 8) .|. fromIntegral m
+{-# INLINE endianRead3i #-}
 
 endianRead4
-  :: (Nullable s, LL.ListLike s Word8, Monad m) =>
-     Endian
-     -> Iteratee s m Word32
+  :: (Nullable s, LL.ListLike s Word8, Monad m)
+  => Endian
+  -> Iteratee s m Word32
 endianRead4 e = do
-  c1 <- I.head
-  c2 <- I.head
-  c3 <- I.head
-  c4 <- I.head
-  case e of
-    MSB -> return $
-               (((((fromIntegral c1
-                `shiftL` 8) .|. fromIntegral c2)
-                `shiftL` 8) .|. fromIntegral c3)
-                `shiftL` 8) .|. fromIntegral c4
-    LSB -> return $
-               (((((fromIntegral c4
-                `shiftL` 8) .|. fromIntegral c3)
-                `shiftL` 8) .|. fromIntegral c2)
-                `shiftL` 8) .|. fromIntegral c1
+  ln' <- I.chunkLength
+  case ln' of
+    Just ln | ln >= 4 -> do
+      ck <- I.getChunk
+      let t = LL.drop 4 ck
+          res = case e of
+                  MSB -> word32 (LL.index ck 0)
+                                (LL.index ck 1)
+                                (LL.index ck 2)
+                                (LL.index ck 3)
+                  LSB -> word32 (LL.index ck 3)
+                                (LL.index ck 2)
+                                (LL.index ck 1)
+                                (LL.index ck 0)
+      res `seq` idone res (I.Chunk t)
+    _ -> do
+      c1 <- I.head
+      c2 <- I.head
+      c3 <- I.head
+      c4 <- I.head
+      return $ case e of
+        MSB -> word32 c1 c2 c3 c4
+        LSB -> word32 c4 c3 c2 c1
+{-# INLINE [1] endianRead4 #-}
 
 endianRead8
-  :: (Nullable s, LL.ListLike s Word8, Monad m) =>
-     Endian
-     -> Iteratee s m Word64
+  :: (Nullable s, LL.ListLike s Word8, Monad m)
+  => Endian
+  -> Iteratee s m Word64
 endianRead8 e = do
-  c1 <- I.head
-  c2 <- I.head
-  c3 <- I.head
-  c4 <- I.head
-  c5 <- I.head
-  c6 <- I.head
-  c7 <- I.head
-  c8 <- I.head
-  case e of
-    MSB -> return $
-               (((((((((((((fromIntegral c1
-                `shiftL` 8) .|. fromIntegral c2)
-                `shiftL` 8) .|. fromIntegral c3)
-                `shiftL` 8) .|. fromIntegral c4)
-                `shiftL` 8) .|. fromIntegral c5)
-                `shiftL` 8) .|. fromIntegral c6)
-                `shiftL` 8) .|. fromIntegral c7)
-                `shiftL` 8) .|. fromIntegral c8
-    LSB -> return $
-               (((((((((((((fromIntegral c8
-                `shiftL` 8) .|. fromIntegral c7)
-                `shiftL` 8) .|. fromIntegral c6)
-                `shiftL` 8) .|. fromIntegral c5)
-                `shiftL` 8) .|. fromIntegral c4)
-                `shiftL` 8) .|. fromIntegral c3)
-                `shiftL` 8) .|. fromIntegral c2)
-                `shiftL` 8) .|. fromIntegral c1
+  ln' <- I.chunkLength
+  case ln' of
+    Just ln | ln >= 8 -> do
+      ck <- I.getChunk
+      let t = LL.drop 8 ck
+          res = case e of
+                  MSB -> word64 (LL.index ck 0)
+                                (LL.index ck 1)
+                                (LL.index ck 2)
+                                (LL.index ck 3)
+                                (LL.index ck 4)
+                                (LL.index ck 5)
+                                (LL.index ck 6)
+                                (LL.index ck 7)
+                  LSB -> word64 (LL.index ck 7)
+                                (LL.index ck 6)
+                                (LL.index ck 5)
+                                (LL.index ck 4)
+                                (LL.index ck 3)
+                                (LL.index ck 2)
+                                (LL.index ck 1)
+                                (LL.index ck 0)
+      res `seq` idone res (I.Chunk t)
+    _ -> do
+      c1 <- I.head
+      c2 <- I.head
+      c3 <- I.head
+      c4 <- I.head
+      c5 <- I.head
+      c6 <- I.head
+      c7 <- I.head
+      c8 <- I.head
+      return $ case e of
+        MSB -> word64 c1 c2 c3 c4 c5 c6 c7 c8
+        LSB -> word64 c8 c7 c6 c5 c4 c3 c2 c1
+{-# INLINE [1] endianRead8 #-}
+
+{-# RULES "iteratee: binary bytestring spec." endianRead4 = endianRead4BS #-}
+{-# RULES "iteratee: binary bytestring spec." endianRead8 = endianRead8BS #-}
+
+endianRead4BS :: Monad m => Endian -> Iteratee B.ByteString m Word32
+endianRead4BS MSB = readWord32be_bs
+endianRead4BS LSB = readWord32le_bs
+{-# INLINE endianRead4BS  #-}
+
+endianRead8BS :: Monad m => Endian -> Iteratee B.ByteString m Word64
+endianRead8BS MSB = readWord64be_bs
+endianRead8BS LSB = readWord64le_bs
+{-# INLINE endianRead8BS  #-}
+
+-- the 16-bit variant is only included for completeness; the
+-- polymorphic code is as fast as any specialization I've yet found
+-- in these cases.  (JWL, 2012-01-09)
+readWord16be_bs :: Monad m => Iteratee B.ByteString m Word16
+readWord16be_bs = endianRead2 MSB
+{-# INLINE readWord16be_bs  #-}
+
+readWord16le_bs :: Monad m => Iteratee B.ByteString m Word16
+readWord16le_bs = endianRead2 LSB
+{-# INLINE readWord16le_bs  #-}
+
+readWord32be_bs :: Monad m => Iteratee B.ByteString m Word32
+readWord32be_bs = do
+  ln' <- I.chunkLength
+  case ln' of
+    Just ln | ln >= 4 -> do
+      ck <- I.getChunk
+      let t = B.drop 4 ck
+          res = word32 (B.unsafeIndex ck 0)
+                       (B.unsafeIndex ck 1)
+                       (B.unsafeIndex ck 2)
+                       (B.unsafeIndex ck 3)
+      res `seq` idone res (I.Chunk t)
+    _ -> do
+      c1 <- I.head
+      c2 <- I.head
+      c3 <- I.head
+      c4 <- I.head
+      return $! word32 c1 c2 c3 c4
+{-# INLINE readWord32be_bs  #-}
+
+readWord32le_bs :: Monad m => Iteratee B.ByteString m Word32
+readWord32le_bs = do
+  ln' <- I.chunkLength
+  case ln' of
+    Just ln | ln >= 4 -> do
+      ck <- I.getChunk
+      let t = B.drop 4 ck
+          res = word32 (B.unsafeIndex ck 3)
+                       (B.unsafeIndex ck 2)
+                       (B.unsafeIndex ck 1)
+                       (B.unsafeIndex ck 0)
+      res `seq` idone res (I.Chunk t)
+    _ -> do
+      c1 <- I.head
+      c2 <- I.head
+      c3 <- I.head
+      c4 <- I.head
+      return $! word32 c4 c3 c2 c1
+{-# INLINE readWord32le_bs  #-}
+
+readWord64be_bs :: Monad m => Iteratee B.ByteString m Word64
+readWord64be_bs = do
+  ln' <- I.chunkLength
+  case ln' of
+    Just ln | ln >= 8 -> do
+      ck <- I.getChunk
+      let t = B.drop 8 ck
+          res = word64 (B.unsafeIndex ck 0)
+                       (B.unsafeIndex ck 1)
+                       (B.unsafeIndex ck 2)
+                       (B.unsafeIndex ck 3)
+                       (B.unsafeIndex ck 4)
+                       (B.unsafeIndex ck 5)
+                       (B.unsafeIndex ck 6)
+                       (B.unsafeIndex ck 7)
+      res `seq` idone res (I.Chunk t)
+    _ -> do
+      cs <- I.joinI $ I.take 8 I.stream2stream
+      if B.length cs == 8
+        then return $ word64 (B.unsafeIndex cs 0)
+                             (B.unsafeIndex cs 1)
+                             (B.unsafeIndex cs 2)
+                             (B.unsafeIndex cs 3)
+                             (B.unsafeIndex cs 4)
+                             (B.unsafeIndex cs 5)
+                             (B.unsafeIndex cs 6)
+                             (B.unsafeIndex cs 7)
+        else I.throwErr (toException EofException)
+{-# INLINE readWord64be_bs  #-}
+
+readWord64le_bs :: Monad m => Iteratee B.ByteString m Word64
+readWord64le_bs = do
+  ln' <- I.chunkLength
+  case ln' of
+    Just ln | ln >= 8 -> do
+      ck <- I.getChunk
+      let t = B.drop 8 ck
+          res = word64 (B.unsafeIndex ck 7)
+                       (B.unsafeIndex ck 6)
+                       (B.unsafeIndex ck 5)
+                       (B.unsafeIndex ck 4)
+                       (B.unsafeIndex ck 3)
+                       (B.unsafeIndex ck 2)
+                       (B.unsafeIndex ck 1)
+                       (B.unsafeIndex ck 0)
+      res `seq` idone res (I.Chunk t)
+    _ -> do
+      cs <- I.joinI $ I.take 8 I.stream2stream
+      if B.length cs == 8
+        then return $ word64 (B.unsafeIndex cs 7)
+                             (B.unsafeIndex cs 6)
+                             (B.unsafeIndex cs 5)
+                             (B.unsafeIndex cs 4)
+                             (B.unsafeIndex cs 3)
+                             (B.unsafeIndex cs 2)
+                             (B.unsafeIndex cs 1)
+                             (B.unsafeIndex cs 0)
+        else I.throwErr (toException EofException)
+{-# INLINE readWord64le_bs  #-}
+
+word16 :: Word8 -> Word8 -> Word16
+word16 c1 c2 = (fromIntegral c1 `shiftL`  8) .|.  fromIntegral c2
+{-# INLINE word16 #-}
+
+word32 :: Word8 -> Word8 -> Word8 -> Word8 -> Word32
+word32 c1 c2 c3 c4 =
+  (fromIntegral c1 `shiftL` 24) .|.
+  (fromIntegral c2 `shiftL` 16) .|.
+  (fromIntegral c3 `shiftL`  8) .|.
+   fromIntegral c4
+{-# INLINE word32 #-}
+
+word64
+  :: Word8 -> Word8 -> Word8 -> Word8 
+  -> Word8 -> Word8 -> Word8 -> Word8 
+  -> Word64
+word64 c1 c2 c3 c4 c5 c6 c7 c8 =
+  (fromIntegral c1 `shiftL` 56) .|.
+  (fromIntegral c2 `shiftL` 48) .|.
+  (fromIntegral c3 `shiftL` 40) .|.
+  (fromIntegral c4 `shiftL` 32) .|.
+  (fromIntegral c5 `shiftL` 24) .|.
+  (fromIntegral c6 `shiftL` 16) .|.
+  (fromIntegral c7 `shiftL`  8) .|.
+   fromIntegral c8
+{-# INLINE word64 #-}
diff --git a/src/Data/Iteratee/Exception.hs b/src/Data/Iteratee/Exception.hs
--- a/src/Data/Iteratee/Exception.hs
+++ b/src/Data/Iteratee/Exception.hs
@@ -40,6 +40,7 @@
 module Data.Iteratee.Exception (
   -- * Exception types
   IFException (..)
+  ,Exception (..)             -- from Control.Exception
   -- ** Enumerator exceptions
   ,EnumException (..)
   ,DivergentException (..)
diff --git a/src/Data/Iteratee/Iteratee.hs b/src/Data/Iteratee/Iteratee.hs
--- a/src/Data/Iteratee/Iteratee.hs
+++ b/src/Data/Iteratee/Iteratee.hs
@@ -245,6 +245,7 @@
       onCont k Nothing  = runIter (f k Nothing) od oc
       onCont k (Just e) = runIter (h k e)       od oc
   in runIter inner onDone onCont
+{-# INLINABLE eneeCheckIfDoneHandle #-}
 
 eneeCheckIfDonePass
   :: (Monad m, NullPoint elo)
@@ -254,7 +255,7 @@
      )
   -> Enumeratee elo eli m a
 eneeCheckIfDonePass f = eneeCheckIfDoneHandle (\k e -> f k (Just e)) f
-{-# INLINEABLE eneeCheckIfDonePass #-}
+{-# INLINABLE eneeCheckIfDonePass #-}
 
 eneeCheckIfDoneIgnore
   :: (Monad m, NullPoint elo)
@@ -292,6 +293,7 @@
 {-# INLINE mapChunksM #-}
 
 -- |Convert one stream into another, not necessarily in lockstep.
+-- 
 -- The transformer mapStream maps one element of the outer stream
 -- to one element of the nested stream.  The transformer below is more
 -- general: it may take several elements of the outer stream to produce
@@ -307,6 +309,7 @@
     check k (Just e) = throwRecoverableErr e (const identity) >> check k Nothing
     check k _ = isStreamFinished >>= maybe (step k) (idone (liftI k) . EOF . Just)
     step k = fi >>= eneeCheckIfDonePass check . k . Chunk
+{-# INLINABLE convStream #-}
 
 -- |The most general stream converter.  Given a function to produce iteratee
 -- transformers and an initial state, convert the stream using iteratees
@@ -345,6 +348,7 @@
       let i = f acc >>= \(acc', s') ->
                            (checkDone (check acc') . k $ Chunk s')
       in joinIM $ enumChunk str' i
+{-# INLINABLE unfoldConvStreamCheck #-}
 
 -- | Collapse a nested iteratee.  The inner iteratee is terminated by @EOF@.
 --   Errors are propagated through the result.
@@ -373,7 +377,8 @@
 
 -- ------------------------------------------------------------------------
 -- Enumerators
--- |Each enumerator takes an iteratee and returns an iteratee
+-- | Each enumerator takes an iteratee and returns an iteratee
+-- 
 -- an Enumerator is an iteratee transformer.
 -- The enumerator normally stops when the stream is terminated
 -- or when the iteratee moves to the done state, whichever comes first.
@@ -414,6 +419,7 @@
 
 
 -- |The composition of two enumerators: essentially the functional composition
+-- 
 -- It is convenient to flip the order of the arguments of the composition
 -- though: in e1 >>> e2, e1 is executed first
 
diff --git a/src/Data/Iteratee/ListLike.hs b/src/Data/Iteratee/ListLike.hs
--- a/src/Data/Iteratee/ListLike.hs
+++ b/src/Data/Iteratee/ListLike.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleContexts, BangPatterns, TupleSections #-}
+{-# LANGUAGE FlexibleContexts, BangPatterns, TupleSections, ScopedTypeVariables #-}
 
 -- |Monadic Iteratees:
 -- incremental input parsers, processors and transformers
@@ -58,6 +58,8 @@
   ,zip4
   ,zip5
   ,sequence_
+  ,countConsumed
+  ,greedy
   -- ** Monadic functions
   ,mapM_
   ,foldM
@@ -80,7 +82,6 @@
 import Control.Monad.Trans.Class
 import Data.Word (Word8)
 import qualified Data.ByteString as B
-import qualified Data.ByteString.Char8 as BC
 
 -- Useful combinators for implementing iteratees and enumerators
 
@@ -354,9 +355,7 @@
       | otherwise          = idone (k (Chunk s1)) (Chunk s2)
       where (s1, s2) = LL.splitAt n str
     step _n k stream       = idone (k stream) stream
-{-# SPECIALIZE take :: Monad m => Int -> Enumeratee [el] [el] m a #-}
-{-# SPECIALIZE take :: Monad m => Int -> Enumeratee B.ByteString B.ByteString m a #-}
-{-# SPECIALIZE take :: Monad m => Int -> Enumeratee BC.ByteString BC.ByteString m a #-}
+{-# INLINE take #-}
 
 -- |Read n elements from a stream and apply the given iteratee to the
 -- stream of the read elements. If the given iteratee accepted fewer
@@ -410,9 +409,7 @@
                 Left  (a,s')       -> od' (idone a s') (Chunk s2)
                 Right (k',e)       -> od' (icont k' e) (Chunk s2)
     step _ k stream       = idone (k stream) stream
-{-# SPECIALIZE takeUpTo :: Monad m => Int -> Enumeratee [el] [el] m a #-}
-{-# SPECIALIZE takeUpTo :: Monad m => Int -> Enumeratee B.ByteString B.ByteString m a #-}
-{-# INLINABLE takeUpTo #-}
+{-# INLINE takeUpTo #-}
 
 -- | Takes an element predicate and returns the (possibly empty)
 -- prefix of the stream. All characters
@@ -963,6 +960,28 @@
     shorter e@(EOF _) _         = e
     shorter _         e@(EOF _) = e
 
+-- |Transform an iteratee into one that keeps track of how much data it
+-- consumes.
+countConsumed :: forall a s el m n.
+                 (Monad m, LL.ListLike s el, Nullable s, Integral n) =>
+                 Iteratee s m a
+              -> Iteratee s m (a, n)
+countConsumed i = go 0 (const i) (Chunk empty)
+  where
+    go :: n -> (Stream s -> Iteratee s m a) -> Stream s
+       -> Iteratee s m (a, n)
+    go !n f str@(EOF _) = (, n) `liftM` f str
+    go !n f str@(Chunk c) = Iteratee rI
+      where
+        newLen = n + fromIntegral (LL.length c)
+        rI od oc = runIter (f str) onDone onCont
+          where
+            onDone a str'@(Chunk c') =
+                od (a, newLen - fromIntegral (LL.length c')) str'
+            onDone a str'@(EOF _) = od (a, n) str'
+            onCont f' mExc = oc (go newLen f') mExc
+{-# INLINE countConsumed #-}
+
 -- ------------------------------------------------------------------------
 -- Enumerators
 
@@ -982,6 +1001,49 @@
                        in runIter iter' idoneM on_cont
 {-# INLINE enumPureNChunk #-}
 
+-- | Convert an iteratee to a \"greedy\" version.
+--
+-- When a chunk is received, repeatedly run the input iteratee
+-- until the entire chunk is consumed, then the outputs
+-- are combined (via 'mconcat').
+--
+-- > > let l = [1..5::Int]
+-- > > run =<< enumPure1Chunk l (joinI (take 2 stream2list))
+-- > [1,2]
+-- > > run =<< enumPure1Chunk l (greedy $ joinI (I.take 2 stream2list))
+-- > [1,2,3,4,5]
+--
+-- Note that a greedy iteratee will consume the entire input chunk and force
+-- the next chunk before returning a value.  A portion of the second chunk may
+-- be consumed.
+-- 
+-- 'greedy' may be useful on the first parameter of 'convStream', e.g.
+-- 
+-- > convStream (greedy someIter)
+--
+-- to create more efficient converters.
+greedy ::
+ (Monad m, Functor m, LL.ListLike s el', Monoid a) =>
+  Iteratee s m a
+  -> Iteratee s m a
+greedy iter' = liftI (step [] iter')
+ where
+  step acc iter (Chunk str)
+    | LL.null str = liftI (step acc iter)
+    | otherwise   = joinIM $ do
+      i2 <- enumPure1Chunk str iter
+      result <- runIter i2 (\a s -> return $ Left (a,s))
+                           (\k e -> return $ Right (icont k e))
+      case result of
+        Left (a, Chunk resS)
+          | LL.null resS
+              || LL.length resS == LL.length str -> return $
+                         idone (mconcat $ reverse (a:acc)) (Chunk resS)
+        Left (a, stream) -> return $ step (a:acc) iter stream
+        Right i -> return $ fmap (mconcat . reverse . (:acc)) i
+  step acc iter stream = joinIM $
+    enumChunk stream (fmap (mconcat . reverse . (:acc)) iter)
+{-# INLINE greedy #-}
 
 -- ------------------------------------------------------------------------
 -- Monadic functions
diff --git a/tests/benchmarks.hs b/tests/benchmarks.hs
--- a/tests/benchmarks.hs
+++ b/tests/benchmarks.hs
@@ -7,6 +7,7 @@
 import Data.Iteratee
 import qualified Data.Iteratee.ListLike as I
 import qualified Data.Iteratee.Parallel as I
+import qualified Data.Iteratee.Binary as I
 import Data.Iteratee.ListLike (enumPureNChunk, stream2list, stream2stream)
 import Data.Word
 import Data.Monoid
@@ -35,6 +36,7 @@
 
 id1  name i = BDIter1 name id i
 idN  name i = BDIterN name 5 id i
+idNx name sz i = BDIterN name sz id i
 idNl name i = BDIterN name 1000 id i
 
 defTotalSize = 10000
@@ -78,6 +80,7 @@
 headsbench = makeGroup "heads" headsBenches
 dropbench = makeGroup "drop" $ drop0 : dropBenches
 zipbench = makeGroup "zip" $ zipBenches
+consbench = makeGroup "consumed" consBenches
 lengthbench = makeGroup "length" listBenches
 takebench = makeGroup "take" $ take0 : takeBenches
 takeUpTobench = makeGroup "takeUpTo" takeUpToBenches
@@ -93,6 +96,7 @@
 headsbenchbs = makeGroupBS "heads" headsBenches
 dropbenchbs = makeGroupBS "drop" dropBenches
 zipbenchbs = makeGroupBS "zip" zipBenches
+consbenchbs = makeGroupBS "consumed" consBenches
 lengthbenchbs = makeGroupBS "length" listBenches
 takebenchbs = makeGroupBS "take" takeBenches
 takeUpTobenchbs = makeGroupBS "takeUpTo" takeUpToBenches
@@ -102,11 +106,17 @@
 convbenchbs = makeGroupBS "convStream" convBenches
 miscbenchbs = makeGroupBS "other" miscBenches
 
+endian2benchbs = makeGroupBS "2" endian2Benches
+endian3benchbs = makeGroupBS "3" endian3Benches
+endian4benchbs = makeGroupBS "4" endian4Benches
+endian8benchbs = makeGroupBS "8" endian8Benches
+endianbenchbs = bgroup "endian" [endian2benchbs, endian3benchbs, endian4benchbs, endian8benchbs]
 
-allListBenches = bgroup "list" [listbench, streambench, breakbench, headsbench, dropbench, zipbench, lengthbench, takebench, takeUpTobench, groupbench, mapbench, foldbench, convbench, miscbench]
 
-allByteStringBenches = bgroup "bytestring" [listbenchbs, streambenchbs, breakbenchbs, headsbenchbs, dropbenchbs, zipbenchbs, lengthbenchbs, takebenchbs, takeUpTobenchbs, groupbenchbs, mapbenchbs, foldbenchbs, convbenchbs, miscbenchbs]
+allListBenches = bgroup "list" [listbench, streambench, breakbench, headsbench, dropbench, zipbench, lengthbench, takebench, takeUpTobench, groupbench, mapbench, foldbench, convbench, miscbench, consbench]
 
+allByteStringBenches = bgroup "bytestring" [listbenchbs, streambenchbs, breakbenchbs, headsbenchbs, dropbenchbs, zipbenchbs, lengthbenchbs, takebenchbs, takeUpTobenchbs, groupbenchbs, mapbenchbs, foldbenchbs, convbenchbs, endianbenchbs, miscbenchbs, consbenchbs]
+
 list0 = makeList "list one go" deepseq
 list1 = BDIter1 "stream2list one go" (flip deepseq ()) stream2list
 list2 = BDIterN "stream2list chunk by 4" 4 (flip deepseq ()) stream2list
@@ -158,7 +168,11 @@
 b_zip4 = idN "zip nonterminating" (I.zip I.length I.stream2stream >> identity)
 zipBenches = [b_zip0, b_zip1, b_zip2, b_zip3, b_zip4 ]
 
+consumed0 = idN "countConsumed" (I.countConsumed (I.foldl' (+) 0))
+consumed1 = idN "countConsumed baseline (`I.enumWith` I.length)" (I.foldl' (+) 0 `I.enumWith` I.length)
+consBenches = [consumed0, consumed1]
 
+
 l1 = makeList "length of list" Prelude.length
 l2 = id1 "length single iteratee" I.length
 l3 = idN "length chunked" I.length
@@ -209,3 +223,17 @@
 
 instance NFData a => NFData (Sum a) where
   rnf (Sum a) = rnf a
+
+endianRead2_1 = id1 "endianRead2 single" (I.endianRead2 MSB)
+endianRead2_2 = idNx "endianRead2 chunked" 1 (I.endianRead2 MSB)
+endianRead3_1 = id1 "endianRead3 single" (I.endianRead3 MSB)
+endianRead3_2 = idNx "endianRead3 chunked" 2 (I.endianRead3 MSB)
+endianRead4_1 = id1 "endianRead4 single" (I.endianRead4 MSB)
+endianRead4_2 = idNx "endianRead4 chunked" 2 (I.endianRead4 MSB)
+endianRead8_1 = id1 "endianRead8 single" (I.endianRead8 MSB)
+endianRead8_2 = idN "endianRead8 chunked" (I.endianRead8 MSB)
+endianRead8_3 = idNx "endianRead8 multiple chunked" 2 (I.endianRead8 MSB)
+endian2Benches = [endianRead2_1, endianRead2_2]
+endian3Benches = [endianRead3_1, endianRead3_2]
+endian4Benches = [endianRead4_1, endianRead4_2]
+endian8Benches = [endianRead8_1, endianRead8_2, endianRead8_3]
diff --git a/tests/testIteratee.hs b/tests/testIteratee.hs
--- a/tests/testIteratee.hs
+++ b/tests/testIteratee.hs
@@ -1,5 +1,5 @@
 {-# OPTIONS_GHC -O #-}
-{-# LANGUAGE NoMonomorphismRestriction #-}
+{-# LANGUAGE NoMonomorphismRestriction, ViewPatterns #-}
 
 import Prelude as P
 
@@ -242,6 +242,10 @@
    ==  runner1 (enumSpecial xs n (i >> stream2list))
  where types = (xs :: [Int], i :: I)
 
+prop_countConsumed (Positive (min (2^10) -> n)) (Positive (min (2^20) -> a)) (Positive k) =
+            runner1 (enumPureNChunk [1..] n iter) == (a, a)
+  where
+    iter = countConsumed . joinI $ (takeUpTo (a + k) ><> Iter.take a) Iter.last
 
 -- ---------------------------------------------
 -- Nested Iteratees
@@ -515,6 +519,7 @@
     testProperty "enumWith" prop_enumWith
     ,testProperty "enumWith remaining" prop_enumWith2
     ,testProperty "enumWith remaining 2" prop_enumWith3
+    ,testProperty "countConsumed" prop_countConsumed
     ]
   ,testGroup "Folds" [
     testProperty "foldl" prop_foldl
