diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 # hw-bits
-[![CircleCI](https://circleci.com/gh/haskell-works/hw-bits/tree/0-branch.svg?style=svg)](https://circleci.com/gh/haskell-works/hw-bits/tree/0-branch)
+[![CircleCI](https://circleci.com/gh/haskell-works/hw-bits.svg?style=svg)](https://circleci.com/gh/haskell-works/hw-bits)
 [![Travis](https://travis-ci.org/haskell-works/hw-bits.svg?branch=master)](https://travis-ci.org/haskell-works/hw-bits)
 
 Facilities for manipulating bits.
diff --git a/hw-bits.cabal b/hw-bits.cabal
--- a/hw-bits.cabal
+++ b/hw-bits.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hw-bits
-version:        0.7.0.3
+version:        0.7.0.4
 synopsis:       Bit manipulation
 description:    Please see README.md
 category:       Data, Bit
@@ -69,6 +69,7 @@
       HaskellWorks.Data.Bits.Types.Broadword
       HaskellWorks.Data.Bits.Types.Builtin
       HaskellWorks.Data.Bits.Word
+      HaskellWorks.Data.Bits.Writer.Storable
   other-modules:
       Paths_hw_bits
   default-language: Haskell2010
@@ -82,16 +83,19 @@
   build-depends:
       base        >= 4.8        && < 5
     , vector      >= 0.12       && < 0.13
-    , bytestring    >= 0.9        && < 0.11
-    , hspec         >= 2.4        && < 2.6
+    , bytestring              >= 0.9        && < 0.11
+    , hedgehog                >= 0.5        && < 0.7
+    , hspec                   >= 2.4        && < 3
+    , hw-hspec-hedgehog       >= 0.1.0.4    && < 0.2
     , hw-bits
-    , hw-prim       >= 0.4.0.3    && < 0.7
-    , QuickCheck    >= 2.10       && < 2.12
+    , hw-prim                 >= 0.4.0.3    && < 0.7
+    , QuickCheck              >= 2.10       && < 2.12
   other-modules:
       HaskellWorks.Data.Bits.BitReadSpec
       HaskellWorks.Data.Bits.BitWiseSpec
       HaskellWorks.Data.Bits.FromBitTextByteStringSpec
       HaskellWorks.Data.Bits.Log2Spec
+      HaskellWorks.Data.Bits.Writer.StorableSpec
   default-language: Haskell2010
 
 benchmark bench
diff --git a/src/HaskellWorks/Data/Bits/Writer/Storable.hs b/src/HaskellWorks/Data/Bits/Writer/Storable.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/Bits/Writer/Storable.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.Bits.Writer.Storable where
+
+import Control.Monad.ST
+import Data.Word
+import HaskellWorks.Data.Bits.BitWise
+
+import qualified Data.STRef                   as ST
+import qualified Data.Vector.Storable.Mutable as DVSM
+
+{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
+
+data Writer s = Writer
+  { vector   :: DVSM.MVector s Word64
+  , position :: ST.STRef s Int
+  }
+
+full :: Writer s -> ST s Bool
+full writer = do
+  p <- ST.readSTRef $ position writer
+  return $ p * 64 >= DVSM.length (vector writer)
+{-# INLINE full #-}
+
+newWriter :: Int -> ST s (Writer s)
+newWriter size = do
+  v <- DVSM.new size
+  p <- ST.newSTRef 0
+  return $ Writer v p
+{-# INLINE newWriter #-}
+
+unsafeWriteBit :: Writer s -> Word64 -> ST s ()
+unsafeWriteBit writer w = do
+  let v = vector   writer             -- vector
+  p <- ST.readSTRef $ position writer -- position
+  let i = p .>. 6                     -- index into vector
+  let o = p .&. 0x3f                  -- offset within a word
+  e <- DVSM.unsafeRead v i
+  DVSM.unsafeWrite v i (((w .&. 1) .<. fromIntegral o) .|. e)
+  ST.writeSTRef (position writer) (p + 1)
+{-# INLINE unsafeWriteBit #-}
+
+unsafeWriteLoBits :: Writer s -> Int -> Word64 -> ST s ()
+unsafeWriteLoBits writer c w = do
+  let u = w .&. ((1 .<. fromIntegral c) - 1)
+  let v = vector   writer             -- vector
+  p <- ST.readSTRef $ position writer -- position
+  let i = p .>. 6                     -- index into vector
+  let o = p .&. 0x3f                  -- offset within a word
+  lo <- DVSM.unsafeRead v i
+  DVSM.unsafeWrite v i $ lo .|. (u .<. fromIntegral o)
+  ST.writeSTRef (position writer) (p + c)
+{-# INLINE unsafeWriteLoBits #-}
+
+unsafeWriteBits :: Writer s -> Int -> Word64 -> ST s ()
+unsafeWriteBits writer c w = do
+  let u = w .&. ((1 .<. fromIntegral c) - 1)  -- masked word
+  let v = vector writer                       -- vector
+  p <- ST.readSTRef $ position writer         -- position
+  let i = p .>. 6                             -- index into vector for lo part
+  let j = i + 1                               -- index into vector for hi part
+  let o = p .&. 0x3f                          -- offset within a word
+  lo <- DVSM.unsafeRead v i
+  DVSM.unsafeWrite v i $ lo .|. (u .<. fromIntegral o)
+  hi <- DVSM.unsafeRead v j
+  DVSM.unsafeWrite v j $ hi .|. (u .>. fromIntegral (64 - o))
+  ST.writeSTRef (position writer) (p + c)
+{-# INLINE unsafeWriteBits #-}
+
+written :: Writer s -> ST s (DVSM.MVector s Word64)
+written writer = do
+  p <- ST.readSTRef $ position writer         -- position
+  return $ DVSM.take ((p + 63) `div` 64) (vector writer)
+{-# INLINE written #-}
diff --git a/test/HaskellWorks/Data/Bits/Writer/StorableSpec.hs b/test/HaskellWorks/Data/Bits/Writer/StorableSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/HaskellWorks/Data/Bits/Writer/StorableSpec.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE BinaryLiterals      #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module HaskellWorks.Data.Bits.Writer.StorableSpec where
+
+import Data.Word
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Data.Vector.Storable                   as DVS
+import qualified HaskellWorks.Data.Bits.Writer.Storable as WS
+
+{-# ANN module ("HLint: Ignore Redundant do" :: String) #-}
+
+spec :: Spec
+spec = describe "HaskellWorks.Data.Bits.Writer.StorableSpec" $ do
+  it "unsafeWriteBit" $ requireTest $ do
+    let v :: DVS.Vector Word64 = DVS.create $ do
+          mw <- WS.newWriter 10
+          WS.unsafeWriteBit mw 1
+          WS.unsafeWriteBit mw 0
+          WS.unsafeWriteBit mw 1
+          WS.unsafeWriteBit mw 1
+          WS.unsafeWriteBit mw 0
+          WS.unsafeWriteBit mw 0
+          WS.unsafeWriteBit mw 1
+          WS.unsafeWriteBit mw 1
+          WS.unsafeWriteBit mw 1
+          WS.unsafeWriteBit mw 0
+          WS.unsafeWriteBit mw 0
+          WS.unsafeWriteBit mw 0
+          WS.written mw
+
+    v === DVS.fromList [0b111001101]
+  it "unsafeWriteBits 1" $ requireTest $ do
+    let v :: DVS.Vector Word64 = DVS.create $ do
+          mw <- WS.newWriter 10
+          WS.unsafeWriteBits mw 1 1
+          WS.unsafeWriteBits mw 1 0
+          WS.unsafeWriteBits mw 1 1
+          WS.unsafeWriteBits mw 1 1
+          WS.unsafeWriteBits mw 1 0
+          WS.unsafeWriteBits mw 1 0
+          WS.unsafeWriteBits mw 1 1
+          WS.unsafeWriteBits mw 1 1
+          WS.unsafeWriteBits mw 1 1
+          WS.unsafeWriteBits mw 1 0
+          WS.unsafeWriteBits mw 1 0
+          WS.unsafeWriteBits mw 1 0
+          WS.written mw
+
+    v === DVS.fromList [0b111001101]
+  it "unsafeWriteBits 2" $ requireTest $ do
+    let v :: DVS.Vector Word64 = DVS.create $ do
+          mw <- WS.newWriter 10
+          WS.unsafeWriteBits mw 1 0b1
+          WS.unsafeWriteBits mw 1 0b0
+          WS.unsafeWriteBits mw 2 0b11
+          WS.unsafeWriteBits mw 2 0b00
+          WS.unsafeWriteBits mw 3 0b111
+          WS.unsafeWriteBits mw 3 0b000
+          WS.written mw
+    v === DVS.fromList [0b111001101]
+  it "unsafeWriteBits 2" $ requireTest $ do
+    let v :: DVS.Vector Word64 = DVS.create $ do
+          mw <- WS.newWriter 10
+          WS.unsafeWriteBits mw 1 0b1
+          WS.unsafeWriteBits mw 1 0b0
+          WS.unsafeWriteBits mw 2 0b11
+          WS.unsafeWriteBits mw 2 0b00
+          WS.unsafeWriteBits mw 3 0b111
+          WS.unsafeWriteBits mw 3 0b000
+          WS.unsafeWriteBits mw 4 0b1111
+          WS.unsafeWriteBits mw 4 0b0000
+          WS.unsafeWriteBits mw 5 0b11111
+          WS.unsafeWriteBits mw 5 0b00000
+          WS.unsafeWriteBits mw 6 0b111111
+          WS.unsafeWriteBits mw 6 0b000000
+          WS.unsafeWriteBits mw 7 0b1111111
+          WS.unsafeWriteBits mw 7 0b0000000
+          WS.unsafeWriteBits mw 8 0b11111111
+          WS.unsafeWriteBits mw 8 0b00000000
+          WS.unsafeWriteBits mw 9 0b111111111
+          WS.unsafeWriteBits mw 9 0b000000000
+          WS.written mw
+    v === DVS.fromList
+      [ 0b1111111100000001111111000000111111000001111100001111000111001101
+      , 0b0000000000000000000000000000000000000000000000011111111100000000
+      ]
+  it "unsafeWriteBits 2" $ requireTest $ do
+    let v :: DVS.Vector Word64 = DVS.create $ do
+          mw <- WS.newWriter 10
+          WS.unsafeWriteBits mw 9 0b111111111
+          WS.unsafeWriteBits mw 9 0b000000000
+          WS.unsafeWriteBits mw 8 0b11111111
+          WS.unsafeWriteBits mw 8 0b00000000
+          WS.unsafeWriteBits mw 7 0b1111111
+          WS.unsafeWriteBits mw 7 0b0000000
+          WS.unsafeWriteBits mw 6 0b111111
+          WS.unsafeWriteBits mw 6 0b000000
+          WS.unsafeWriteBits mw 5 0b11111
+          WS.unsafeWriteBits mw 5 0b00000
+          WS.unsafeWriteBits mw 4 0b1111
+          WS.unsafeWriteBits mw 4 0b0000
+          WS.unsafeWriteBits mw 3 0b111
+          WS.unsafeWriteBits mw 3 0b000
+          WS.unsafeWriteBits mw 2 0b11
+          WS.unsafeWriteBits mw 2 0b00
+          WS.unsafeWriteBits mw 1 0b1
+          WS.unsafeWriteBits mw 1 0b0
+          WS.written mw
+    v === DVS.fromList
+      [ 0b1111000000111111000000011111110000000011111111000000000111111111
+      , 0b0000000000000000000000000000000000000001001100011100001111000001
+      ]
