diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,8 +3,7 @@
 winery is a serialisation library for Haskell. It tries to achieve two
 goals: compact representation and perpetual inspectability.
 
-The `binary` library provides a compact representation, but there is no way to
-inspect the serialised value without the original instance.
+The standard `binary` library has no way to inspect the serialised value without the original instance.
 
 There's `serialise`, which is an alternative library based on CBOR. Every value has to be accompanied with tags, so it tends to be redundant for arrays of small values. Encoding records with field names is also redudant.
 
@@ -114,3 +113,31 @@
 , foo: Just 42
 }
 ```
+
+## Benchmark
+
+```haskell
+data TestRec = TestRec
+  { id_ :: !Int
+  , first_name :: !Text
+  , last_name :: !Text
+  , email :: !Text
+  , gender :: !Gender
+  , num :: !Int
+  , latitude :: !Double
+  , longitude :: !Double
+  } deriving (Show, Generic)
+```
+
+(De)serialisation of the datatype above using generic instances:
+
+```
+serialise/winery                         mean 658.6 μs  ( +- 45.04 μs  )
+serialise/binary                         mean 1.056 ms  ( +- 58.95 μs  )
+serialise/serialise                      mean 258.8 μs  ( +- 5.654 μs  )
+deserialise/winery                       mean 706.4 μs  ( +- 52.41 μs  )
+deserialise/binary                       mean 1.393 ms  ( +- 56.71 μs  )
+deserialise/serialise                    mean 765.8 μs  ( +- 30.26 μs  )
+```
+
+Not bad, considering that binary and serialise don't encode field names.
diff --git a/benchmarks/bench.hs b/benchmarks/bench.hs
--- a/benchmarks/bench.hs
+++ b/benchmarks/bench.hs
@@ -46,7 +46,7 @@
   winery <- B.readFile "benchmarks/data.winery"
   binary <- B.readFile "benchmarks/data.binary"
   cbor <- B.readFile "benchmarks/data.cbor"
-  Right (values :: [TestRec]) <- return $ deserialise winery
+  values :: [TestRec] <- return $ B.decode $ BL.fromStrict binary
   defaultMain
     [ bgroup "serialise"
       [ bench "winery" $ nf serialise values
diff --git a/src/Data/Winery.hs b/src/Data/Winery.hs
--- a/src/Data/Winery.hs
+++ b/src/Data/Winery.hs
@@ -12,6 +12,7 @@
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE StandaloneDeriving #-}
 module Data.Winery
   ( Schema(..)
   , Serialise(..)
@@ -59,7 +60,7 @@
 import Control.Monad.Trans.Cont
 import Control.Monad.Reader
 import qualified Data.ByteString as B
-import qualified Data.ByteString.FastBuilder as BB
+import qualified Data.Winery.Internal.Builder as BB
 import Data.Bits
 import Data.Dynamic
 import Data.Functor.Compose
@@ -216,8 +217,9 @@
 
 -- | Serialise a value along with its schema.
 serialise :: Serialise a => a -> B.ByteString
-serialise a = BB.toStrictByteString $ mappend (BB.word8 currentSchemaVersion)
-  $ encodingBuilder $ toEncoding (schema [a], a)
+serialise a = BB.toByteString $ mappend (BB.word8 currentSchemaVersion)
+  $ toEncoding (schema [a], a)
+{-# INLINE serialise #-}
 
 -- | Deserialise a 'serialise'd 'B.Bytestring'.
 deserialise :: Serialise a => B.ByteString -> Either StrategyError a
@@ -232,7 +234,7 @@
 
 -- | Serialise a value without its schema.
 serialiseOnly :: Serialise a => a -> B.ByteString
-serialiseOnly = BB.toStrictByteString . encodingBuilder . toEncoding
+serialiseOnly = BB.toByteString . toEncoding
 {-# INLINE serialiseOnly #-}
 
 substSchema :: Serialise a => Proxy a -> [TypeRep] -> Schema
@@ -298,8 +300,8 @@
 
 instance Serialise Bool where
   schemaVia _ _ = SBool
-  toEncoding False = Encoding 1 (BB.word8 0)
-  toEncoding True = Encoding 1 (BB.word8 1)
+  toEncoding False = BB.word8 0
+  toEncoding True = BB.word8 1
   deserialiser = Deserialiser $ Plan $ \case
     SBool -> pure $ (/=0) <$> evalContT getWord8
     s -> unexpectedSchema "Serialise Bool" s
@@ -307,7 +309,7 @@
 
 instance Serialise Word8 where
   schemaVia _ _ = SWord8
-  toEncoding x = Encoding 1 (BB.word8 x)
+  toEncoding = BB.word8
   deserialiser = Deserialiser $ Plan $ \case
     SWord8 -> pure $ evalContT getWord8
     s -> unexpectedSchema "Serialise Word8" s
@@ -315,7 +317,7 @@
 
 instance Serialise Word16 where
   schemaVia _ _ = SWord16
-  toEncoding x = Encoding 2 (BB.word16BE x)
+  toEncoding = BB.word16
   deserialiser = Deserialiser $ Plan $ \case
     SWord16 -> pure $ evalContT $ do
       a <- getWord8
@@ -326,7 +328,7 @@
 
 instance Serialise Word32 where
   schemaVia _ _ = SWord32
-  toEncoding x = Encoding 4 (BB.word32BE x)
+  toEncoding = BB.word32
   deserialiser = Deserialiser $ Plan $ \case
     SWord32 -> pure word32be
     s -> unexpectedSchema "Serialise Word32" s
@@ -334,7 +336,7 @@
 
 instance Serialise Word64 where
   schemaVia _ _ = SWord64
-  toEncoding x = Encoding 8 (BB.word64BE x)
+  toEncoding = BB.word64
   deserialiser = Deserialiser $ Plan $ \case
     SWord64 -> pure word64be
     s -> unexpectedSchema "Serialise Word64" s
@@ -342,7 +344,7 @@
 
 instance Serialise Word where
   schemaVia _ _ = SWord64
-  toEncoding x = Encoding 8 $ BB.word64BE $ fromIntegral x
+  toEncoding = BB.word64 . fromIntegral
   deserialiser = Deserialiser $ Plan $ \case
     SWord64 -> pure $ fromIntegral <$> word64be
     s -> unexpectedSchema "Serialise Word" s
@@ -350,7 +352,7 @@
 
 instance Serialise Int8 where
   schemaVia _ _ = SInt8
-  toEncoding x = Encoding 1 (BB.int8 x)
+  toEncoding = BB.word8 . fromIntegral
   deserialiser = Deserialiser $ Plan $ \case
     SInt8 -> pure $ fromIntegral <$> evalContT getWord8
     s -> unexpectedSchema "Serialise Int8" s
@@ -358,7 +360,7 @@
 
 instance Serialise Int16 where
   schemaVia _ _ = SInt16
-  toEncoding x = Encoding 2 (BB.int16BE x)
+  toEncoding = BB.word16 . fromIntegral
   deserialiser = Deserialiser $ Plan $ \case
     SInt16 -> pure $ fromIntegral <$> word16be
     s -> unexpectedSchema "Serialise Int16" s
@@ -366,7 +368,7 @@
 
 instance Serialise Int32 where
   schemaVia _ _ = SInt32
-  toEncoding x = Encoding 4 (BB.int32BE x)
+  toEncoding = BB.word32 . fromIntegral
   deserialiser = Deserialiser $ Plan $ \case
     SInt32 -> pure $ fromIntegral <$> word32be
     s -> unexpectedSchema "Serialise Int32" s
@@ -374,7 +376,7 @@
 
 instance Serialise Int64 where
   schemaVia _ _ = SInt64
-  toEncoding x = Encoding 8 (BB.int64BE x)
+  toEncoding = BB.word64 . fromIntegral
   deserialiser = Deserialiser $ Plan $ \case
     SInt64 -> pure $ fromIntegral <$> word64be
     s -> unexpectedSchema "Serialise Int64" s
@@ -389,7 +391,7 @@
 
 instance Serialise Float where
   schemaVia _ _ = SFloat
-  toEncoding x = Encoding 4 $ BB.word32BE $ unsafeCoerce x
+  toEncoding = BB.word32 . unsafeCoerce
   deserialiser = Deserialiser $ Plan $ \case
     SFloat -> pure $ unsafeCoerce <$> word32be
     s -> unexpectedSchema "Serialise Float" s
@@ -397,7 +399,7 @@
 
 instance Serialise Double where
   schemaVia _ _ = SDouble
-  toEncoding x = Encoding 8 $ BB.word64BE $ unsafeCoerce x
+  toEncoding = BB.word64 . unsafeCoerce
   deserialiser = Deserialiser $ Plan $ \case
     SDouble -> pure $ unsafeCoerce <$> word64be
     s -> unexpectedSchema "Serialise Double" s
@@ -452,7 +454,7 @@
 
 instance Serialise B.ByteString where
   schemaVia _ _ = SBytes
-  toEncoding bs = Encoding (B.length bs) (BB.byteString bs)
+  toEncoding = BB.bytes
   deserialiser = Deserialiser $ Plan $ \case
     SBytes -> pure id
     s -> unexpectedSchema "Serialise ByteString" s
@@ -463,7 +465,7 @@
     Just s -> SArray (VarInt s) (substSchema (Proxy :: Proxy a) ts)
   toEncoding xs = case constantSize (Proxy :: Proxy a) of
     Nothing -> encodeVarInt (length xs)
-      <> encodeMulti (map toEncoding xs)
+      <> encodeMulti (\r -> foldr (encodeItem . toEncoding) r xs)
     Just _ -> encodeVarInt (length xs) <> foldMap toEncoding xs
   deserialiser = extractListWith deserialiser
 
@@ -528,12 +530,6 @@
   toEncoding = toEncoding . toList
   deserialiser = Seq.fromList <$> deserialiser
 
-instance Serialise a => Serialise (Identity a) where
-  schemaVia _ = schemaVia (Proxy :: Proxy a)
-  toEncoding = toEncoding . runIdentity
-  deserialiser = Identity <$> deserialiser
-  constantSize _ = constantSize (Proxy :: Proxy a)
-
 -- | Extract a field of a record.
 extractField :: Serialise a => T.Text -> Deserialiser a
 extractField = extractFieldWith deserialiser
@@ -571,7 +567,7 @@
       sa = substSchema (Proxy :: Proxy a) ts
       sb = substSchema (Proxy :: Proxy b) ts
   toEncoding (a, b) = case constantSize (Proxy :: Proxy (a, b)) of
-    Nothing -> encodeMulti [toEncoding a, toEncoding b]
+    Nothing -> encodeMulti (encodeItem (toEncoding a) . encodeItem (toEncoding b))
     Just _ -> toEncoding a <> toEncoding b
   deserialiser = Deserialiser $ Plan $ \case
     SProduct [sa, sb] -> do
@@ -597,7 +593,7 @@
       sb = substSchema (Proxy :: Proxy b) ts
       sc = substSchema (Proxy :: Proxy c) ts
   toEncoding (a, b, c) = case constantSize (Proxy :: Proxy (a, b, c)) of
-    Nothing -> encodeMulti [toEncoding a, toEncoding b, toEncoding c]
+    Nothing -> encodeMulti $ encodeItem (toEncoding a) . encodeItem (toEncoding b) . encodeItem (toEncoding c)
     Just _ -> toEncoding a <> toEncoding b <> toEncoding c
   deserialiser = Deserialiser $ Plan $ \case
     SProduct [sa, sb, sc] -> do
@@ -627,7 +623,7 @@
       sc = substSchema (Proxy :: Proxy c) ts
       sd = substSchema (Proxy :: Proxy d) ts
   toEncoding (a, b, c, d) = case constantSize (Proxy :: Proxy (a, b, c)) of
-    Nothing -> encodeMulti [toEncoding a, toEncoding b, toEncoding c, toEncoding d]
+    Nothing -> encodeMulti $ encodeItem (toEncoding a) . encodeItem (toEncoding b) . encodeItem (toEncoding c) . encodeItem (toEncoding d)
     Just _ -> toEncoding a <> toEncoding b <> toEncoding c <> toEncoding d
   deserialiser = Deserialiser $ Plan $ \case
     SProduct [sa, sb, sc, sd] -> do
@@ -653,8 +649,8 @@
 instance (Serialise a, Serialise b) => Serialise (Either a b) where
   schemaVia _ ts = SVariant [("Left", [substSchema (Proxy :: Proxy a) ts])
     , ("Right", [substSchema (Proxy :: Proxy b) ts])]
-  toEncoding (Left a) = Encoding 1 (BB.word8 0) <> toEncoding a
-  toEncoding (Right b) = Encoding 1 (BB.word8 1) <> toEncoding b
+  toEncoding (Left a) = BB.word8 0 <> toEncoding a
+  toEncoding (Right b) = BB.word8 1 <> toEncoding b
   deserialiser = Deserialiser $ Plan $ \case
     SVariant [(_, [sa]), (_, [sb])] -> do
       getA <- unwrapDeserialiser deserialiser sa
@@ -726,16 +722,17 @@
   where
     rep = "gdeserialiserRecord :: Deserialiser "
       <> viaShow (typeRep (Proxy :: Proxy a))
+{-# INLINE gdeserialiserRecord #-}
 
 class GEncodeRecord f where
-  recordEncoder :: f x -> [Encoding]
+  recordEncoder :: f x -> EncodingMulti -> EncodingMulti
 
 instance (GEncodeRecord f, GEncodeRecord g) => GEncodeRecord (f :*: g) where
-  recordEncoder (f :*: g) = recordEncoder f ++ recordEncoder g
+  recordEncoder (f :*: g) = recordEncoder f . recordEncoder g
   {-# INLINE recordEncoder #-}
 
 instance Serialise a => GEncodeRecord (S1 c (K1 i a)) where
-  recordEncoder (M1 (K1 a)) = pure $! toEncoding a
+  recordEncoder (M1 (K1 a)) = encodeItem (toEncoding a)
   {-# INLINE recordEncoder #-}
 
 instance GEncodeRecord f => GEncodeRecord (C1 c f) where
@@ -774,17 +771,17 @@
 
 class GSerialiseProduct f where
   productSchema :: proxy f -> [TypeRep] -> [Schema]
-  productEncoder :: f x -> [Encoding]
+  productEncoder :: f x -> EncodingMulti -> EncodingMulti
   productDecoder :: TransFusion (FieldDecoder ()) Decoder (Decoder (f x))
 
 instance GSerialiseProduct U1 where
   productSchema _ _ = []
-  productEncoder _ = []
+  productEncoder _ = id
   productDecoder = pure (pure U1)
 
 instance (Serialise a) => GSerialiseProduct (K1 i a) where
   productSchema _ ts = [substSchema (Proxy :: Proxy a) ts]
-  productEncoder (K1 a) = [toEncoding a]
+  productEncoder (K1 a) = encodeItem (toEncoding a)
   productDecoder = TransFusion $ \k -> fmap (fmap K1) $ k $ FieldDecoder () Nothing (getDeserialiser deserialiser)
 
 instance GSerialiseProduct f => GSerialiseProduct (M1 i c f) where
@@ -794,7 +791,7 @@
 
 instance (GSerialiseProduct f, GSerialiseProduct g) => GSerialiseProduct (f :*: g) where
   productSchema _ ts = productSchema (Proxy :: Proxy f) ts ++ productSchema (Proxy :: Proxy g) ts
-  productEncoder (f :*: g) = productEncoder f ++ productEncoder g
+  productEncoder (f :*: g) = productEncoder f . productEncoder g
   productDecoder = liftA2 (:*:) <$> productDecoder <*> productDecoder
 
 deserialiserProduct' :: GSerialiseProduct f => [Schema] -> Strategy (Decoder (f x))
@@ -870,3 +867,7 @@
   variantSchema _ ts = variantSchema (Proxy :: Proxy f) ts
   variantEncoder i (M1 a) = variantEncoder i a
   variantDecoder = fmap (fmap (fmap (fmap M1))) <$> variantDecoder
+
+instance Serialise Ordering
+deriving instance Serialise a => Serialise (Identity a)
+deriving instance (Serialise a, Typeable b) => Serialise (Const a (b :: *))
diff --git a/src/Data/Winery/Internal.hs b/src/Data/Winery/Internal.hs
--- a/src/Data/Winery/Internal.hs
+++ b/src/Data/Winery/Internal.hs
@@ -8,8 +8,10 @@
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TypeFamilies #-}
 module Data.Winery.Internal
-  ( Encoding(..)
+  ( Encoding
+  , EncodingMulti
   , encodeMulti
+  , encodeItem
   , encodeVarInt
   , Decoder
   , decodeAt
@@ -35,10 +37,9 @@
 import Control.Monad.Fix
 import Control.Monad.ST
 import Control.Monad.Trans.Cont
-import Data.ByteString.FastBuilder
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Unsafe as B
-import qualified Data.ByteString.FastBuilder as BB
+import Data.Winery.Internal.Builder
 import Data.Bits
 import Data.Dynamic
 import Data.Monoid
@@ -48,16 +49,6 @@
 import qualified Data.Vector.Unboxed.Mutable as UM
 import Data.Word
 
-data Encoding = Encoding
-  { encodingLength :: !Int, encodingBuilder :: !Builder }
-
-instance Monoid Encoding where
-  mempty = Encoding 0 mempty
-  mappend (Encoding m a) (Encoding n b) = Encoding (m + n) (mappend a b)
-
-rebuildEncoding :: Encoding -> Encoding
-rebuildEncoding (Encoding l b) = Encoding l (BB.rebuild b)
-
 type Decoder = (->) B.ByteString
 
 decodeAt :: (Int, Int) -> Decoder a -> Decoder a
@@ -67,17 +58,18 @@
 encodeVarInt n
   | n < 0 = case negate n of
     n'
-      | n' < 0x40 -> e1 (fromIntegral n' `setBit` 6)
-      | otherwise -> go (e1 (0xc0 .|. fromIntegral n')) (shiftR n' 6)
-  | n < 0x40 = e1 (fromIntegral n)
-  | otherwise = go (e1 (fromIntegral n `setBit` 7 `clearBit` 6)) (shiftR n 6)
-  where
-  e1 = Encoding 1 . BB.word8
-  go !acc m
-    | m < 0x80 = acc `mappend` e1 (fromIntegral m)
-    | otherwise = go (acc <> e1 (setBit (fromIntegral m) 7)) (shiftR m 7)
-{-# INLINE encodeVarInt #-}
+      | n' < 0x40 -> word8 (fromIntegral n' `setBit` 6)
+      | otherwise -> encodesUVarInt (word8 (0xc0 .|. fromIntegral n')) (unsafeShiftR n' 6)
+  | n < 0x40 = word8 (fromIntegral n)
+  | otherwise = encodesUVarInt (word8 (fromIntegral n `setBit` 7 `clearBit` 6)) (unsafeShiftR n 6)
+{-# SPECIALISE encodeVarInt :: Int -> Encoding #-}
 
+encodesUVarInt :: (Bits a, Integral a) => Encoding -> a -> Encoding
+encodesUVarInt !acc m
+  | m < 0x80 = acc `mappend` word8 (fromIntegral m)
+  | otherwise = encodesUVarInt (acc <> word8 (setBit (fromIntegral m) 7)) (unsafeShiftR m 7)
+{-# SPECIALISE encodesUVarInt :: Encoding -> Int -> Encoding #-}
+
 getWord8 :: ContT r Decoder Word8
 getWord8 = ContT $ \k bs -> case B.uncons bs of
   Nothing -> k 0 bs
@@ -89,15 +81,15 @@
   n | testBit n 7 -> do
       m <- getWord8 >>= go
       if testBit n 6
-        then return $! negate $ shiftL m 6 .|. fromIntegral n .&. 0x3f
-        else return $! shiftL m 6 .|. clearBit (fromIntegral n) 7
+        then return $! negate $ unsafeShiftL m 6 .|. fromIntegral n .&. 0x3f
+        else return $! unsafeShiftL m 6 .|. clearBit (fromIntegral n) 7
     | testBit n 6 -> return $ negate $ fromIntegral $ clearBit n 6
     | otherwise -> return $ fromIntegral n
   where
     go n
       | testBit n 7 = do
         m <- getWord8 >>= go
-        return $! shiftL m 7 .|. clearBit (fromIntegral n) 7
+        return $! unsafeShiftL m 7 .|. clearBit (fromIntegral n) 7
       | otherwise = return $ fromIntegral n
 {-# INLINE decodeVarInt #-}
 
@@ -130,14 +122,20 @@
     (fromIntegral (s `B.unsafeIndex` 7) )
   else error $ "word64be" ++ show s
 
-encodeMulti :: [Encoding] -> Encoding
-encodeMulti xs = rebuildEncoding
-  $ foldMap (encodeVarInt . encodingLength) (safeInit xs) <> mconcat xs
-  where
-    safeInit [] = []
-    safeInit [_] = []
-    safeInit (y:ys) = y : safeInit ys
+data EncodingMulti = EncodingMulti0
+    | EncodingMulti !Encoding !Encoding
+
+encodeMulti :: (EncodingMulti -> EncodingMulti) -> Encoding
+encodeMulti f = case f EncodingMulti0 of
+  EncodingMulti0 -> mempty
+  EncodingMulti r s -> mappend r s
 {-# INLINE encodeMulti #-}
+
+encodeItem :: Encoding -> EncodingMulti -> EncodingMulti
+encodeItem e EncodingMulti0 = EncodingMulti mempty e
+encodeItem e (EncodingMulti a b) = EncodingMulti
+  (mappend (encodeVarInt (getSize e)) a) (mappend e b)
+{-# INLINE encodeItem #-}
 
 type Offsets = U.Vector (Int, Int)
 
diff --git a/src/Data/Winery/Internal/Builder.hs b/src/Data/Winery/Internal/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Winery/Internal/Builder.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, BangPatterns #-}
+module Data.Winery.Internal.Builder
+  ( Encoding
+  , getSize
+  , toByteString
+  , word8
+  , word16
+  , word32
+  , word64
+  , bytes
+  ) where
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Internal as B
+import Data.Word
+import Foreign.Ptr
+import Foreign.ForeignPtr
+import Foreign.Storable
+import System.IO.Unsafe
+import System.Endian
+
+data Encoding = Encoding {-# UNPACK #-}!Int !Tree
+  | Empty
+
+data Tree = Bin Tree Tree
+  | LWord8 {-# UNPACK #-} !Word8
+  | LWord16 {-# UNPACK #-} !Word16
+  | LWord32 {-# UNPACK #-} !Word32
+  | LWord64 {-# UNPACK #-} !Word64
+  | LBytes !B.ByteString
+
+instance Monoid Encoding where
+  mempty = Empty
+  {-# INLINE mempty #-}
+  mappend Empty a = a
+  mappend a Empty = a
+  mappend (Encoding s a) (Encoding t b) = Encoding (s + t) (Bin a b)
+  {-# INLINE mappend #-}
+
+getSize :: Encoding -> Int
+getSize Empty = 0
+getSize (Encoding s _) = s
+{-# INLINE getSize #-}
+
+toByteString :: Encoding -> B.ByteString
+toByteString Empty = B.empty
+toByteString (Encoding len tree) = unsafeDupablePerformIO $ do
+  fp <- B.mallocByteString len
+  withForeignPtr fp $ \ptr -> do
+    let copyBS ofs (B.PS fp' sofs len') = withForeignPtr fp'
+          $ \src -> B.memcpy (ptr `plusPtr` ofs) (src `plusPtr` sofs) len'
+    let go :: Int -> Tree -> IO ()
+        go ofs l = case l of
+          LWord8 w -> pokeByteOff ptr ofs w
+          LWord16 w -> pokeByteOff ptr ofs $ toBE16 w
+          LWord32 w -> pokeByteOff ptr ofs $ toBE32 w
+          LWord64 w -> pokeByteOff ptr ofs $ toBE64 w
+          LBytes bs -> copyBS ofs bs
+          Bin a b -> rotate ofs a b
+
+        rotate :: Int -> Tree -> Tree -> IO ()
+        rotate ofs (LWord8 w) t = pokeByteOff ptr ofs w >> go (ofs + 1) t
+        rotate ofs (LWord16 w) t = pokeByteOff ptr ofs (toBE16 w) >> go (ofs + 2) t
+        rotate ofs (LWord32 w) t = pokeByteOff ptr ofs (toBE32 w) >> go (ofs + 4) t
+        rotate ofs (LWord64 w) t = pokeByteOff ptr ofs (toBE64 w) >> go (ofs + 8) t
+        rotate ofs (LBytes bs) t = copyBS ofs bs >> go (ofs + B.length bs) t
+        rotate ofs (Bin c d) t = rotate ofs c (Bin d t)
+    go 0 tree
+  return (B.PS fp 0 len)
+
+word8 :: Word8 -> Encoding
+word8 = Encoding 1 . LWord8
+{-# INLINE word8 #-}
+
+word16 :: Word16 -> Encoding
+word16 = Encoding 2 . LWord16
+{-# INLINE word16 #-}
+
+word32 :: Word32 -> Encoding
+word32 = Encoding 4 . LWord32
+{-# INLINE word32 #-}
+
+word64 :: Word64 -> Encoding
+word64 = Encoding 8 . LWord64
+{-# INLINE word64 #-}
+
+bytes :: B.ByteString -> Encoding
+bytes bs = Encoding (B.length bs) $ LBytes bs
+{-# INLINE bytes #-}
diff --git a/winery.cabal b/winery.cabal
--- a/winery.cabal
+++ b/winery.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: cd7f7da4332784c7d2fa7dab5a2c1c418d2f8c00ede5bbb3c1b560a6323fb4a6
+-- hash: 750a23f7c3318207ce7adf5a4637dd1630f0e706c5efab6184ecbb0fc4b4882e
 
 name:           winery
-version:        0.1
+version:        0.1.1
 synopsis:       Sustainable serialisation library
 description:    Please see the README on Github at <https://github.com/fumieval/winery#readme>
 category:       Data
@@ -35,7 +35,8 @@
       base >=4.7 && <5
     , bytestring
     , containers
-    , fast-builder
+    , cpu
+    , fingertree
     , hashable
     , mtl
     , prettyprinter
@@ -49,6 +50,7 @@
       Data.Winery.Term
       Data.Winery.Internal
   other-modules:
+      Data.Winery.Internal.Builder
       Paths_winery
   default-language: Haskell2010
 
@@ -60,7 +62,8 @@
       base >=4.7 && <5
     , bytestring
     , containers
-    , fast-builder
+    , cpu
+    , fingertree
     , hashable
     , mtl
     , prettyprinter
@@ -83,7 +86,8 @@
       base >=4.7 && <5
     , bytestring
     , containers
-    , fast-builder
+    , cpu
+    , fingertree
     , hashable
     , mtl
     , prettyprinter
@@ -109,8 +113,9 @@
     , bytestring
     , cassava
     , containers
+    , cpu
     , deepseq
-    , fast-builder
+    , fingertree
     , gauge
     , hashable
     , mtl
