diff --git a/Data/Text.hs b/Data/Text.hs
--- a/Data/Text.hs
+++ b/Data/Text.hs
@@ -234,8 +234,8 @@
 -- $strict
 --
 -- This package provides both strict and lazy 'Text' types.  The
--- strict type is provided by the 'Data.Text' package, while the lazy
--- type is provided by the 'Data.Text.Lazy' package.  Internally, the
+-- strict type is provided by the "Data.Text" module, while the lazy
+-- type is provided by the "Data.Text.Lazy" module. Internally, the
 -- lazy @Text@ type consists of a list of strict chunks.
 --
 -- The strict 'Text' type requires that an entire string fit into
@@ -330,7 +330,7 @@
 instance NFData Text
 #endif
 
--- This instance preserves data abstraction at the cost of inefficiency.
+-- | This instance preserves data abstraction at the cost of inefficiency.
 -- We omit reflection services for the sake of data abstraction.
 --
 -- This instance was created by copying the behavior of Data.Set and
@@ -338,7 +338,7 @@
 -- submit improvements.
 --
 -- Original discussion is archived here:
-
+--
 --  "could we get a Data instance for Data.Text.Text?"
 --  http://groups.google.com/group/haskell-cafe/browse_thread/thread/b5bbb1b28a7e525d/0639d46852575b93
 
@@ -430,7 +430,7 @@
         A.copyI arr 0 arr1 off1 len1
         A.copyI arr len1 arr2 off2 len
         return arr
-{-# INLINE append #-}
+{-# NOINLINE append #-}
 
 {-# RULES
 "TEXT append -> fused" [~1] forall t1 t2.
diff --git a/Data/Text/Encoding.hs b/Data/Text/Encoding.hs
--- a/Data/Text/Encoding.hs
+++ b/Data/Text/Encoding.hs
@@ -74,8 +74,7 @@
 import Data.Bits ((.&.))
 import Data.Text.Internal.Unsafe.Char (ord)
 import qualified Data.ByteString.Builder as B
-import qualified Data.ByteString.Builder.Extra as B
-import qualified Data.ByteString.Builder.Internal as B hiding (empty)
+import qualified Data.ByteString.Builder.Internal as B hiding (empty, append)
 import qualified Data.ByteString.Builder.Prim as BP
 import qualified Data.ByteString.Builder.Prim.Internal as BP
 import qualified Data.Text.Internal.Encoding.Utf16 as U16
@@ -172,12 +171,16 @@
 -- a 'ByteString' that represents a possibly incomplete input (e.g. a
 -- packet from a network stream) that may not end on a UTF-8 boundary.
 --
--- The first element of the result is the maximal chunk of 'Text' that
--- can be decoded from the given input. The second is a function which
--- accepts another 'ByteString'. That string will be assumed to
--- directly follow the string that was passed as input to the original
--- function, and it will in turn be decoded.
+-- 1. The maximal prefix of 'Text' that could be decoded from the
+--    given input.
 --
+-- 2. The suffix of the 'ByteString' that could not be decoded due to
+--    insufficient input.
+--
+-- 3. A function that accepts another 'ByteString'.  That string will
+--    be assumed to directly follow the string that was passed as
+--    input to the original function, and it will in turn be decoded.
+--
 -- To help understand the use of these functions, consider the Unicode
 -- string @\"hi &#9731;\"@. If encoded as UTF-8, this becomes @\"hi
 -- \\xe2\\x98\\x83\"@; the final @\'&#9731;\'@ is encoded as 3 bytes.
@@ -189,15 +192,17 @@
 -- as we receive each one.
 --
 -- @
--- let 'Some' t0 f0 = 'streamDecodeUtf8' \"hi \\xe2\"
--- t0 == \"hi \" :: 'Text'
+-- ghci> let s0\@('Some' _ _ f0) = 'streamDecodeUtf8' \"hi \\xe2\"
+-- ghci> s0
+-- 'Some' \"hi \" \"\\xe2\" _
 -- @
 --
 -- We use the continuation @f0@ to decode our second packet.
 --
 -- @
--- let 'Some' t1 f1 = f0 \"\\x98\"
--- t1 == \"\"
+-- ghci> let s1\@('Some' _ _ f1) = f0 \"\\x98\"
+-- ghci> s1
+-- 'Some' \"\" \"\\xe2\\x98\"
 -- @
 --
 -- We could not give @f0@ enough input to decode anything, so it
@@ -205,8 +210,9 @@
 -- the last byte of input, it will make progress.
 --
 -- @
--- let 'Some' t2 f2 = f1 \"\\x83\"
--- t2 == \"&#9731;\"
+-- ghci> let s2\@('Some' _ _ f2) = f1 \"\\x83\"
+-- ghci> s2
+-- 'Some' \"\\x2603\" \"\" _
 -- @
 --
 -- If given invalid input, an exception will be thrown by the function
@@ -238,12 +244,13 @@
 -- | Decode, in a stream oriented way, a 'ByteString' containing UTF-8
 -- encoded text.
 streamDecodeUtf8With :: OnDecodeError -> ByteString -> Decoding
-streamDecodeUtf8With onErr = decodeChunk 0 0
+streamDecodeUtf8With onErr = decodeChunk B.empty 0 0
  where
   -- We create a slightly larger than necessary buffer to accommodate a
   -- potential surrogate pair started in the last buffer
-  decodeChunk :: CodePoint -> DecoderState -> ByteString -> Decoding
-  decodeChunk codepoint0 state0 bs@(PS fp off len) =
+  decodeChunk :: ByteString -> CodePoint -> DecoderState -> ByteString
+              -> Decoding
+  decodeChunk undecoded0 codepoint0 state0 bs@(PS fp off len) =
     runST $ (unsafeIOToST . decodeChunkToBuffer) =<< A.new (len+1)
    where
     decodeChunkToBuffer :: A.MArray s -> IO Decoding
@@ -281,8 +288,11 @@
                       return $! textP arr 0 (fromIntegral n)
                   lastPtr <- peek curPtrPtr
                   let left = lastPtr `minusPtr` curPtr
-                  return $ Some chunkText (B.drop left bs)
-                           (decodeChunk codepoint state)
+                      undecoded = case state of
+                        UTF8_ACCEPT -> B.empty
+                        _           -> B.append undecoded0 (B.drop left bs)
+                  return $ Some chunkText undecoded
+                           (decodeChunk undecoded codepoint state)
         in loop (ptr `plusPtr` off)
   desc = "Data.Text.Internal.Encoding.streamDecodeUtf8With: Invalid UTF-8 stream"
 
diff --git a/Data/Text/Internal.hs b/Data/Text/Internal.hs
--- a/Data/Text/Internal.hs
+++ b/Data/Text/Internal.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP, DeriveDataTypeable #-}
+{-# OPTIONS_HADDOCK not-home #-}
 
 -- |
 -- Module      : Data.Text.Internal
diff --git a/Data/Text/Internal/Builder.hs b/Data/Text/Internal/Builder.hs
--- a/Data/Text/Internal/Builder.hs
+++ b/Data/Text/Internal/Builder.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
+{-# OPTIONS_HADDOCK not-home #-}
 
 -----------------------------------------------------------------------------
 -- |
diff --git a/Data/Text/Internal/Fusion/Common.hs b/Data/Text/Internal/Fusion/Common.hs
--- a/Data/Text/Internal/Fusion/Common.hs
+++ b/Data/Text/Internal/Fusion/Common.hs
@@ -106,7 +106,7 @@
 
 import Prelude (Bool(..), Char, Eq(..), Int, Integral, Maybe(..),
                 Ord(..), Ordering(..), String, (.), ($), (+), (-), (*), (++),
-                (&&), fromIntegral, not, otherwise)
+                (&&), fromIntegral, otherwise)
 import qualified Data.List as L
 import qualified Prelude as P
 import Data.Bits (shiftL)
diff --git a/Data/Text/Internal/Lazy.hs b/Data/Text/Internal/Lazy.hs
--- a/Data/Text/Internal/Lazy.hs
+++ b/Data/Text/Internal/Lazy.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE BangPatterns, DeriveDataTypeable #-}
+{-# OPTIONS_HADDOCK not-home #-}
+
 -- |
 -- Module      : Data.Text.Internal.Lazy
 -- Copyright   : (c) 2009, 2010 Bryan O'Sullivan
diff --git a/Data/Text/Internal/Read.hs b/Data/Text/Internal/Read.hs
new file mode 100644
--- /dev/null
+++ b/Data/Text/Internal/Read.hs
@@ -0,0 +1,62 @@
+-- |
+-- Module      : Data.Text.Internal.Read
+-- Copyright   : (c) 2014 Bryan O'Sullivan
+--
+-- License     : BSD-style
+-- Maintainer  : bos@serpentine.com
+-- Stability   : experimental
+-- Portability : GHC
+--
+-- Common internal functiopns for reading textual data.
+module Data.Text.Internal.Read
+    (
+      IReader
+    , IParser(..)
+    , T(..)
+    , digitToInt
+    , hexDigitToInt
+    , perhaps
+    ) where
+
+import Control.Applicative (Applicative(..))
+import Control.Arrow (first)
+import Control.Monad (ap)
+import Data.Char (ord)
+
+type IReader t a = t -> Either String (a,t)
+
+newtype IParser t a = P {
+      runP :: IReader t a
+    }
+
+instance Functor (IParser t) where
+    fmap f m = P $ fmap (first f) . runP m
+
+instance Applicative (IParser t) where
+    pure a = P $ \t -> Right (a,t)
+    {-# INLINE pure #-}
+    (<*>) = ap
+
+instance Monad (IParser t) where
+    return = pure
+    m >>= k  = P $ \t -> case runP m t of
+                           Left err     -> Left err
+                           Right (a,t') -> runP (k a) t'
+    {-# INLINE (>>=) #-}
+    fail msg = P $ \_ -> Left msg
+
+data T = T !Integer !Int
+
+perhaps :: a -> IParser t a -> IParser t a
+perhaps def m = P $ \t -> case runP m t of
+                            Left _      -> Right (def,t)
+                            r@(Right _) -> r
+
+hexDigitToInt :: Char -> Int
+hexDigitToInt c
+    | c >= '0' && c <= '9' = ord c - ord '0'
+    | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
+    | otherwise            = ord c - (ord 'A' - 10)
+
+digitToInt :: Char -> Int
+digitToInt c = ord c - ord '0'
diff --git a/Data/Text/Internal/Unsafe.hs b/Data/Text/Internal/Unsafe.hs
--- a/Data/Text/Internal/Unsafe.hs
+++ b/Data/Text/Internal/Unsafe.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}
+{-# OPTIONS_HADDOCK not-home #-}
+
 -- |
 -- Module      : Data.Text.Internal.Unsafe
 -- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan
diff --git a/Data/Text/Lazy.hs b/Data/Text/Lazy.hs
--- a/Data/Text/Lazy.hs
+++ b/Data/Text/Lazy.hs
@@ -880,7 +880,7 @@
     | otherwise        = concat (rep 0)
     where rep !i | i >= n    = []
                  | otherwise = t : rep (i+1)
-{-# INLINE replicate #-}
+{-# INLINE [1] replicate #-}
 
 -- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the
 -- value of every element. Subject to fusion.
diff --git a/Data/Text/Lazy/Builder/Int.hs b/Data/Text/Lazy/Builder/Int.hs
--- a/Data/Text/Lazy/Builder/Int.hs
+++ b/Data/Text/Lazy/Builder/Int.hs
@@ -49,7 +49,7 @@
 #endif
 
 decimal :: Integral a => a -> Builder
-{-# SPECIALIZE decimal :: Int8 -> Builder #-}
+{-# RULES "decimal/Int8" decimal = boundedDecimal :: Int8 -> Builder #-}
 {-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}
 {-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}
 {-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}
@@ -61,6 +61,7 @@
 {-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}
 {-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
 decimal i = decimal' (<= -128) i
+{-# NOINLINE decimal #-}
 
 boundedDecimal :: (Integral a, Bounded a) => a -> Builder
 {-# SPECIALIZE boundedDecimal :: Int -> Builder #-}
@@ -169,6 +170,7 @@
   where
     go n | n < 16    = hexDigit n
          | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)
+{-# NOINLINE[0] hexadecimal #-}
 
 hexInteger :: Integer -> Builder
 hexInteger i
diff --git a/Data/Text/Lazy/Read.hs b/Data/Text/Lazy/Read.hs
--- a/Data/Text/Lazy/Read.hs
+++ b/Data/Text/Lazy/Read.hs
@@ -24,15 +24,17 @@
     ) where
 
 import Control.Monad (liftM)
-import Data.Char (isDigit, isHexDigit, ord)
+import Data.Char (isDigit, isHexDigit)
 import Data.Int (Int8, Int16, Int32, Int64)
 import Data.Ratio ((%))
+import Data.Text.Internal.Read
 import Data.Text.Lazy as T
 import Data.Word (Word, Word8, Word16, Word32, Word64)
 
 -- | Read some text.  If the read succeeds, return its value and the
 -- remaining text, otherwise an error message.
-type Reader a = Text -> Either String (a,Text)
+type Reader a = IReader Text a
+type Parser = IParser Text
 
 -- | Read a decimal integer.  The input must begin with at least one
 -- decimal digit, and is consumed until a non-digit or end of string
@@ -101,15 +103,6 @@
   where (h,t)  = T.span isHexDigit txt
         go n d = (n * 16 + fromIntegral (hexDigitToInt d))
 
-hexDigitToInt :: Char -> Int
-hexDigitToInt c
-    | c >= '0' && c <= '9' = ord c - ord '0'
-    | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
-    | otherwise            = ord c - (ord 'A' - 10)
-
-digitToInt :: Char -> Int
-digitToInt c = ord c - ord '0'
-
 -- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
 -- apply it to the result of applying the given reader.
 signed :: Num a => Reader a -> Reader a
@@ -169,30 +162,10 @@
   sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
   if sign == '+' then p else negate `liftM` p
 
-newtype Parser a = P {
-      runP :: Reader a
-    }
-
-instance Monad Parser where
-    return a = P $ \t -> Right (a,t)
-    {-# INLINE return #-}
-    m >>= k  = P $ \t -> case runP m t of
-                           Left err     -> Left err
-                           Right (a,t') -> runP (k a) t'
-    {-# INLINE (>>=) #-}
-    fail msg = P $ \_ -> Left msg
-
-perhaps :: a -> Parser a -> Parser a
-perhaps def m = P $ \t -> case runP m t of
-                            Left _      -> Right (def,t)
-                            r@(Right _) -> r
-
 char :: (Char -> Bool) -> Parser Char
 char p = P $ \t -> case T.uncons t of
                      Just (c,t') | p c -> Right (c,t')
                      _                 -> Left "character does not match"
-
-data T = T !Integer !Int
 
 floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
 {-# INLINE floaty #-}
diff --git a/Data/Text/Read.hs b/Data/Text/Read.hs
--- a/Data/Text/Read.hs
+++ b/Data/Text/Read.hs
@@ -24,16 +24,18 @@
     ) where
 
 import Control.Monad (liftM)
-import Data.Char (isDigit, isHexDigit, ord)
+import Data.Char (isDigit, isHexDigit)
 import Data.Int (Int8, Int16, Int32, Int64)
 import Data.Ratio ((%))
 import Data.Text as T
 import Data.Text.Internal.Private (span_)
+import Data.Text.Internal.Read
 import Data.Word (Word, Word8, Word16, Word32, Word64)
 
 -- | Read some text.  If the read succeeds, return its value and the
 -- remaining text, otherwise an error message.
-type Reader a = Text -> Either String (a,Text)
+type Reader a = IReader Text a
+type Parser a = IParser Text a
 
 -- | Read a decimal integer.  The input must begin with at least one
 -- decimal digit, and is consumed until a non-digit or end of string
@@ -111,15 +113,6 @@
   where (# h,t #)  = span_ isHexDigit txt
         go n d = (n * 16 + fromIntegral (hexDigitToInt d))
 
-hexDigitToInt :: Char -> Int
-hexDigitToInt c
-    | c >= '0' && c <= '9' = ord c - ord '0'
-    | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)
-    | otherwise            = ord c - (ord 'A' - 10)
-
-digitToInt :: Char -> Int
-digitToInt c = ord c - ord '0'
-
 -- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and
 -- apply it to the result of applying the given reader.
 signed :: Num a => Reader a -> Reader a
@@ -179,30 +172,10 @@
   sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
   if sign == '+' then p else negate `liftM` p
 
-newtype Parser a = P {
-      runP :: Reader a
-    }
-
-instance Monad Parser where
-    return a = P $ \t -> Right (a,t)
-    {-# INLINE return #-}
-    m >>= k  = P $ \t -> case runP m t of
-                           Left err     -> Left err
-                           Right (a,t') -> runP (k a) t'
-    {-# INLINE (>>=) #-}
-    fail msg = P $ \_ -> Left msg
-
-perhaps :: a -> Parser a -> Parser a
-perhaps def m = P $ \t -> case runP m t of
-                            Left _      -> Right (def,t)
-                            r@(Right _) -> r
-
 char :: (Char -> Bool) -> Parser Char
 char p = P $ \t -> case T.uncons t of
                      Just (c,t') | p c -> Right (c,t')
                      _                 -> Left "character does not match"
-
-data T = T !Integer !Int
 
 floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
 {-# INLINE floaty #-}
diff --git a/cbits/cbits.c b/cbits/cbits.c
--- a/cbits/cbits.c
+++ b/cbits/cbits.c
@@ -245,8 +245,21 @@
   while (srcend - src >= 4) {
     uint64_t w = *((uint64_t *) src);
 
-    if (w & 0xFF80FF80FF80FF80ULL)
+    if (w & 0xFF80FF80FF80FF80ULL) {
+      if (!(w & 0x000000000000FF80ULL)) {
+	*dest++ = w & 0xFFFF;
+	src++;
+	if (!(w & 0x00000000FF800000ULL)) {
+	  *dest++ = (w >> 16) & 0xFFFF;
+	  src++;
+	  if (!(w & 0x0000FF8000000000ULL)) {
+	    *dest++ = (w >> 32) & 0xFFFF;
+	    src++;
+	  }
+	}
+      }
       break;
+    }
     *dest++ = w & 0xFFFF;
     *dest++ = (w >> 16) & 0xFFFF;
     *dest++ = (w >> 32) & 0xFFFF;
diff --git a/tests/Tests/Properties.hs b/tests/Tests/Properties.hs
--- a/tests/Tests/Properties.hs
+++ b/tests/Tests/Properties.hs
@@ -1,6 +1,6 @@
 -- | General quicktest properties for the text library
 --
-{-# LANGUAGE BangPatterns, CPP, FlexibleInstances, OverloadedStrings,
+{-# LANGUAGE BangPatterns, FlexibleInstances, OverloadedStrings,
              ScopedTypeVariables, TypeSynonymInstances #-}
 {-# OPTIONS_GHC -fno-enable-rewrite-rules #-}
 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
@@ -9,13 +9,8 @@
       tests
     ) where
 
-import Test.QuickCheck hiding ((.&.))
-import Test.QuickCheck.Monadic
-import Text.Show.Functions ()
-
 import Control.Applicative ((<$>), (<*>))
 import Control.Arrow ((***), second)
-import Control.Exception (catch)
 import Data.Bits ((.&.))
 import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isUpper, ord)
 import Data.Int (Int8, Int16, Int32, Int64)
@@ -25,43 +20,41 @@
 import Data.Text.Foreign
 import Data.Text.Internal.Encoding.Utf8
 import Data.Text.Internal.Fusion.Size
+import Data.Text.Internal.Search (indices)
 import Data.Text.Lazy.Read as TL
 import Data.Text.Read as T
-import Data.Text.Internal.Search (indices)
 import Data.Word (Word, Word8, Word16, Word32, Word64)
 import Numeric (showHex)
+import Prelude hiding (replicate)
 import Test.Framework (Test, testGroup)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck hiding ((.&.))
+import Test.QuickCheck.Monadic
+import Tests.QuickCheckUtils
+import Tests.Utils
+import Text.Show.Functions ()
+import qualified Control.Exception as Exception
 import qualified Data.Bits as Bits (shiftL, shiftR)
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.List as L
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as E
+import qualified Data.Text.IO as T
 import qualified Data.Text.Internal.Fusion as S
 import qualified Data.Text.Internal.Fusion.Common as S
-import qualified Data.Text.IO as T
+import qualified Data.Text.Internal.Lazy.Fusion as SL
+import qualified Data.Text.Internal.Lazy.Search as S (indices)
+import qualified Data.Text.Internal.Unsafe.Shift as U
 import qualified Data.Text.Lazy as TL
 import qualified Data.Text.Lazy.Builder as TB
 import qualified Data.Text.Lazy.Builder.Int as TB
 import qualified Data.Text.Lazy.Builder.RealFloat as TB
 import qualified Data.Text.Lazy.Encoding as EL
-import qualified Data.Text.Internal.Lazy.Fusion as SL
 import qualified Data.Text.Lazy.IO as TL
-import qualified Data.Text.Internal.Lazy.Search as S (indices)
-import qualified Data.Text.Internal.Unsafe.Shift as U
 import qualified System.IO as IO
-
-import Tests.QuickCheckUtils
-import Tests.Utils
 import qualified Tests.SlowFunctions as Slow
 
-#if MIN_VERSION_base(4,6,0)
-import Prelude hiding (replicate)
-#else
-import Prelude hiding (catch, replicate)
-#endif
-
 t_pack_unpack       = (T.unpack . T.pack) `eq` id
 tl_pack_unpack      = (TL.unpack . TL.pack) `eq` id
 t_stream_unstream   = (S.unstream . S.stream) `eq` id
@@ -104,15 +97,23 @@
 t_utf8_incr  = do
         Positive n <- arbitrary
         forAll genUnicode $ recode n `eq` id
-    where recode n = T.concat . feedChunksOf n E.streamDecodeUtf8 . E.encodeUtf8
-          feedChunksOf :: Int -> (B.ByteString -> E.Decoding) -> B.ByteString
-                       -> [T.Text]
-          feedChunksOf n f bs
-            | B.null bs  = []
-            | otherwise  = let (a,b) = B.splitAt n bs
-                               E.Some t _ f' = f a
-                           in t : feedChunksOf n f' b
+    where recode n = T.concat . map fst . feedChunksOf n E.streamDecodeUtf8 .
+                     E.encodeUtf8
 
+feedChunksOf :: Int -> (B.ByteString -> E.Decoding) -> B.ByteString
+             -> [(T.Text, B.ByteString)]
+feedChunksOf n f bs
+  | B.null bs  = []
+  | otherwise  = let (x,y) = B.splitAt n bs
+                     E.Some t b f' = f x
+                 in (t,b) : feedChunksOf n f' y
+
+t_utf8_undecoded = forAll genUnicode $ \t ->
+  let b = E.encodeUtf8 t
+      ls = concatMap (leftover . E.encodeUtf8 . T.singleton) . T.unpack $ t
+      leftover = (++ [B.empty]) . init . tail . B.inits
+  in (map snd . feedChunksOf 1 E.streamDecodeUtf8) b == ls
+
 data Badness = Solo | Leading | Trailing
              deriving (Eq, Show)
 
@@ -130,7 +131,7 @@
     onErr <- genDecodeErr de
     monadicIO $ do
     l <- run $ let len = T.length (E.decodeUtf8With onErr bs)
-               in (len `seq` return (Right len)) `catch`
+               in (len `seq` return (Right len)) `Exception.catch`
                   (\(e::UnicodeException) -> return (Left e))
     assert $ case l of
       Left err -> length (show err) >= 0
@@ -839,6 +840,7 @@
       testProperty "t_utf8" t_utf8,
       testProperty "t_utf8'" t_utf8',
       testProperty "t_utf8_incr" t_utf8_incr,
+      testProperty "t_utf8_undecoded" t_utf8_undecoded,
       testProperty "tl_utf8" tl_utf8,
       testProperty "tl_utf8'" tl_utf8',
       testProperty "t_utf16LE" t_utf16LE,
diff --git a/tests/Tests/QuickCheckUtils.hs b/tests/Tests/QuickCheckUtils.hs
--- a/tests/Tests/QuickCheckUtils.hs
+++ b/tests/Tests/QuickCheckUtils.hs
@@ -7,6 +7,14 @@
 module Tests.QuickCheckUtils
     (
       genUnicode
+    , genUnicodeWith
+    , ascii
+    , plane0
+    , plane1
+    , plane2
+    , plane14
+    , planes
+
     , unsquare
     , smallArbitrary
 
@@ -34,25 +42,24 @@
 import Control.Exception (bracket)
 import Data.Bits ((.&.))
 import Data.Char (chr)
-import Data.Word (Word8, Word16)
 import Data.String (IsString, fromString)
 import Data.Text.Foreign (I16)
+import Data.Word (Word8, Word16)
 import Debug.Trace (trace)
 import System.Random (Random (..), RandomGen)
 import Test.QuickCheck hiding ((.&.))
 import Test.QuickCheck.Monadic (assert, monadicIO, run)
+import Tests.Utils
 import qualified Data.ByteString as B
 import qualified Data.Text as T
 import qualified Data.Text.Encoding.Error as T
 import qualified Data.Text.Internal.Fusion as TF
 import qualified Data.Text.Internal.Fusion.Common as TF
-import qualified Data.Text.Lazy as TL
-import qualified Data.Text.Internal.Lazy.Fusion as TLF
 import qualified Data.Text.Internal.Lazy as TL
+import qualified Data.Text.Internal.Lazy.Fusion as TLF
+import qualified Data.Text.Lazy as TL
 import qualified System.IO as IO
 
-import Tests.Utils
-
 instance Random I16 where
     randomR = integralRandomR
     random  = randomR (minBound,maxBound)
@@ -72,7 +79,11 @@
 #endif
 
 genUnicode :: IsString a => Gen a
-genUnicode = fmap fromString string where
+genUnicode = genUnicodeWith planes
+
+genUnicodeWith :: IsString a => [Gen Int] -> Gen a
+genUnicodeWith gens = fmap fromString string
+  where
     string = sized $ \n ->
         do k <- choose (0,n)
            sequence [ char | _ <- [1..k] ]
@@ -93,34 +104,45 @@
       where
         masked = c .&. 0xFFFF
 
-    ascii = choose (0,0x7F)
-    plane0 = choose (0xF0, 0xFFFF)
-    plane1 = oneof [ choose (0x10000, 0x10FFF)
-                   , choose (0x11000, 0x11FFF)
-                   , choose (0x12000, 0x12FFF)
-                   , choose (0x13000, 0x13FFF)
-                   , choose (0x1D000, 0x1DFFF)
-                   , choose (0x1F000, 0x1FFFF)
-                   ]
-    plane2 = oneof [ choose (0x20000, 0x20FFF)
-                   , choose (0x21000, 0x21FFF)
-                   , choose (0x22000, 0x22FFF)
-                   , choose (0x23000, 0x23FFF)
-                   , choose (0x24000, 0x24FFF)
-                   , choose (0x25000, 0x25FFF)
-                   , choose (0x26000, 0x26FFF)
-                   , choose (0x27000, 0x27FFF)
-                   , choose (0x28000, 0x28FFF)
-                   , choose (0x29000, 0x29FFF)
-                   , choose (0x2A000, 0x2AFFF)
-                   , choose (0x2B000, 0x2BFFF)
-                   , choose (0x2F000, 0x2FFFF)
-                   ]
-    plane14 = choose (0xE0000, 0xE0FFF)
-    planes = [ascii, plane0, plane1, plane2, plane14]
+    char = chr `fmap` excluding reserved (oneof gens)
 
-    char = chr `fmap` excluding reserved (oneof planes)
+ascii :: Gen Int
+ascii = choose (0,0x7F)
 
+plane0 :: Gen Int
+plane0 = choose (0xF0, 0xFFFF)
+
+plane1 :: Gen Int
+plane1 = oneof [ choose (0x10000, 0x10FFF)
+               , choose (0x11000, 0x11FFF)
+               , choose (0x12000, 0x12FFF)
+               , choose (0x13000, 0x13FFF)
+               , choose (0x1D000, 0x1DFFF)
+               , choose (0x1F000, 0x1FFFF)
+               ]
+
+plane2 :: Gen Int
+plane2 = oneof [ choose (0x20000, 0x20FFF)
+               , choose (0x21000, 0x21FFF)
+               , choose (0x22000, 0x22FFF)
+               , choose (0x23000, 0x23FFF)
+               , choose (0x24000, 0x24FFF)
+               , choose (0x25000, 0x25FFF)
+               , choose (0x26000, 0x26FFF)
+               , choose (0x27000, 0x27FFF)
+               , choose (0x28000, 0x28FFF)
+               , choose (0x29000, 0x29FFF)
+               , choose (0x2A000, 0x2AFFF)
+               , choose (0x2B000, 0x2BFFF)
+               , choose (0x2F000, 0x2FFFF)
+               ]
+
+plane14 :: Gen Int
+plane14 = choose (0xE0000, 0xE0FFF)
+
+planes :: [Gen Int]
+planes = [ascii, plane0, plane1, plane2, plane14]
+
 -- For tests that have O(n^2) running times or input sizes, resize
 -- their inputs to the square root of the originals.
 unsquare :: (Arbitrary a, Show a, Testable b) => (a -> b) -> Property
@@ -294,17 +316,6 @@
 windowsNewlineMode = IO.NewlineMode
     { IO.inputNL = IO.CRLF, IO.outputNL = IO.CRLF
     }
-
--- Newline and NewlineMode have standard Show instance from GHC 7 onwards
-#if __GLASGOW_HASKELL__ < 700
-instance Show IO.Newline where
-    show IO.CRLF = "CRLF"
-    show IO.LF   = "LF"
-
-instance Show IO.NewlineMode where
-    show (IO.NewlineMode i o) = "NewlineMode { inputNL = " ++ show i ++
-                                ", outputNL = " ++ show o ++ " }"
-# endif
 
 instance Arbitrary IO.NewlineMode where
     arbitrary = oneof . map return $
diff --git a/text.cabal b/text.cabal
--- a/text.cabal
+++ b/text.cabal
@@ -1,5 +1,5 @@
 name:           text
-version:        1.1.0.0
+version:        1.1.0.1
 homepage:       https://github.com/bos/text
 bug-reports:    https://github.com/bos/text/issues
 synopsis:       An efficient packed Unicode text type.
@@ -103,6 +103,7 @@
     Data.Text.Internal.Lazy.Fusion
     Data.Text.Internal.Lazy.Search
     Data.Text.Internal.Private
+    Data.Text.Internal.Read
     Data.Text.Internal.Search
     Data.Text.Internal.Unsafe
     Data.Text.Internal.Unsafe.Char
