diff --git a/hw-prim.cabal b/hw-prim.cabal
--- a/hw-prim.cabal
+++ b/hw-prim.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hw-prim
-version:        0.6.2.17
+version:        0.6.2.18
 synopsis:       Primitive functions and data types
 description:    Primitive functions and data types.
 category:       Data
@@ -48,6 +48,7 @@
   exposed-modules:
       HaskellWorks.Data.AtIndex
       HaskellWorks.Data.ByteString
+      HaskellWorks.Data.ByteString.Builder
       HaskellWorks.Data.ByteString.Lazy
       HaskellWorks.Data.Char
       HaskellWorks.Data.Char.IsChar
diff --git a/src/HaskellWorks/Data/ByteString.hs b/src/HaskellWorks/Data/ByteString.hs
--- a/src/HaskellWorks/Data/ByteString.hs
+++ b/src/HaskellWorks/Data/ByteString.hs
@@ -12,15 +12,19 @@
   , hGetContentsChunkedBy
   ) where
 
-import Data.Semigroup ((<>))
+import Control.Monad.ST
+import Data.Semigroup   ((<>))
 import Data.Word
 
-import qualified Data.ByteString          as BS
-import qualified Data.ByteString.Internal as BSI
-import qualified Data.ByteString.Lazy     as LBS
-import qualified Data.Vector.Storable     as DVS
-import qualified System.IO                as IO
-import qualified System.IO.Unsafe         as IO
+import qualified Control.Monad.ST.Unsafe       as ST
+import qualified Data.ByteString               as BS
+import qualified Data.ByteString.Internal      as BSI
+import qualified Data.ByteString.Lazy          as LBS
+import qualified Data.ByteString.Lazy.Internal as LBSI
+import qualified Data.Vector.Storable          as DVS
+import qualified Data.Vector.Storable.Mutable  as DVSM
+import qualified System.IO                     as IO
+import qualified System.IO.Unsafe              as IO
 
 class ToByteString a where
   toByteString :: a -> BS.ByteString
@@ -49,6 +53,10 @@
     (fptr, start, offset) -> BSI.fromForeignPtr fptr start offset
   {-# INLINE toByteString #-}
 
+instance ToByteString [Word64] where
+  toByteString = toByteString . DVS.fromList
+  {-# INLINE toByteString #-}
+
 class ToByteStrings a where
   toByteStrings :: a -> [BS.ByteString]
 
@@ -78,6 +86,29 @@
 
 instance ToByteStrings (DVS.Vector Word64) where
   toByteStrings = (:[]) . toByteString
+  {-# INLINE toByteStrings #-}
+
+instance ToByteStrings [Word64] where
+  toByteStrings ws = toByteString <$> go ws
+    where go :: [Word64] -> [DVS.Vector Word64]
+          go us = DVS.createT (goST us)
+          goST :: [Word64] -> ST s [DVSM.MVector s Word64]
+          goST us = do
+            mv <- DVSM.new defaultChunkSize
+            (i, ts) <- writeWords 0 defaultChunkSize us mv
+            mvs <- ST.unsafeInterleaveST (goST ts)
+            if null ts
+              then return [DVSM.take i mv]
+              else return (DVSM.take i mv:mvs)
+          writeWords :: Int -> Int -> [Word64] -> DVSM.MVector s Word64 -> ST s (Int, [Word64])
+          writeWords i n us mv = if i < n
+            then case us of
+              t:ts -> do
+                DVSM.write mv i t
+                writeWords (i + 1) n ts mv
+              [] -> return (i, us)
+            else return (i, us)
+          defaultChunkSize = (LBSI.defaultChunkSize `div` 64) * 8
   {-# INLINE toByteStrings #-}
 
 instance ToByteStrings [DVS.Vector Word8] where
diff --git a/src/HaskellWorks/Data/ByteString/Builder.hs b/src/HaskellWorks/Data/ByteString/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/ByteString/Builder.hs
@@ -0,0 +1,21 @@
+module HaskellWorks.Data.ByteString.Builder
+  ( chainInterleaveIO
+  ) where
+
+import Data.Function
+import Data.Monoid   (Monoid (..))
+
+import qualified Data.ByteString      as BS
+import qualified Data.ByteString.Lazy as LBS
+import qualified System.IO.Unsafe     as IO
+
+chainInterleaveIO :: [IO LBS.ByteString] -> IO LBS.ByteString
+chainInterleaveIO iobs = LBS.fromChunks . ([] &) <$> go diobs
+  where diobs :: [IO ([BS.ByteString] -> [BS.ByteString])]
+        diobs = ((++) . LBS.toChunks <$>) <$> iobs
+        go :: [IO ([BS.ByteString] -> [BS.ByteString])] -> IO ([BS.ByteString] -> [BS.ByteString])
+        go (ma:mas) = do
+          a <- ma
+          as <- IO.unsafeInterleaveIO $ go mas
+          return (a . as)
+        go [] = return mempty
diff --git a/test/HaskellWorks/Data/ByteStringSpec.hs b/test/HaskellWorks/Data/ByteStringSpec.hs
--- a/test/HaskellWorks/Data/ByteStringSpec.hs
+++ b/test/HaskellWorks/Data/ByteStringSpec.hs
@@ -1,15 +1,17 @@
 module HaskellWorks.Data.ByteStringSpec where
 
 import Control.Monad
+import Data.Foldable
 import HaskellWorks.Hspec.Hedgehog
 import Hedgehog
 import Test.Hspec
 
-import qualified Data.ByteString              as BS
-import qualified Data.ByteString.Lazy         as LBS
-import qualified HaskellWorks.Data.ByteString as BS
-import qualified Hedgehog.Gen                 as G
-import qualified Hedgehog.Range               as R
+import qualified Data.ByteString               as BS
+import qualified Data.ByteString.Lazy          as LBS
+import qualified Data.ByteString.Lazy.Internal as LBSI
+import qualified HaskellWorks.Data.ByteString  as BS
+import qualified Hedgehog.Gen                  as G
+import qualified Hedgehog.Range                as R
 
 {-# ANN module ("HLint: Ignore Redundant do" :: String) #-}
 
@@ -45,4 +47,7 @@
     chunkSize <- forAll $ G.int (R.linear 1 4)
     forM_ (drop 1 (reverse (BS.rechunk chunkSize bss))) $ \bs -> do
       (BS.length bs) `mod` chunkSize === 0
+  it "rechunk creates correctly sized segments" $ requireProperty $ do
+    ws <- forAll $ G.list (R.linear 0 (LBSI.defaultChunkSize `div` 4)) (G.word64 R.constantBounded)
+    fold (BS.toByteStrings ws) === BS.toByteString ws
 
