@@ -45,6 +45,10 @@ module Data.Text.Encoding
4545 , encodeUtf16BE
4646 , encodeUtf32LE
4747 , encodeUtf32BE
48+
49+ -- * Generic encoding of Text
50+ , encodeStreamWithB
51+ , encodeTextWithB
4852 ) where
4953
5054import Control.Exception (evaluate, try)
@@ -56,6 +60,8 @@ import Control.Monad.ST (unsafeIOToST, unsafeSTToIO)
5660import Data.Bits ((.&.))
5761import Data.ByteString as B
5862import Data.ByteString.Internal as B
63+import Data.ByteString.Lazy.Builder.Internal as B
64+import Data.ByteString.Lazy.Builder.BasicEncoding.Internal as B
5965import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)
6066import Data.Text.Internal (Text(..), textP)
6167import Data.Text.UnsafeChar (ord, unsafeWrite)
@@ -278,3 +284,29 @@ encodeUtf32BE txt = E.unstream (E.restreamUtf32BE (F.stream txt))
278284foreign import ccall unsafe "_hs_text_decode_utf8" c_decode_utf8
279285 :: MutableByteArray# s -> Ptr CSize
280286 -> Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)
287+
288+-- | Encode all elements of a 'F.Stream' using a 'B.BoundedEncoding'.
289+{-# INLINE encodeStreamWithB #-}
290+encodeStreamWithB :: B.BoundedEncoding a -> F.Stream a -> B.Builder
291+encodeStreamWithB be =
292+ \(F.Stream next s0 _) -> B.builder $ step next s0
293+ where
294+ bound = B.sizeBound be
295+ step next s0 k (B.BufferRange op0 ope0) =
296+ go s0 op0
297+ where
298+ go s !op = case next s of
299+ F.Done -> k (B.BufferRange op ope0)
300+ F.Skip s' -> go s' op
301+ F.Yield x s'
302+ | op `plusPtr` bound <= ope0 -> B.runB be x op >>= go s'
303+ | otherwise ->
304+ return $ B.bufferFull bound op (step next s k)
305+
306+
307+-- |
308+-- | /Subject to fusion./
309+-- Encode all 'Char's of a 'T.Text' using a 'B.BoundedEncoding'.
310+{-# INLINE encodeTextWithB #-}
311+encodeTextWithB :: B.BoundedEncoding Char -> Text -> B.Builder
312+encodeTextWithB be = encodeStreamWithB be . F.stream