diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+*.hi
+*.o
+*.p_hi
+*.prof
+*.tix
+.hpc/
+/benchmarks/bench
+/benchmarks/builder
+/dist/*
+/tests/qc
+GNUmakefile
+dist-boot
+dist-install
+ghc.mk
diff --git a/TODO b/TODO
new file mode 100644
--- /dev/null
+++ b/TODO
@@ -0,0 +1,28 @@
+layer handling:
+
+    bit packing
+    state parameters
+    string pools
+
+    reading structures from the end of a stream, seek/tell behaviour
+
+seek based protocols are too hard. 
+    hGetContents/ interleaving.
+
+user requests:
+
+    get remaining bytestring after a runGet
+
+    some kind of lookahead, or restoring parsing state, or something with
+      equal functionality. make it another layer on top?
+
+    getLazyByteString takes an Int, which in Haskell98 is only guarantied to
+      be 29 bits, ie. 512 mb.
+      maybe we should have a readN64 for allowing reading of larger stuff?
+      (which could be implemented with readN on 64bit machines)
+      reference: bringerts tar archive decoder would be limitid to 0.5GB
+                 files, alt. 2GB in GHC
+
+SYB-deriving
+
+investigate the UArray instance, it does not seem to compile in GHC 6.4
diff --git a/benchmarks/Benchmark.hs b/benchmarks/Benchmark.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Benchmark.hs
@@ -0,0 +1,1461 @@
+{-# LANGUAGE BangPatterns #-}
+module Main (main) where
+
+import qualified Data.ByteString.Lazy as L
+import Data.Binary
+import Data.Binary.Put
+import Data.Binary.Get
+
+import Control.Exception
+import System.CPUTime
+import Numeric
+import Text.Printf
+import System.Environment
+
+import MemBench
+
+data Endian
+    = Big
+    | Little
+    | Host
+    deriving (Eq,Ord,Show)
+
+main :: IO ()
+main = do
+  mb <- getArgs >>= readIO . head
+  memBench (mb*10) 
+  putStrLn ""
+  putStrLn "Binary (de)serialisation benchmarks:"
+
+  -- do bytewise 
+  sequence_
+    [ test wordSize chunkSize Host mb
+    | wordSize  <- [1]
+    , chunkSize <- [16] --1,2,4,8,16]
+    ]
+
+  -- now Word16 .. Word64
+  sequence_
+    [ test wordSize chunkSize end mb
+    | wordSize  <- [2,4,8]
+    , chunkSize <- [16]
+    , end       <- [Host] -- ,Big,Little]
+    ]
+
+------------------------------------------------------------------------
+
+time :: IO a -> IO Double
+time action = do
+    start <- getCPUTime
+    action
+    end   <- getCPUTime
+    return $! (fromIntegral (end - start)) / (10^12)
+
+------------------------------------------------------------------------
+
+test :: Int -> Int -> Endian -> Int -> IO ()
+test wordSize chunkSize end mb = do
+    let bytes :: Int
+        bytes = mb * 2^20
+        iterations = bytes `div` wordSize
+        bs  = runPut (doPut wordSize chunkSize end iterations)
+        sum = runGet (doGet wordSize chunkSize end iterations) bs
+
+    case (chunkSize,end) of (1,Host) -> putStrLn "" ; _ -> return ()
+
+    printf "%dMB of Word%-2d in chunks of %2d (%6s endian): "
+        (mb :: Int) (8 * wordSize :: Int) (chunkSize :: Int) (show end)
+
+    putSeconds <- time $ evaluate (L.length bs)
+    getSeconds <- time $ evaluate sum
+--    print (L.length bs, sum)
+    let putThroughput = fromIntegral mb / putSeconds
+        getThroughput = fromIntegral mb / getSeconds
+
+    printf "%6.1f MB/s write, %6.1f MB/s read, %5.1f get/put-ratio\n"
+           putThroughput
+           getThroughput
+           (getThroughput/putThroughput)
+
+------------------------------------------------------------------------
+
+doPut :: Int -> Int -> Endian -> Int -> Put
+doPut wordSize chunkSize end = case (wordSize, chunkSize, end) of
+    (1, 1,_)   -> putWord8N1
+    (1, 2,_)   -> putWord8N2
+    (1, 4,_)   -> putWord8N4
+    (1, 8,_)   -> putWord8N8
+    (1, 16, _) -> putWord8N16
+
+    (2, 1,  Big)    -> putWord16N1Big
+    (2, 2,  Big)    -> putWord16N2Big
+    (2, 4,  Big)    -> putWord16N4Big
+    (2, 8,  Big)    -> putWord16N8Big
+    (2, 16, Big)    -> putWord16N16Big
+    (2, 1,  Little) -> putWord16N1Little
+    (2, 2,  Little) -> putWord16N2Little
+    (2, 4,  Little) -> putWord16N4Little
+    (2, 8,  Little) -> putWord16N8Little
+    (2, 16, Little) -> putWord16N16Little
+    (2, 1,  Host)   -> putWord16N1Host
+    (2, 2,  Host)   -> putWord16N2Host
+    (2, 4,  Host)   -> putWord16N4Host
+    (2, 8,  Host)   -> putWord16N8Host
+    (2, 16, Host)   -> putWord16N16Host
+
+    (4, 1,  Big)    -> putWord32N1Big
+    (4, 2,  Big)    -> putWord32N2Big
+    (4, 4,  Big)    -> putWord32N4Big
+    (4, 8,  Big)    -> putWord32N8Big
+    (4, 16, Big)    -> putWord32N16Big
+    (4, 1,  Little) -> putWord32N1Little
+    (4, 2,  Little) -> putWord32N2Little
+    (4, 4,  Little) -> putWord32N4Little
+    (4, 8,  Little) -> putWord32N8Little
+    (4, 16, Little) -> putWord32N16Little
+    (4, 1,  Host)   -> putWord32N1Host
+    (4, 2,  Host)   -> putWord32N2Host
+    (4, 4,  Host)   -> putWord32N4Host
+    (4, 8,  Host)   -> putWord32N8Host
+    (4, 16, Host)   -> putWord32N16Host
+
+    (8, 1,  Host)        -> putWord64N1Host
+    (8, 2,  Host)        -> putWord64N2Host
+    (8, 4,  Host)        -> putWord64N4Host
+    (8, 8,  Host)        -> putWord64N8Host
+    (8, 16, Host)        -> putWord64N16Host
+    (8, 1,  Big)         -> putWord64N1Big
+    (8, 2,  Big)         -> putWord64N2Big
+    (8, 4,  Big)         -> putWord64N4Big
+    (8, 8,  Big)         -> putWord64N8Big
+    (8, 16, Big)         -> putWord64N16Big
+    (8, 1,  Little)      -> putWord64N1Little
+    (8, 2,  Little)      -> putWord64N2Little
+    (8, 4,  Little)      -> putWord64N4Little
+    (8, 8,  Little)      -> putWord64N8Little
+    (8, 16, Little)      -> putWord64N16Little
+
+------------------------------------------------------------------------
+
+doGet :: Int -> Int -> Endian -> Int -> Get Int
+doGet wordSize chunkSize end =
+  case (wordSize, chunkSize, end) of
+    (1, 1,_)  -> fmap fromIntegral . getWord8N1
+    (1, 2,_)  -> fmap fromIntegral . getWord8N2
+    (1, 4,_)  -> fmap fromIntegral . getWord8N4
+    (1, 8,_)  -> fmap fromIntegral . getWord8N8
+    (1, 16,_) -> fmap fromIntegral . getWord8N16
+
+    (2, 1,Big)      -> fmap fromIntegral . getWord16N1Big
+    (2, 2,Big)      -> fmap fromIntegral . getWord16N2Big
+    (2, 4,Big)      -> fmap fromIntegral . getWord16N4Big
+    (2, 8,Big)      -> fmap fromIntegral . getWord16N8Big
+    (2, 16,Big)     -> fmap fromIntegral . getWord16N16Big
+    (2, 1,Little)   -> fmap fromIntegral . getWord16N1Little
+    (2, 2,Little)   -> fmap fromIntegral . getWord16N2Little
+    (2, 4,Little)   -> fmap fromIntegral . getWord16N4Little
+    (2, 8,Little)   -> fmap fromIntegral . getWord16N8Little
+    (2, 16,Little)  -> fmap fromIntegral . getWord16N16Little
+    (2, 1,Host)     -> fmap fromIntegral . getWord16N1Host
+    (2, 2,Host)     -> fmap fromIntegral . getWord16N2Host
+    (2, 4,Host)     -> fmap fromIntegral . getWord16N4Host
+    (2, 8,Host)     -> fmap fromIntegral . getWord16N8Host
+    (2, 16,Host)    -> fmap fromIntegral . getWord16N16Host
+
+    (4, 1,Big)      -> fmap fromIntegral . getWord32N1Big
+    (4, 2,Big)      -> fmap fromIntegral . getWord32N2Big
+    (4, 4,Big)      -> fmap fromIntegral . getWord32N4Big
+    (4, 8,Big)      -> fmap fromIntegral . getWord32N8Big
+    (4, 16,Big)     -> fmap fromIntegral . getWord32N16Big
+    (4, 1,Little)   -> fmap fromIntegral . getWord32N1Little
+    (4, 2,Little)   -> fmap fromIntegral . getWord32N2Little
+    (4, 4,Little)   -> fmap fromIntegral . getWord32N4Little
+    (4, 8,Little)   -> fmap fromIntegral . getWord32N8Little
+    (4, 16,Little)  -> fmap fromIntegral . getWord32N16Little
+    (4, 1,Host)     -> fmap fromIntegral . getWord32N1Host
+    (4, 2,Host)     -> fmap fromIntegral . getWord32N2Host
+    (4, 4,Host)     -> fmap fromIntegral . getWord32N4Host
+    (4, 8,Host)     -> fmap fromIntegral . getWord32N8Host
+    (4, 16,Host)    -> fmap fromIntegral . getWord32N16Host
+
+    (8, 1,Host)     -> fmap fromIntegral . getWord64N1Host
+    (8, 2,Host)     -> fmap fromIntegral . getWord64N2Host
+    (8, 4,Host)     -> fmap fromIntegral . getWord64N4Host
+    (8, 8,Host)     -> fmap fromIntegral . getWord64N8Host
+    (8, 16,Host)    -> fmap fromIntegral . getWord64N16Host
+    (8, 1,Big)      -> fmap fromIntegral . getWord64N1Big
+    (8, 2,Big)      -> fmap fromIntegral . getWord64N2Big
+    (8, 4,Big)      -> fmap fromIntegral . getWord64N4Big
+    (8, 8,Big)      -> fmap fromIntegral . getWord64N8Big
+    (8, 16,Big)     -> fmap fromIntegral . getWord64N16Big
+    (8, 1,Little)   -> fmap fromIntegral . getWord64N1Little
+    (8, 2,Little)   -> fmap fromIntegral . getWord64N2Little
+    (8, 4,Little)   -> fmap fromIntegral . getWord64N4Little
+    (8, 8,Little)   -> fmap fromIntegral . getWord64N8Little
+    (8, 16,Little)  -> fmap fromIntegral . getWord64N16Little
+
+------------------------------------------------------------------------
+
+putWord8N1 bytes = loop 0 0
+  where loop :: Word8 -> Int -> Put
+        loop !s !n | n == bytes = return ()
+                   | otherwise  = do putWord8 s
+                                     loop (s+1) (n+1)
+
+putWord8N2 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord8 (s+0)
+          putWord8 (s+1)
+          loop (s+2) (n-2)
+
+putWord8N4 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord8 (s+0)
+          putWord8 (s+1)
+          putWord8 (s+2)
+          putWord8 (s+3)
+          loop (s+4) (n-4)
+
+putWord8N8 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord8 (s+0)
+          putWord8 (s+1)
+          putWord8 (s+2)
+          putWord8 (s+3)
+          putWord8 (s+4)
+          putWord8 (s+5)
+          putWord8 (s+6)
+          putWord8 (s+7)
+          loop (s+8) (n-8)
+
+putWord8N16 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord8 (s+0)
+          putWord8 (s+1)
+          putWord8 (s+2)
+          putWord8 (s+3)
+          putWord8 (s+4)
+          putWord8 (s+5)
+          putWord8 (s+6)
+          putWord8 (s+7)
+          putWord8 (s+8)
+          putWord8 (s+9)
+          putWord8 (s+10)
+          putWord8 (s+11)
+          putWord8 (s+12)
+          putWord8 (s+13)
+          putWord8 (s+14)
+          putWord8 (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+-- Big endian, word16 writes
+
+putWord16N1Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16be (s+0)
+          loop (s+1) (n-1)
+
+putWord16N2Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16be (s+0)
+          putWord16be (s+1)
+          loop (s+2) (n-2)
+
+putWord16N4Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16be (s+0)
+          putWord16be (s+1)
+          putWord16be (s+2)
+          putWord16be (s+3)
+          loop (s+4) (n-4)
+
+putWord16N8Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16be (s+0)
+          putWord16be (s+1)
+          putWord16be (s+2)
+          putWord16be (s+3)
+          putWord16be (s+4)
+          putWord16be (s+5)
+          putWord16be (s+6)
+          putWord16be (s+7)
+          loop (s+8) (n-8)
+
+putWord16N16Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16be (s+0)
+          putWord16be (s+1)
+          putWord16be (s+2)
+          putWord16be (s+3)
+          putWord16be (s+4)
+          putWord16be (s+5)
+          putWord16be (s+6)
+          putWord16be (s+7)
+          putWord16be (s+8)
+          putWord16be (s+9)
+          putWord16be (s+10)
+          putWord16be (s+11)
+          putWord16be (s+12)
+          putWord16be (s+13)
+          putWord16be (s+14)
+          putWord16be (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+-- Little endian, word16 writes
+
+putWord16N1Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16le (s+0)
+          loop (s+1) (n-1)
+
+putWord16N2Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16le (s+0)
+          putWord16le (s+1)
+          loop (s+2) (n-2)
+
+putWord16N4Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16le (s+0)
+          putWord16le (s+1)
+          putWord16le (s+2)
+          putWord16le (s+3)
+          loop (s+4) (n-4)
+
+putWord16N8Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16le (s+0)
+          putWord16le (s+1)
+          putWord16le (s+2)
+          putWord16le (s+3)
+          putWord16le (s+4)
+          putWord16le (s+5)
+          putWord16le (s+6)
+          putWord16le (s+7)
+          loop (s+8) (n-8)
+
+putWord16N16Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16le (s+0)
+          putWord16le (s+1)
+          putWord16le (s+2)
+          putWord16le (s+3)
+          putWord16le (s+4)
+          putWord16le (s+5)
+          putWord16le (s+6)
+          putWord16le (s+7)
+          putWord16le (s+8)
+          putWord16le (s+9)
+          putWord16le (s+10)
+          putWord16le (s+11)
+          putWord16le (s+12)
+          putWord16le (s+13)
+          putWord16le (s+14)
+          putWord16le (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+-- Host endian, unaligned, word16 writes
+
+putWord16N1Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16host (s+0)
+          loop (s+1) (n-1)
+
+putWord16N2Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16host (s+0)
+          putWord16host (s+1)
+          loop (s+2) (n-2)
+
+putWord16N4Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16host (s+0)
+          putWord16host (s+1)
+          putWord16host (s+2)
+          putWord16host (s+3)
+          loop (s+4) (n-4)
+
+putWord16N8Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16host (s+0)
+          putWord16host (s+1)
+          putWord16host (s+2)
+          putWord16host (s+3)
+          putWord16host (s+4)
+          putWord16host (s+5)
+          putWord16host (s+6)
+          putWord16host (s+7)
+          loop (s+8) (n-8)
+
+putWord16N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord16host (s+0)
+          putWord16host (s+1)
+          putWord16host (s+2)
+          putWord16host (s+3)
+          putWord16host (s+4)
+          putWord16host (s+5)
+          putWord16host (s+6)
+          putWord16host (s+7)
+          putWord16host (s+8)
+          putWord16host (s+9)
+          putWord16host (s+10)
+          putWord16host (s+11)
+          putWord16host (s+12)
+          putWord16host (s+13)
+          putWord16host (s+14)
+          putWord16host (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+
+putWord32N1Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32be (s+0)
+          loop (s+1) (n-1)
+
+putWord32N2Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32be (s+0)
+          putWord32be (s+1)
+          loop (s+2) (n-2)
+
+putWord32N4Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32be (s+0)
+          putWord32be (s+1)
+          putWord32be (s+2)
+          putWord32be (s+3)
+          loop (s+4) (n-4)
+
+putWord32N8Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32be (s+0)
+          putWord32be (s+1)
+          putWord32be (s+2)
+          putWord32be (s+3)
+          putWord32be (s+4)
+          putWord32be (s+5)
+          putWord32be (s+6)
+          putWord32be (s+7)
+          loop (s+8) (n-8)
+
+putWord32N16Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32be (s+0)
+          putWord32be (s+1)
+          putWord32be (s+2)
+          putWord32be (s+3)
+          putWord32be (s+4)
+          putWord32be (s+5)
+          putWord32be (s+6)
+          putWord32be (s+7)
+          putWord32be (s+8)
+          putWord32be (s+9)
+          putWord32be (s+10)
+          putWord32be (s+11)
+          putWord32be (s+12)
+          putWord32be (s+13)
+          putWord32be (s+14)
+          putWord32be (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+
+putWord32N1Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32le (s+0)
+          loop (s+1) (n-1)
+
+putWord32N2Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32le (s+0)
+          putWord32le (s+1)
+          loop (s+2) (n-2)
+
+putWord32N4Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32le (s+0)
+          putWord32le (s+1)
+          putWord32le (s+2)
+          putWord32le (s+3)
+          loop (s+4) (n-4)
+
+putWord32N8Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32le (s+0)
+          putWord32le (s+1)
+          putWord32le (s+2)
+          putWord32le (s+3)
+          putWord32le (s+4)
+          putWord32le (s+5)
+          putWord32le (s+6)
+          putWord32le (s+7)
+          loop (s+8) (n-8)
+
+putWord32N16Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32le (s+0)
+          putWord32le (s+1)
+          putWord32le (s+2)
+          putWord32le (s+3)
+          putWord32le (s+4)
+          putWord32le (s+5)
+          putWord32le (s+6)
+          putWord32le (s+7)
+          putWord32le (s+8)
+          putWord32le (s+9)
+          putWord32le (s+10)
+          putWord32le (s+11)
+          putWord32le (s+12)
+          putWord32le (s+13)
+          putWord32le (s+14)
+          putWord32le (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+
+putWord32N1Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32host (s+0)
+          loop (s+1) (n-1)
+
+putWord32N2Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32host (s+0)
+          putWord32host (s+1)
+          loop (s+2) (n-2)
+
+putWord32N4Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32host (s+0)
+          putWord32host (s+1)
+          putWord32host (s+2)
+          putWord32host (s+3)
+          loop (s+4) (n-4)
+
+putWord32N8Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32host (s+0)
+          putWord32host (s+1)
+          putWord32host (s+2)
+          putWord32host (s+3)
+          putWord32host (s+4)
+          putWord32host (s+5)
+          putWord32host (s+6)
+          putWord32host (s+7)
+          loop (s+8) (n-8)
+
+putWord32N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord32host (s+0)
+          putWord32host (s+1)
+          putWord32host (s+2)
+          putWord32host (s+3)
+          putWord32host (s+4)
+          putWord32host (s+5)
+          putWord32host (s+6)
+          putWord32host (s+7)
+          putWord32host (s+8)
+          putWord32host (s+9)
+          putWord32host (s+10)
+          putWord32host (s+11)
+          putWord32host (s+12)
+          putWord32host (s+13)
+          putWord32host (s+14)
+          putWord32host (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+
+putWord64N1Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64be (s+0)
+          loop (s+1) (n-1)
+
+putWord64N2Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64be (s+0)
+          putWord64be (s+1)
+          loop (s+2) (n-2)
+
+putWord64N4Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64be (s+0)
+          putWord64be (s+1)
+          putWord64be (s+2)
+          putWord64be (s+3)
+          loop (s+4) (n-4)
+
+putWord64N8Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64be (s+0)
+          putWord64be (s+1)
+          putWord64be (s+2)
+          putWord64be (s+3)
+          putWord64be (s+4)
+          putWord64be (s+5)
+          putWord64be (s+6)
+          putWord64be (s+7)
+          loop (s+8) (n-8)
+
+putWord64N16Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64be (s+0)
+          putWord64be (s+1)
+          putWord64be (s+2)
+          putWord64be (s+3)
+          putWord64be (s+4)
+          putWord64be (s+5)
+          putWord64be (s+6)
+          putWord64be (s+7)
+          putWord64be (s+8)
+          putWord64be (s+9)
+          putWord64be (s+10)
+          putWord64be (s+11)
+          putWord64be (s+12)
+          putWord64be (s+13)
+          putWord64be (s+14)
+          putWord64be (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+
+putWord64N1Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64le (s+0)
+          loop (s+1) (n-1)
+
+putWord64N2Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64le (s+0)
+          putWord64le (s+1)
+          loop (s+2) (n-2)
+
+putWord64N4Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64le (s+0)
+          putWord64le (s+1)
+          putWord64le (s+2)
+          putWord64le (s+3)
+          loop (s+4) (n-4)
+
+putWord64N8Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64le (s+0)
+          putWord64le (s+1)
+          putWord64le (s+2)
+          putWord64le (s+3)
+          putWord64le (s+4)
+          putWord64le (s+5)
+          putWord64le (s+6)
+          putWord64le (s+7)
+          loop (s+8) (n-8)
+
+putWord64N16Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64le (s+0)
+          putWord64le (s+1)
+          putWord64le (s+2)
+          putWord64le (s+3)
+          putWord64le (s+4)
+          putWord64le (s+5)
+          putWord64le (s+6)
+          putWord64le (s+7)
+          putWord64le (s+8)
+          putWord64le (s+9)
+          putWord64le (s+10)
+          putWord64le (s+11)
+          putWord64le (s+12)
+          putWord64le (s+13)
+          putWord64le (s+14)
+          putWord64le (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+
+putWord64N1Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64host (s+0)
+          loop (s+1) (n-1)
+
+putWord64N2Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64host (s+0)
+          putWord64host (s+1)
+          loop (s+2) (n-2)
+
+putWord64N4Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64host (s+0)
+          putWord64host (s+1)
+          putWord64host (s+2)
+          putWord64host (s+3)
+          loop (s+4) (n-4)
+
+putWord64N8Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64host (s+0)
+          putWord64host (s+1)
+          putWord64host (s+2)
+          putWord64host (s+3)
+          putWord64host (s+4)
+          putWord64host (s+5)
+          putWord64host (s+6)
+          putWord64host (s+7)
+          loop (s+8) (n-8)
+
+putWord64N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = return ()
+        loop s n = do
+          putWord64host (s+0)
+          putWord64host (s+1)
+          putWord64host (s+2)
+          putWord64host (s+3)
+          putWord64host (s+4)
+          putWord64host (s+5)
+          putWord64host (s+6)
+          putWord64host (s+7)
+          putWord64host (s+8)
+          putWord64host (s+9)
+          putWord64host (s+10)
+          putWord64host (s+11)
+          putWord64host (s+12)
+          putWord64host (s+13)
+          putWord64host (s+14)
+          putWord64host (s+15)
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+------------------------------------------------------------------------
+
+getWord8N1 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord8
+          loop (s+s0) (n-1)
+
+getWord8N2 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord8
+          s1 <- getWord8
+          loop (s+s0+s1) (n-2)
+
+getWord8N4 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord8
+          s1 <- getWord8
+          s2 <- getWord8
+          s3 <- getWord8
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord8N8 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord8
+          s1 <- getWord8
+          s2 <- getWord8
+          s3 <- getWord8
+          s4 <- getWord8
+          s5 <- getWord8
+          s6 <- getWord8
+          s7 <- getWord8
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord8N16 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord8
+          s1 <- getWord8
+          s2 <- getWord8
+          s3 <- getWord8
+          s4 <- getWord8
+          s5 <- getWord8
+          s6 <- getWord8
+          s7 <- getWord8
+          s8 <- getWord8
+          s9 <- getWord8
+          s10 <- getWord8
+          s11 <- getWord8
+          s12 <- getWord8
+          s13 <- getWord8
+          s14 <- getWord8
+          s15 <- getWord8
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord16N1Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16be
+          loop (s+s0) (n-1)
+
+getWord16N2Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16be
+          s1 <- getWord16be
+          loop (s+s0+s1) (n-2)
+
+getWord16N4Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16be
+          s1 <- getWord16be
+          s2 <- getWord16be
+          s3 <- getWord16be
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord16N8Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16be
+          s1 <- getWord16be
+          s2 <- getWord16be
+          s3 <- getWord16be
+          s4 <- getWord16be
+          s5 <- getWord16be
+          s6 <- getWord16be
+          s7 <- getWord16be
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord16N16Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16be
+          s1 <- getWord16be
+          s2 <- getWord16be
+          s3 <- getWord16be
+          s4 <- getWord16be
+          s5 <- getWord16be
+          s6 <- getWord16be
+          s7 <- getWord16be
+          s8 <- getWord16be
+          s9 <- getWord16be
+          s10 <- getWord16be
+          s11 <- getWord16be
+          s12 <- getWord16be
+          s13 <- getWord16be
+          s14 <- getWord16be
+          s15 <- getWord16be
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord16N1Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16le
+          loop (s+s0) (n-1)
+
+getWord16N2Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16le
+          s1 <- getWord16le
+          loop (s+s0+s1) (n-2)
+
+getWord16N4Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16le
+          s1 <- getWord16le
+          s2 <- getWord16le
+          s3 <- getWord16le
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord16N8Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16le
+          s1 <- getWord16le
+          s2 <- getWord16le
+          s3 <- getWord16le
+          s4 <- getWord16le
+          s5 <- getWord16le
+          s6 <- getWord16le
+          s7 <- getWord16le
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord16N16Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16le
+          s1 <- getWord16le
+          s2 <- getWord16le
+          s3 <- getWord16le
+          s4 <- getWord16le
+          s5 <- getWord16le
+          s6 <- getWord16le
+          s7 <- getWord16le
+          s8 <- getWord16le
+          s9 <- getWord16le
+          s10 <- getWord16le
+          s11 <- getWord16le
+          s12 <- getWord16le
+          s13 <- getWord16le
+          s14 <- getWord16le
+          s15 <- getWord16le
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord16N1Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16host
+          loop (s+s0) (n-1)
+
+getWord16N2Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16host
+          s1 <- getWord16host
+          loop (s+s0+s1) (n-2)
+
+getWord16N4Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16host
+          s1 <- getWord16host
+          s2 <- getWord16host
+          s3 <- getWord16host
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord16N8Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16host
+          s1 <- getWord16host
+          s2 <- getWord16host
+          s3 <- getWord16host
+          s4 <- getWord16host
+          s5 <- getWord16host
+          s6 <- getWord16host
+          s7 <- getWord16host
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord16N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord16host
+          s1 <- getWord16host
+          s2 <- getWord16host
+          s3 <- getWord16host
+          s4 <- getWord16host
+          s5 <- getWord16host
+          s6 <- getWord16host
+          s7 <- getWord16host
+          s8 <- getWord16host
+          s9 <- getWord16host
+          s10 <- getWord16host
+          s11 <- getWord16host
+          s12 <- getWord16host
+          s13 <- getWord16host
+          s14 <- getWord16host
+          s15 <- getWord16host
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord32N1Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32be
+          loop (s+s0) (n-1)
+
+getWord32N2Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32be
+          s1 <- getWord32be
+          loop (s+s0+s1) (n-2)
+
+getWord32N4Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32be
+          s1 <- getWord32be
+          s2 <- getWord32be
+          s3 <- getWord32be
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord32N8Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32be
+          s1 <- getWord32be
+          s2 <- getWord32be
+          s3 <- getWord32be
+          s4 <- getWord32be
+          s5 <- getWord32be
+          s6 <- getWord32be
+          s7 <- getWord32be
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+-- getWordhostN16 = loop 0
+getWord32N16Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32be
+          s1 <- getWord32be
+          s2 <- getWord32be
+          s3 <- getWord32be
+          s4 <- getWord32be
+          s5 <- getWord32be
+          s6 <- getWord32be
+          s7 <- getWord32be
+          s8 <- getWord32be
+          s9 <- getWord32be
+          s10 <- getWord32be
+          s11 <- getWord32be
+          s12 <- getWord32be
+          s13 <- getWord32be
+          s14 <- getWord32be
+          s15 <- getWord32be
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord32N1Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32le
+          loop (s+s0) (n-1)
+
+getWord32N2Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32le
+          s1 <- getWord32le
+          loop (s+s0+s1) (n-2)
+
+getWord32N4Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32le
+          s1 <- getWord32le
+          s2 <- getWord32le
+          s3 <- getWord32le
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord32N8Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32le
+          s1 <- getWord32le
+          s2 <- getWord32le
+          s3 <- getWord32le
+          s4 <- getWord32le
+          s5 <- getWord32le
+          s6 <- getWord32le
+          s7 <- getWord32le
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+-- getWordhostN16 = loop 0
+getWord32N16Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32le
+          s1 <- getWord32le
+          s2 <- getWord32le
+          s3 <- getWord32le
+          s4 <- getWord32le
+          s5 <- getWord32le
+          s6 <- getWord32le
+          s7 <- getWord32le
+          s8 <- getWord32le
+          s9 <- getWord32le
+          s10 <- getWord32le
+          s11 <- getWord32le
+          s12 <- getWord32le
+          s13 <- getWord32le
+          s14 <- getWord32le
+          s15 <- getWord32le
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord32N1Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32host
+          loop (s+s0) (n-1)
+
+getWord32N2Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32host
+          s1 <- getWord32host
+          loop (s+s0+s1) (n-2)
+
+getWord32N4Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32host
+          s1 <- getWord32host
+          s2 <- getWord32host
+          s3 <- getWord32host
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord32N8Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32host
+          s1 <- getWord32host
+          s2 <- getWord32host
+          s3 <- getWord32host
+          s4 <- getWord32host
+          s5 <- getWord32host
+          s6 <- getWord32host
+          s7 <- getWord32host
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+-- getWordhostN16 = loop 0
+getWord32N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord32host
+          s1 <- getWord32host
+          s2 <- getWord32host
+          s3 <- getWord32host
+          s4 <- getWord32host
+          s5 <- getWord32host
+          s6 <- getWord32host
+          s7 <- getWord32host
+          s8 <- getWord32host
+          s9 <- getWord32host
+          s10 <- getWord32host
+          s11 <- getWord32host
+          s12 <- getWord32host
+          s13 <- getWord32host
+          s14 <- getWord32host
+          s15 <- getWord32host
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord64N1Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64be
+          loop (s+s0) (n-1)
+
+getWord64N2Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64be
+          s1 <- getWord64be
+          loop (s+s0+s1) (n-2)
+
+getWord64N4Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64be
+          s1 <- getWord64be
+          s2 <- getWord64be
+          s3 <- getWord64be
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord64N8Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64be
+          s1 <- getWord64be
+          s2 <- getWord64be
+          s3 <- getWord64be
+          s4 <- getWord64be
+          s5 <- getWord64be
+          s6 <- getWord64be
+          s7 <- getWord64be
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord64N16Big = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64be
+          s1 <- getWord64be
+          s2 <- getWord64be
+          s3 <- getWord64be
+          s4 <- getWord64be
+          s5 <- getWord64be
+          s6 <- getWord64be
+          s7 <- getWord64be
+          s8 <- getWord64be
+          s9 <- getWord64be
+          s10 <- getWord64be
+          s11 <- getWord64be
+          s12 <- getWord64be
+          s13 <- getWord64be
+          s14 <- getWord64be
+          s15 <- getWord64be
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord64N1Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64le
+          loop (s+s0) (n-1)
+
+getWord64N2Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64le
+          s1 <- getWord64le
+          loop (s+s0+s1) (n-2)
+
+getWord64N4Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64le
+          s1 <- getWord64le
+          s2 <- getWord64le
+          s3 <- getWord64le
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord64N8Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64le
+          s1 <- getWord64le
+          s2 <- getWord64le
+          s3 <- getWord64le
+          s4 <- getWord64le
+          s5 <- getWord64le
+          s6 <- getWord64le
+          s7 <- getWord64le
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord64N16Little = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64le
+          s1 <- getWord64le
+          s2 <- getWord64le
+          s3 <- getWord64le
+          s4 <- getWord64le
+          s5 <- getWord64le
+          s6 <- getWord64le
+          s7 <- getWord64le
+          s8 <- getWord64le
+          s9 <- getWord64le
+          s10 <- getWord64le
+          s11 <- getWord64le
+          s12 <- getWord64le
+          s13 <- getWord64le
+          s14 <- getWord64le
+          s15 <- getWord64le
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
+
+------------------------------------------------------------------------
+
+getWord64N1Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64host
+          loop (s+s0) (n-1)
+
+getWord64N2Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64host
+          s1 <- getWord64host
+          loop (s+s0+s1) (n-2)
+
+getWord64N4Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64host
+          s1 <- getWord64host
+          s2 <- getWord64host
+          s3 <- getWord64host
+          loop (s+s0+s1+s2+s3) (n-4)
+
+getWord64N8Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64host
+          s1 <- getWord64host
+          s2 <- getWord64host
+          s3 <- getWord64host
+          s4 <- getWord64host
+          s5 <- getWord64host
+          s6 <- getWord64host
+          s7 <- getWord64host
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7) (n-8)
+
+getWord64N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop s 0 = return s
+        loop s n = do
+          s0 <- getWord64host
+          s1 <- getWord64host
+          s2 <- getWord64host
+          s3 <- getWord64host
+          s4 <- getWord64host
+          s5 <- getWord64host
+          s6 <- getWord64host
+          s7 <- getWord64host
+          s8 <- getWord64host
+          s9 <- getWord64host
+          s10 <- getWord64host
+          s11 <- getWord64host
+          s12 <- getWord64host
+          s13 <- getWord64host
+          s14 <- getWord64host
+          s15 <- getWord64host
+          loop (s+s0+s1+s2+s3+s4+s5+s6+s7+s9+s10+s11+s12+s13+s14+s15) (n-16)
diff --git a/benchmarks/Builder.hs b/benchmarks/Builder.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/Builder.hs
@@ -0,0 +1,196 @@
+{-# LANGUAGE CPP, ExistentialQuantification #-}
+
+#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
+#include "MachDeps.h"
+#endif
+
+module Main (main) where
+
+import Control.DeepSeq
+import Control.Exception (evaluate)
+import Control.Monad.Trans (liftIO)
+import Criterion.Config
+import Criterion.Main hiding (run)
+import qualified Data.ByteString as S
+import qualified Data.ByteString.Char8 as C
+import qualified Data.ByteString.Lazy as L
+import Data.Char (ord)
+import Data.Monoid (Monoid(mappend, mempty))
+import Data.Word (Word8)
+
+import Data.Binary.Builder
+
+instance NFData S.ByteString
+
+data B = forall a. NFData a => B a
+
+instance NFData B where
+    rnf (B b) = rnf b
+
+main :: IO ()
+main = defaultMainWith defaultConfig
+    (liftIO . evaluate $ rnf [B word8s, B smallByteString, B largeByteString])
+    [ -- Test GHC loop optimization of continuation based code.
+      bench "[Word8]" $ whnf (run . fromWord8s) word8s
+
+      -- Test bounds check merging
+    , bench "bounds/[Word8]" $ whnf (run . from4Word8s) word8s
+
+    , bench "small ByteString" $ whnf (run . fromByteString) smallByteString
+    , bench "large ByteString" $ whnf (run . fromByteString) largeByteString
+    , bench "length-prefixed ByteString" $ whnf (run . lengthPrefixedBS)
+      smallByteString
+
+    , bgroup "Host endian"
+      [ bench "1MB of Word8 in chunks of 16" $ whnf (run . putWord8N16) n
+      , bench "1MB of Word16 in chunks of 16" $ whnf (run . putWord16N16Host)
+        (n `div` 2)
+      , bench "1MB of Word32 in chunks of 16" $ whnf (run . putWord32N16Host)
+        (n `div` 4)
+      , bench "1MB of Word64 in chunks of 16" $ whnf (run . putWord64N16Host)
+        (n `div` 8)
+      ]
+    ]
+  where
+    run = L.length . toLazyByteString
+    n = 1 * (2 ^ (20 :: Int))  -- one MB
+
+-- Input data
+
+word8s :: [Word8]
+word8s = replicate 10000 $ fromIntegral $ ord 'a'
+{-# NOINLINE word8s #-}
+
+smallByteString :: S.ByteString
+smallByteString = C.pack "abcdefghi"
+
+largeByteString :: S.ByteString
+largeByteString = S.pack word8s
+
+------------------------------------------------------------------------
+-- Benchmarks
+
+fromWord8s :: [Word8] -> Builder
+fromWord8s [] = mempty
+fromWord8s (x:xs) = singleton x <> fromWord8s xs
+
+from4Word8s :: [Word8] -> Builder
+from4Word8s [] = mempty
+from4Word8s (x:xs) = singleton x <> singleton x <> singleton x <> singleton x <>
+                     from4Word8s xs
+
+-- Write 100 short, length-prefixed ByteStrings.
+lengthPrefixedBS :: S.ByteString -> Builder
+lengthPrefixedBS bs = loop 100
+  where loop n | n `seq` False = undefined
+        loop 0 = mempty
+        loop n =
+#if WORD_SIZE_IN_BITS == 32
+            putWord32be (fromIntegral $ S.length bs) <>
+#elif WORD_SIZE_IN_BITS == 64
+            putWord64be (fromIntegral $ S.length bs) <>
+#else
+# error Unsupported platform
+#endif
+            fromByteString bs <>
+            loop (n-1)
+
+putWord8N16 :: Int -> Builder
+putWord8N16 = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = mempty
+        loop s n =
+          singleton (s+0) <>
+          singleton (s+1) <>
+          singleton (s+2) <>
+          singleton (s+3) <>
+          singleton (s+4) <>
+          singleton (s+5) <>
+          singleton (s+6) <>
+          singleton (s+7) <>
+          singleton (s+8) <>
+          singleton (s+9) <>
+          singleton (s+10) <>
+          singleton (s+11) <>
+          singleton (s+12) <>
+          singleton (s+13) <>
+          singleton (s+14) <>
+          singleton (s+15) <>
+          loop (s+16) (n-16)
+
+putWord16N16Host :: Int -> Builder
+putWord16N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = mempty
+        loop s n =
+          putWord16host (s+0) <>
+          putWord16host (s+1) <>
+          putWord16host (s+2) <>
+          putWord16host (s+3) <>
+          putWord16host (s+4) <>
+          putWord16host (s+5) <>
+          putWord16host (s+6) <>
+          putWord16host (s+7) <>
+          putWord16host (s+8) <>
+          putWord16host (s+9) <>
+          putWord16host (s+10) <>
+          putWord16host (s+11) <>
+          putWord16host (s+12) <>
+          putWord16host (s+13) <>
+          putWord16host (s+14) <>
+          putWord16host (s+15) <>
+          loop (s+16) (n-16)
+
+putWord32N16Host :: Int -> Builder
+putWord32N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = mempty
+        loop s n =
+          putWord32host (s+0) <>
+          putWord32host (s+1) <>
+          putWord32host (s+2) <>
+          putWord32host (s+3) <>
+          putWord32host (s+4) <>
+          putWord32host (s+5) <>
+          putWord32host (s+6) <>
+          putWord32host (s+7) <>
+          putWord32host (s+8) <>
+          putWord32host (s+9) <>
+          putWord32host (s+10) <>
+          putWord32host (s+11) <>
+          putWord32host (s+12) <>
+          putWord32host (s+13) <>
+          putWord32host (s+14) <>
+          putWord32host (s+15) <>
+          loop (s+16) (n-16)
+
+putWord64N16Host :: Int -> Builder
+putWord64N16Host = loop 0
+  where loop s n | s `seq` n `seq` False = undefined
+        loop _ 0 = mempty
+        loop s n =
+          putWord64host (s+0) <>
+          putWord64host (s+1) <>
+          putWord64host (s+2) <>
+          putWord64host (s+3) <>
+          putWord64host (s+4) <>
+          putWord64host (s+5) <>
+          putWord64host (s+6) <>
+          putWord64host (s+7) <>
+          putWord64host (s+8) <>
+          putWord64host (s+9) <>
+          putWord64host (s+10) <>
+          putWord64host (s+11) <>
+          putWord64host (s+12) <>
+          putWord64host (s+13) <>
+          putWord64host (s+14) <>
+          putWord64host (s+15) <>
+          loop (s+16) (n-16)
+
+------------------------------------------------------------------------
+-- Utilities
+
+infixr 6 <>
+
+(<>) :: Monoid m => m -> m -> m
+(<>) = mappend
diff --git a/benchmarks/CBenchmark.c b/benchmarks/CBenchmark.c
new file mode 100644
--- /dev/null
+++ b/benchmarks/CBenchmark.c
@@ -0,0 +1,39 @@
+#include "CBenchmark.h"
+
+void bytewrite(unsigned char *a, int bytes) {
+  unsigned char n = 0;
+  int i = 0;
+  int iterations = bytes;
+  while (i < iterations) {
+    a[i++] = n++;
+  }
+}
+
+unsigned char byteread(unsigned char *a, int bytes) {
+  unsigned char n = 0;
+  int i = 0;
+  int iterations = bytes;
+  while (i < iterations) {
+    n += a[i++];
+  }
+  return n;
+}
+
+void wordwrite(unsigned long *a, int bytes) {
+  unsigned long n = 0;
+  int i = 0;
+  int iterations = bytes / sizeof(unsigned long) ;
+  while (i < iterations) {
+    a[i++] = n++;
+  }
+}
+
+unsigned int wordread(unsigned long *a, int bytes) {
+  unsigned long n = 0;
+  int i = 0;
+  int iterations = bytes / sizeof(unsigned long);
+  while (i < iterations) {
+    n += a[i++];
+  }
+  return n;
+}
diff --git a/benchmarks/CBenchmark.h b/benchmarks/CBenchmark.h
new file mode 100644
--- /dev/null
+++ b/benchmarks/CBenchmark.h
@@ -0,0 +1,4 @@
+void bytewrite(unsigned char *a, int bytes);
+unsigned char byteread(unsigned char *a, int bytes);
+void wordwrite(unsigned long *a, int bytes);
+unsigned int wordread(unsigned long *a, int bytes);
diff --git a/benchmarks/Makefile b/benchmarks/Makefile
new file mode 100644
--- /dev/null
+++ b/benchmarks/Makefile
@@ -0,0 +1,23 @@
+ghc := ghc
+ghc-flags :=
+programs := builder bench
+
+.PHONY: all
+all: $(programs)
+
+builder: Builder.hs
+	$(ghc) $(ghc-flags) --make -O2 Builder.hs -o $@ -fforce-recomp -i../src
+
+bench: Benchmark.hs MemBench.hs CBenchmark.o
+	$(ghc) $(ghc-flags) --make -O2 -fliberate-case-threshold=1000 -fasm Benchmark.hs CBenchmark.o -o $@ -fforce-recomp -i../src
+
+.PHONY: run-bench
+run-bench: bench
+	./bench 100
+
+CBenchmark.o: CBenchmark.c
+	$(ghc) -c -optc -O3 $< -o $@
+
+.PHONY: clean
+clean:
+	rm -f *.o *.hi $(programs)
diff --git a/benchmarks/MemBench.hs b/benchmarks/MemBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/MemBench.hs
@@ -0,0 +1,85 @@
+{-# LANGUAGE ForeignFunctionInterface, BangPatterns #-}
+module MemBench (memBench) where
+
+import Foreign
+import Foreign.C
+
+import Control.Exception
+import System.CPUTime
+import Numeric
+
+memBench :: Int -> IO ()
+memBench mb = do
+  let bytes = mb * 2^20
+  allocaBytes bytes $ \ptr -> do
+    let bench label test = do
+          seconds <- time $ test (castPtr ptr) (fromIntegral bytes)
+          let throughput = fromIntegral mb / seconds
+          putStrLn $ show mb ++ "MB of " ++ label
+                  ++ " in " ++ showFFloat (Just 3) seconds "s, at: "
+                  ++ showFFloat (Just 1) throughput "MB/s"
+    bench "setup        " c_wordwrite
+    putStrLn ""
+    putStrLn "C memory throughput benchmarks:"
+    bench "bytes written" c_bytewrite
+    bench "bytes read   " c_byteread
+    bench "words written" c_wordwrite
+    bench "words read   " c_wordread
+    putStrLn ""
+    putStrLn "Haskell memory throughput benchmarks:"
+    bench "bytes written" hs_bytewrite
+    bench "bytes read   " hs_byteread
+    bench "words written" hs_wordwrite
+    bench "words read   " hs_wordread
+
+hs_bytewrite  :: Ptr CUChar -> Int -> IO ()
+hs_bytewrite !ptr bytes = loop 0 0
+  where iterations = bytes
+        loop :: Int -> CUChar -> IO ()
+        loop !i !n | i == iterations = return ()
+                   | otherwise = do pokeByteOff ptr i n
+                                    loop (i+1) (n+1)
+
+hs_byteread  :: Ptr CUChar -> Int -> IO CUChar
+hs_byteread !ptr bytes = loop 0 0
+  where iterations = bytes
+        loop :: Int -> CUChar -> IO CUChar
+        loop !i !n | i == iterations = return n
+                   | otherwise = do x <- peekByteOff ptr i
+                                    loop (i+1) (n+x)
+
+hs_wordwrite :: Ptr CULong -> Int -> IO ()
+hs_wordwrite !ptr bytes = loop 0 0
+  where iterations = bytes `div` sizeOf (undefined :: CULong)
+        loop :: Int -> CULong -> IO ()
+        loop !i !n | i == iterations = return ()
+                   | otherwise = do pokeByteOff ptr i n
+                                    loop (i+1) (n+1)
+
+hs_wordread  :: Ptr CULong -> Int -> IO CULong
+hs_wordread !ptr bytes = loop 0 0
+  where iterations = bytes `div` sizeOf (undefined :: CULong)
+        loop :: Int -> CULong -> IO CULong
+        loop !i !n | i == iterations = return n
+                   | otherwise = do x <- peekByteOff ptr i
+                                    loop (i+1) (n+x)
+
+
+foreign import ccall unsafe "CBenchmark.h byteread"
+  c_byteread :: Ptr CUChar -> CInt -> IO ()
+
+foreign import ccall unsafe "CBenchmark.h bytewrite"
+  c_bytewrite :: Ptr CUChar -> CInt -> IO ()
+
+foreign import ccall unsafe "CBenchmark.h wordread"
+  c_wordread :: Ptr CUInt -> CInt -> IO ()
+
+foreign import ccall unsafe "CBenchmark.h wordwrite"
+  c_wordwrite :: Ptr CUInt -> CInt -> IO ()
+
+time :: IO a -> IO Double
+time action = do
+    start <- getCPUTime
+    action
+    end   <- getCPUTime
+    return $! (fromIntegral (end - start)) / (10^12)
diff --git a/binary.cabal b/binary.cabal
--- a/binary.cabal
+++ b/binary.cabal
@@ -1,5 +1,5 @@
 name:            binary
-version:         0.5.1.0
+version:         0.5.1.1
 license:         BSD3
 license-file:    LICENSE
 author:          Lennart Kolmodin <kolmodin@gmail.com>
diff --git a/docs/hcar/binary-Lb.tex b/docs/hcar/binary-Lb.tex
new file mode 100644
--- /dev/null
+++ b/docs/hcar/binary-Lb.tex
@@ -0,0 +1,48 @@
+\begin{hcarentry}{binary}
+\label{binary}
+\report{Lennart Kolmodin}
+\status{active}
+\participants{Duncan Coutts, Don Stewart, Binary Strike Team}
+\makeheader
+
+The Binary Strike Team is pleased to announce yet a release of a new,
+pure, efficient binary serialisation library.
+
+The `binary' package provides efficient serialisation of Haskell values
+to and from lazy ByteStrings. ByteStrings constructed this way may then
+be written to disk, written to the network, or further processed (e.g.
+stored in memory directly, or compressed in memory with zlib or bzlib).
+
+The binary library has been heavily tuned for performance, particularly for
+writing speed. Throughput of up to 160M/s has been achieved in practice, and
+in general speed is on par or better than NewBinary, with the advantage of a
+pure interface. Efforts are underway to improve performance still further.
+Plans are also taking shape for a parser combinator library on top of
+binary, for bit parsing and foreign structure parsing (e.g. network
+protocols).
+
+Data.Derive~\cref{derive} has support for automatically generating Binary
+instances, allowing to read and write your data structures with little fuzz.
+
+Binary was developed by a team of 8 during the Haskell Hackathon in Oxford
+2007, and since then has about 15 people contributed code and many more
+given feedback and cheerleading on \verb|#haskell|.
+
+The package is cabalized and available through Hackage~\cref{hackagedb}.
+% to editors: ref. to cabal?
+
+\FurtherReading
+\begin{compactitem}
+\item Homepage
+
+  \url{http://code.haskell.org/binary/}
+\item Hackage
+
+  \url{http://hackage.haskell.org/cgi-bin/hackage-scripts/package/binary}
+\item Development version
+
+  \texttt{darcs get --partial}
+
+  \url{http://code.haskell.org/binary}
+\end{compactitem}
+\end{hcarentry}
diff --git a/src/Data/Binary.hs b/src/Data/Binary.hs
--- a/src/Data/Binary.hs
+++ b/src/Data/Binary.hs
@@ -8,7 +8,7 @@
 -- Copyright   : Lennart Kolmodin
 -- License     : BSD3-style (see LICENSE)
 -- 
--- Maintainer  : Lennart Kolmodin <kolmodin@dtek.chalmers.se>
+-- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
 -- Stability   : unstable
 -- Portability : portable to Hugs and GHC. Requires the FFI and some flexible instances
 --
diff --git a/src/Data/Binary/Builder.hs b/src/Data/Binary/Builder.hs
--- a/src/Data/Binary/Builder.hs
+++ b/src/Data/Binary/Builder.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 #if __GLASGOW_HASKELL__ >= 701
 {-# LANGUAGE Safe #-}
 #endif
@@ -7,7 +8,7 @@
 -- Copyright   : Lennart Kolmodin, Ross Paterson
 -- License     : BSD3-style (see LICENSE)
 -- 
--- Maintainer  : Lennart Kolmodin <kolmodin@dtek.chalmers.se>
+-- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
 -- Stability   : experimental
 -- Portability : portable to Hugs and GHC
 --
diff --git a/src/Data/Binary/Builder/Base.hs b/src/Data/Binary/Builder/Base.hs
--- a/src/Data/Binary/Builder/Base.hs
+++ b/src/Data/Binary/Builder/Base.hs
@@ -9,7 +9,7 @@
 -- Copyright   : Lennart Kolmodin, Ross Paterson
 -- License     : BSD3-style (see LICENSE)
 --
--- Maintainer  : Lennart Kolmodin <kolmodin@dtek.chalmers.se>
+-- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
 -- Stability   : experimental
 -- Portability : portable to Hugs and GHC
 --
diff --git a/src/Data/Binary/Builder/Internal.hs b/src/Data/Binary/Builder/Internal.hs
--- a/src/Data/Binary/Builder/Internal.hs
+++ b/src/Data/Binary/Builder/Internal.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 #if __GLASGOW_HASKELL__ >= 701
 {-# LANGUAGE Trustworthy #-}
 #endif
@@ -7,7 +8,7 @@
 -- Copyright   : Lennart Kolmodin, Ross Paterson
 -- License     : BSD3-style (see LICENSE)
 -- 
--- Maintainer  : Lennart Kolmodin <kolmodin@dtek.chalmers.se>
+-- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
 -- Stability   : experimental
 -- Portability : portable to Hugs and GHC
 --
diff --git a/src/Data/Binary/Get.hs b/src/Data/Binary/Get.hs
--- a/src/Data/Binary/Get.hs
+++ b/src/Data/Binary/Get.hs
@@ -10,7 +10,7 @@
 -- Copyright   : Lennart Kolmodin
 -- License     : BSD3-style (see LICENSE)
 -- 
--- Maintainer  : Lennart Kolmodin <kolmodin@dtek.chalmers.se>
+-- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
 -- Stability   : experimental
 -- Portability : portable to Hugs and GHC.
 --
diff --git a/src/Data/Binary/Put.hs b/src/Data/Binary/Put.hs
--- a/src/Data/Binary/Put.hs
+++ b/src/Data/Binary/Put.hs
@@ -9,7 +9,7 @@
 -- Copyright   : Lennart Kolmodin
 -- License     : BSD3-style (see LICENSE)
 -- 
--- Maintainer  : Lennart Kolmodin <kolmodin@dtek.chalmers.se>
+-- Maintainer  : Lennart Kolmodin <kolmodin@gmail.com>
 -- Stability   : stable
 -- Portability : Portable to Hugs and GHC. Requires MPTCs
 --
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,16 @@
+all: compiled
+
+interpreted:
+	runhaskell QC.hs 1000
+
+compiled:
+	ghc --make -fhpc -O QC.hs -o qc -threaded -package QuickCheck-1.2.0.1 -i../src
+	./qc 500
+
+hugs:
+	runhugs -98 QC.hs  
+
+clean:
+	rm -f *.o *.hi qc *.tix *~
+
+.PHONY: clean
diff --git a/tests/Parallel.hs b/tests/Parallel.hs
new file mode 100644
--- /dev/null
+++ b/tests/Parallel.hs
@@ -0,0 +1,147 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Test.QuickCheck.Parallel
+-- Copyright   :  (c) Don Stewart 2006
+-- License     :  BSD-style (see the file LICENSE)
+-- 
+-- Maintainer  :  dons@cse.unsw.edu.au
+-- Stability   :  experimental
+-- Portability :  non-portable (uses Control.Exception, Control.Concurrent)
+--
+-- A parallel batch driver for running QuickCheck on threaded or SMP systems.
+-- See the /Example.hs/ file for a complete overview.
+--
+
+module Parallel (
+    pRun,
+    pDet,
+    pNon
+  ) where
+
+import Test.QuickCheck
+import Data.List
+import Control.Concurrent
+import Control.Exception  hiding (evaluate)
+import System.Random
+import System.IO          (hFlush,stdout)
+import Text.Printf
+
+type Name   = String
+type Depth  = Int
+type Test   = (Name, Depth -> IO String)
+
+-- | Run a list of QuickCheck properties in parallel chunks, using
+-- 'n' Haskell threads (first argument), and test to a depth of 'd'
+-- (second argument). Compile your application with '-threaded' and run
+-- with the SMP runtime's '-N4' (or however many OS threads you want to
+-- donate), for best results.
+--
+-- > import Test.QuickCheck.Parallel
+-- >
+-- > do n <- getArgs >>= readIO . head
+-- >    pRun n 1000 [ ("sort1", pDet prop_sort1) ]
+--
+-- Will run 'n' threads over the property list, to depth 1000.
+--
+pRun :: Int -> Int -> [Test] -> IO ()
+pRun n depth tests = do
+    chan <- newChan
+    ps   <- getChanContents chan
+    work <- newMVar tests
+
+    forM_ [1..n] $ forkIO . thread work chan
+
+    let wait xs i
+            | i >= n     = return () -- done
+            | otherwise = case xs of
+                    Nothing : xs -> wait xs $! i+1
+                    Just s  : xs -> putStr s >> hFlush stdout >> wait xs i
+    wait ps 0
+
+  where
+    thread :: MVar [Test] -> Chan (Maybe String) -> Int -> IO ()
+    thread work chan me = loop
+      where
+        loop = do
+            job <- modifyMVar work $ \jobs -> return $ case jobs of
+                        []     -> ([], Nothing)
+                        (j:js) -> (js, Just j)
+            case job of
+                Nothing          -> writeChan chan Nothing -- done
+                Just (name,prop) -> do
+                    v <- prop depth
+                    writeChan chan . Just $ printf "%d: %-25s: %s" me name v
+                    loop
+
+
+-- | Wrap a property, and run it on a deterministic set of data
+pDet :: Testable a => a -> Int -> IO String
+pDet a n = mycheck Det defaultConfig
+    { configMaxTest = n
+    , configEvery   = \n args -> unlines args } a
+
+-- | Wrap a property, and run it on a non-deterministic set of data
+pNon :: Testable a => a -> Int -> IO String
+pNon a n = mycheck NonDet defaultConfig
+    { configMaxTest = n
+    , configEvery   = \n args -> unlines args } a
+
+data Mode = Det | NonDet
+
+------------------------------------------------------------------------
+
+mycheck :: Testable a => Mode -> Config -> a -> IO String
+mycheck Det config a = do
+     let rnd = mkStdGen 99  -- deterministic
+     mytests config (evaluate a) rnd 0 0 []
+
+mycheck NonDet config a = do
+    rnd <- newStdGen        -- different each run
+    mytests config (evaluate a) rnd 0 0 []
+
+mytests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO String
+mytests config gen rnd0 ntest nfail stamps
+  | ntest == configMaxTest config = do done "OK," ntest stamps
+  | nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps
+  | otherwise = do
+         case ok result of
+           Nothing    ->
+             mytests config gen rnd1 ntest (nfail+1) stamps
+           Just True  ->
+             mytests config gen rnd1 (ntest+1) nfail (stamp result:stamps)
+           Just False ->
+             return ( "Falsifiable after "
+                   ++ show ntest
+                   ++ " tests:\n"
+                   ++ unlines (arguments result)
+                    )
+     where
+      result      = generate (configSize config ntest) rnd2 gen
+      (rnd1,rnd2) = split rnd0
+
+done :: String -> Int -> [[String]] -> IO String
+done mesg ntest stamps =
+    return ( mesg ++ " " ++ show ntest ++ " tests" ++ table )
+  where
+    table = display
+        . map entry
+        . reverse
+        . sort
+        . map pairLength
+        . group
+        . sort
+        . filter (not . null)
+        $ stamps
+
+    display []  = ".\n"
+    display [x] = " (" ++ x ++ ").\n"
+    display xs  = ".\n" ++ unlines (map (++ ".") xs)
+
+    pairLength xss@(xs:_) = (length xss, xs)
+    entry (n, xs)         = percentage n ntest
+                          ++ " "
+                          ++ concat (intersperse ", " xs)
+
+    percentage n m        = show ((100 * n) `div` m) ++ "%"
+
+forM_ = flip mapM_
diff --git a/tests/QC.hs b/tests/QC.hs
new file mode 100644
--- /dev/null
+++ b/tests/QC.hs
@@ -0,0 +1,244 @@
+{-# OPTIONS_GHC -fglasgow-exts #-}
+module Main where
+
+import Data.Binary
+import Data.Binary.Put
+import Data.Binary.Get
+
+import Parallel
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Internal as B
+import qualified Data.ByteString.Unsafe as B
+import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy.Internal as L
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+import qualified Data.IntMap as IntMap
+import qualified Data.IntSet as IntSet
+
+import Data.Array (Array)
+import Data.Array.IArray
+import Data.Array.Unboxed (UArray)
+
+import qualified Control.OldException as C (catch,evaluate)
+import Control.Monad
+import Foreign
+import System.Environment
+import System.IO
+import System.IO.Unsafe
+
+import Test.QuickCheck hiding (test)
+import QuickCheckUtils
+import Text.Printf
+
+-- import qualified Data.Sequence as Seq
+
+------------------------------------------------------------------------
+
+roundTrip :: (Eq a, Binary a) => a -> (L.ByteString -> L.ByteString) -> Bool
+roundTrip a f = a ==
+    {-# SCC "decode.refragment.encode" #-} decode (f (encode a))
+
+roundTripWith put get x =
+    forAll positiveList $ \xs ->
+    x == runGet get (refragment xs (runPut (put x)))
+
+-- make sure that a test fails
+errorish :: B a
+errorish a = unsafePerformIO $
+    C.catch (do C.evaluate a
+                return False)
+            (\_ -> return True)
+
+-- low level ones:
+
+prop_Word16be = roundTripWith putWord16be getWord16be
+prop_Word16le = roundTripWith putWord16le getWord16le
+prop_Word16host = roundTripWith putWord16host getWord16host
+
+prop_Word32be = roundTripWith putWord32be getWord32be
+prop_Word32le = roundTripWith putWord32le getWord32le
+prop_Word32host = roundTripWith putWord32host getWord32host
+
+prop_Word64be = roundTripWith putWord64be getWord64be
+prop_Word64le = roundTripWith putWord64le getWord64le
+prop_Word64host = roundTripWith putWord64host getWord64host
+
+prop_Wordhost = roundTripWith putWordhost getWordhost
+
+-- read too much:
+
+prop_bookworm x = errorish $ x == a && x /= b
+  where
+    (a,b) = decode (encode x)
+
+-- sanity:
+
+invariant_lbs :: L.ByteString -> Bool
+invariant_lbs (L.Empty)      = True
+invariant_lbs (L.Chunk x xs) = not (B.null x) && invariant_lbs xs
+
+prop_invariant :: (Binary a) => a -> Bool
+prop_invariant = invariant_lbs . encode
+
+-- be lazy!
+
+-- doesn't do fair testing of lazy put/get.
+-- tons of untested cases
+
+-- lazyTrip :: (Binary a, Eq a) => a -> Property
+-- lazyTrip a = forAll positiveList $ \xs ->
+--     a == (runGet lazyGet . refragment xs . runPut . lazyPut $ a)
+
+-- refragment a lazy bytestring's chunks
+refragment :: [Int] -> L.ByteString -> L.ByteString
+refragment [] lps = lps
+refragment (x:xs) lps =
+    let x' = fromIntegral . (+1) . abs $ x
+        rest = refragment xs (L.drop x' lps) in
+    L.append (L.fromChunks [B.concat . L.toChunks . L.take x' $ lps]) rest
+
+-- check identity of refragmentation
+prop_refragment lps xs = lps == refragment xs lps
+
+-- check that refragmention still hold invariant
+prop_refragment_inv lps xs = invariant_lbs $ refragment xs lps
+
+main :: IO ()
+main = do
+    hSetBuffering stdout NoBuffering
+    s <- getArgs
+    let x = if null s then 100 else read (head s)
+    pRun 2 x tests
+
+{-
+run :: [(String, Int -> IO ())] -> IO ()
+run tests = do
+    x <- getArgs
+    let n = if null x then 100 else read . head $ x
+    mapM_ (\(s,a) -> printf "%-50s" s >> a n) tests
+-}
+
+------------------------------------------------------------------------
+
+type T a = a -> Property
+type B a = a -> Bool
+
+p       :: Testable a => a -> Int -> IO String
+p       = pNon
+
+test    :: (Eq a, Binary a) => a -> Property
+test a  = forAll positiveList (roundTrip a . refragment)
+
+positiveList :: Gen [Int]
+positiveList = fmap (filter (/=0) . map abs) $ arbitrary
+
+-- tests :: [(String, Int -> IO String)]
+tests =
+-- utils
+        [ ("refragment id",        p prop_refragment     )
+        , ("refragment invariant", p prop_refragment_inv )
+
+-- boundaries
+        , ("read to much",  p (prop_bookworm :: B Word8     ))
+
+-- Primitives
+        , ("Word16be",      p prop_Word16be)
+        , ("Word16le",      p prop_Word16le)
+        , ("Word16host",    p prop_Word16host)
+        , ("Word32be",      p prop_Word32be)
+        , ("Word32le",      p prop_Word32le)
+        , ("Word32host",    p prop_Word32host)
+        , ("Word64be",      p prop_Word64be)
+        , ("Word64le",      p prop_Word64le)
+        , ("Word64host",    p prop_Word64host)
+        , ("Wordhost",      p prop_Wordhost)
+
+-- higher level ones using the Binary class
+        ,("()",         p (test :: T ()                     ))
+        ,("Bool",       p (test :: T Bool                   ))
+        ,("Ordering",   p (test :: T Ordering               ))
+
+        ,("Word8",      p (test :: T Word8                  ))
+        ,("Word16",     p (test :: T Word16                 ))
+        ,("Word32",     p (test :: T Word32                 ))
+        ,("Word64",     p (test :: T Word64                 ))
+
+        ,("Int8",       p (test :: T Int8                   ))
+        ,("Int16",      p (test :: T Int16                  ))
+        ,("Int32",      p (test :: T Int32                  ))
+        ,("Int64",      p (test :: T Int64                  ))
+
+        ,("Word",       p (test :: T Word                   ))
+        ,("Int",        p (test :: T Int                    ))
+        ,("Integer",    p (test :: T Integer                ))
+
+        ,("Float",      p (test :: T Float                  ))
+        ,("Double",     p (test :: T Double                 ))
+
+        ,("Char",       p (test :: T Char                   ))
+
+        ,("[()]",       p (test :: T [()]                  ))
+        ,("[Word8]",    p (test :: T [Word8]               ))
+        ,("[Word32]",   p (test :: T [Word32]              ))
+        ,("[Word64]",   p (test :: T [Word64]              ))
+        ,("[Word]",     p (test :: T [Word]                ))
+        ,("[Int]",      p (test :: T [Int]                 ))
+        ,("[Integer]",  p (test :: T [Integer]             ))
+        ,("String",     p (test :: T String                ))
+
+        ,("((), ())",           p (test :: T ((), ())        ))
+        ,("(Word8, Word32)",    p (test :: T (Word8, Word32) ))
+        ,("(Int8, Int32)",      p (test :: T (Int8,  Int32)  ))
+        ,("(Int32, [Int])",     p (test :: T (Int32, [Int])  ))
+
+        ,("Maybe Int8",         p (test :: T (Maybe Int8)        ))
+        ,("Either Int8 Int16",  p (test :: T (Either Int8 Int16) ))
+
+        ,("(Maybe Word8, Bool, [Int], Either Bool Word8)",
+                p (test :: T (Maybe Word8, Bool, [Int], Either Bool Word8) ))
+
+        ,("(Int, ByteString)",        p (test     :: T (Int, B.ByteString)   ))
+--      ,("Lazy (Int, ByteString)",   p (lazyTrip :: T (Int, B.ByteString)   ))
+        ,("[(Int, ByteString)]",      p (test     :: T [(Int, B.ByteString)] ))
+--      ,("Lazy [(Int, ByteString)]", p (lazyTrip :: T [(Int, B.ByteString)] ))
+
+
+--      ,("Lazy IntMap",       p (lazyTrip  :: T IntSet.IntSet          ))
+        ,("IntSet",            p (test      :: T IntSet.IntSet          ))
+        ,("IntMap ByteString", p (test      :: T (IntMap.IntMap B.ByteString) ))
+
+        ,("B.ByteString",  p (test :: T B.ByteString        ))
+        ,("L.ByteString",  p (test :: T L.ByteString        ))
+
+        ,("B.ByteString invariant",   p (prop_invariant :: B B.ByteString                 ))
+        ,("[B.ByteString] invariant", p (prop_invariant :: B [B.ByteString]               ))
+        ,("L.ByteString invariant",   p (prop_invariant :: B L.ByteString                 ))
+        ,("[L.ByteString] invariant", p (prop_invariant :: B [L.ByteString]               ))
+        ,("IntMap invariant",         p (prop_invariant :: B (IntMap.IntMap B.ByteString) ))
+
+        ,("Set Word32",      p (test :: T (Set.Set Word32)      ))
+        ,("Map Word16 Int",  p (test :: T (Map.Map Word16 Int)  ))
+
+        ,("(Maybe Int64, Bool, [Int])", p (test :: T (Maybe Int64, Bool, [Int])))
+
+{-
+--
+-- Big tuples lack an Arbitrary instance in Hugs/QuickCheck
+--
+
+        ,("(Maybe Word16, Bool, [Int], Either Bool Word16, Int)",
+            p (test :: T (Maybe Word16, Bool, [Int], Either Bool Word16, Int) ))
+
+        ,("(Maybe Word32, Bool, [Int], Either Bool Word32, Int, Int)", p (roundTrip :: (Maybe Word32, Bool, [Int], Either Bool Word32, Int, Int) -> Bool))
+
+        ,("(Maybe Word64, Bool, [Int], Either Bool Word64, Int, Int, Int)", p (roundTrip :: (Maybe Word64, Bool, [Int], Either Bool Word64, Int, Int, Int) -> Bool))
+-}
+
+-- GHC only:
+--      ,("Sequence", p (roundTrip :: Seq.Seq Int64 -> Bool))
+
+-- Obsolete
+--      ,("ensureLeft/Fail", mytest (shouldFail (decode L.empty :: Either ParseError Int)))
+        ]
diff --git a/tests/QuickCheckUtils.hs b/tests/QuickCheckUtils.hs
new file mode 100644
--- /dev/null
+++ b/tests/QuickCheckUtils.hs
@@ -0,0 +1,258 @@
+{-# OPTIONS_GHC -fglasgow-exts #-}
+--
+-- Uses multi-param type classes
+--
+module QuickCheckUtils where
+
+import Control.Monad
+
+import Test.QuickCheck.Batch
+import Test.QuickCheck
+import Text.Show.Functions
+
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Unsafe as B
+import qualified Data.ByteString.Internal as B
+import qualified Data.ByteString.Lazy as L
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+import qualified Data.IntMap as IntMap
+import qualified Data.IntSet as IntSet
+
+import qualified Control.Exception as C (evaluate)
+
+import Control.Monad        ( liftM2 )
+import Data.Char
+import Data.List
+import Data.Word
+import Data.Int
+import System.Random
+import System.IO
+
+-- import Control.Concurrent
+import System.Mem
+import System.CPUTime
+import Text.Printf
+
+import qualified Data.ByteString      as P
+import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy.Internal as L
+
+-- import qualified Data.Sequence as Seq
+
+-- Enable this to get verbose test output. Including the actual tests.
+debug = False
+
+mytest :: Testable a => a -> Int -> IO ()
+mytest a n = mycheck defaultConfig
+    { configMaxTest=n
+    , configEvery= \n args -> if debug then show n ++ ":\n" ++ unlines args else [] } a
+
+mycheck :: Testable a => Config -> a -> IO ()
+mycheck config a = do
+     rnd <- newStdGen
+     performGC -- >> threadDelay 100
+     t <- mytests config (evaluate a) rnd 0 0 [] 0 -- 0
+     printf " %0.3f seconds\n" (t :: Double)
+     hFlush stdout
+
+time :: a -> IO (a , Double)
+time a = do
+    start <- getCPUTime
+    v     <- C.evaluate a
+    v `seq` return ()
+    end   <- getCPUTime
+    return (v,     (      (fromIntegral (end - start)) / (10^12)))
+
+mytests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> Double -> IO  Double
+mytests config gen rnd0 ntest nfail stamps t0
+  | ntest == configMaxTest config = do done "OK," ntest stamps
+                                       return t0
+
+  | nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps
+                                       return t0
+
+  | otherwise = do
+     (result,t1) <- time (generate (configSize config ntest) rnd2 gen)
+
+     putStr (configEvery config ntest (arguments result)) >> hFlush stdout
+     case ok result of
+       Nothing    ->
+         mytests config gen rnd1 ntest (nfail+1) stamps (t0 + t1)
+       Just True  ->
+         mytests config gen rnd1 (ntest+1) nfail (stamp result:stamps) (t0 + t1)
+       Just False -> do
+         putStr ( "Falsifiable after "
+               ++ show ntest
+               ++ " tests:\n"
+               ++ unlines (arguments result)
+                ) >> hFlush stdout
+         return t0
+
+     where
+      (rnd1,rnd2) = split rnd0
+
+done :: String -> Int -> [[String]] -> IO ()
+done mesg ntest stamps = putStr ( mesg ++ " " ++ show ntest ++ " tests" ++ table )
+ where
+  table = display
+        . map entry
+        . reverse
+        . sort
+        . map pairLength
+        . group
+        . sort
+        . filter (not . null)
+        $ stamps
+
+  display []  = ". "
+  display [x] = " (" ++ x ++ "). "
+  display xs  = ".\n" ++ unlines (map (++ ".") xs)
+
+  pairLength xss@(xs:_) = (length xss, xs)
+  entry (n, xs)         = percentage n ntest
+                       ++ " "
+                       ++ concat (intersperse ", " xs)
+
+  percentage n m        = show ((100 * n) `div` m) ++ "%"
+
+------------------------------------------------------------------------
+
+instance Random Word8 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Int8 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Word16 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Int16 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Word where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Word32 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Int32 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Word64 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+instance Random Int64 where
+  randomR = integralRandomR
+  random = randomR (minBound,maxBound)
+
+------------------------------------------------------------------------
+
+integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)
+integralRandomR  (a,b) g = case randomR (fromIntegral a :: Integer,
+                                         fromIntegral b :: Integer) g of
+                            (x,g) -> (fromIntegral x, g)
+
+------------------------------------------------------------------------
+
+instance Arbitrary Word8 where
+    arbitrary       = choose (0, 2^8-1)
+    coarbitrary w   = variant 0
+
+instance Arbitrary Word16 where
+    arbitrary       = choose (0, 2^16-1)
+    coarbitrary     = undefined
+
+instance Arbitrary Word32 where
+--  arbitrary       = choose (0, 2^32-1)
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary     = undefined
+
+instance Arbitrary Word64 where
+--  arbitrary       = choose (0, 2^64-1)
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary     = undefined
+
+instance Arbitrary Int8 where
+--  arbitrary       = choose (0, 2^8-1)
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary w   = variant 0
+
+instance Arbitrary Int16 where
+--  arbitrary       = choose (0, 2^16-1)
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary     = undefined
+
+instance Arbitrary Int32 where
+--  arbitrary       = choose (0, 2^32-1)
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary     = undefined
+
+instance Arbitrary Int64 where
+--  arbitrary       = choose (0, 2^64-1)
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary     = undefined
+
+instance Arbitrary Word where
+    arbitrary       = choose (minBound, maxBound)
+    coarbitrary w   = variant 0
+
+------------------------------------------------------------------------
+
+instance Arbitrary Char where
+    arbitrary = choose (maxBound, minBound)
+    coarbitrary = undefined
+
+{-
+instance Arbitrary a => Arbitrary (Maybe a) where
+    arbitrary = oneof [ return Nothing, liftM Just arbitrary]
+    coarbitrary = undefined
+    -}
+
+instance Arbitrary Ordering where
+    arbitrary = oneof [ return LT,return  GT,return  EQ ]
+    coarbitrary = undefined
+
+{-
+instance (Arbitrary a, Arbitrary b) => Arbitrary (Either a b) where
+    arbitrary = oneof [ liftM Left arbitrary, liftM Right arbitrary]
+    coarbitrary = undefined
+    -}
+
+instance Arbitrary IntSet.IntSet where
+    arbitrary = fmap IntSet.fromList arbitrary
+    coarbitrary = undefined
+
+instance (Arbitrary e) => Arbitrary (IntMap.IntMap e) where
+    arbitrary = fmap IntMap.fromList arbitrary
+    coarbitrary = undefined
+
+instance (Arbitrary a, Ord a) => Arbitrary (Set.Set a) where
+    arbitrary = fmap Set.fromList arbitrary
+    coarbitrary = undefined
+
+instance (Arbitrary a, Ord a, Arbitrary b) => Arbitrary (Map.Map a b) where
+    arbitrary = fmap Map.fromList arbitrary
+    coarbitrary = undefined
+
+{-
+instance (Arbitrary a) => Arbitrary (Seq.Seq a) where
+    arbitrary = fmap Seq.fromList arbitrary
+    coarbitrary = undefined
+-}
+
+instance Arbitrary L.ByteString where
+    arbitrary     = arbitrary >>= return . L.fromChunks . filter (not. B.null) -- maintain the invariant.
+    coarbitrary s = coarbitrary (L.unpack s)
+
+instance Arbitrary B.ByteString where
+  arbitrary = B.pack `fmap` arbitrary
+  coarbitrary s = coarbitrary (B.unpack s)
diff --git a/tools/derive/BinaryDerive.hs b/tools/derive/BinaryDerive.hs
new file mode 100644
--- /dev/null
+++ b/tools/derive/BinaryDerive.hs
@@ -0,0 +1,57 @@
+{-# OPTIONS -fglasgow-exts #-}
+
+module BinaryDerive where
+
+import Data.Generics
+import Data.List
+
+deriveM ::  (Typeable a, Data a) => a -> IO ()
+deriveM (a :: a) = mapM_ putStrLn . lines $ derive (undefined :: a)
+
+derive :: (Typeable a, Data a) => a -> String
+derive x = 
+    "instance " ++ context ++ "Binary " ++ inst ++ " where\n" ++
+    concat putDefs ++ getDefs
+    where
+    context
+        | nTypeChildren > 0 =
+            wrap (join ", " (map ("Binary "++) typeLetters)) ++ " => "
+        | otherwise = ""
+    inst = wrap $ tyConString typeName ++ concatMap (" "++) typeLetters
+    wrap x = if nTypeChildren > 0 then "("++x++")" else x 
+    join sep lst = concat $ intersperse sep lst
+    nTypeChildren = length typeChildren
+    typeLetters = take nTypeChildren manyLetters
+    manyLetters = map (:[]) ['a'..'z']
+    (typeName,typeChildren) = splitTyConApp (typeOf x)
+    constrs :: [(Int, (String, Int))]
+    constrs = zip [0..] $ map gen $ dataTypeConstrs (dataTypeOf x)
+    gen con = ( showConstr con
+              , length $ gmapQ undefined $ fromConstr con `asTypeOf` x
+              )
+    putDefs = map ((++"\n") . putDef) constrs
+    putDef (n, (name, ps)) =
+        let wrap = if ps /= 0 then ("("++) . (++")") else id
+            pattern = name ++ concatMap (' ':) (take ps manyLetters)
+        in
+        "  put " ++ wrap pattern ++" = "
+        ++ concat [ "putWord8 " ++ show n | length constrs  > 1 ]
+        ++ concat [ " >> "                | length constrs  > 1 && ps  > 0 ]
+        ++ concat [ "return ()"           | length constrs == 1 && ps == 0 ]
+        ++ join " >> " (map ("put "++) (take ps manyLetters))
+    getDefs =
+       (if length constrs > 1
+            then "  get = do\n    tag_ <- getWord8\n    case tag_ of\n"
+            else "  get =")
+        ++ concatMap ((++"\n")) (map getDef constrs) ++
+       (if length constrs > 1
+	    then "      _ -> fail \"no parse\""
+	    else ""
+       )
+    getDef (n, (name, ps)) =
+        let wrap = if ps /= 0 then ("("++) . (++")") else id
+        in
+        concat [ "      " ++ show n ++ " ->" | length constrs > 1 ]
+        ++ concatMap (\x -> " get >>= \\"++x++" ->") (take ps manyLetters)
+        ++ " return "
+        ++ wrap (name ++ concatMap (" "++) (take ps manyLetters))
diff --git a/tools/derive/Example.hs b/tools/derive/Example.hs
new file mode 100644
--- /dev/null
+++ b/tools/derive/Example.hs
@@ -0,0 +1,68 @@
+
+import Data.Generics
+
+import Data.Binary
+
+import BinaryDerive
+
+data Foo = Bar
+    deriving (Typeable, Data, Show, Eq)
+
+instance Binary Main.Foo where
+  put Bar = return ()
+  get = return Bar
+
+data Color = RGB Int Int Int
+           | CMYK Int Int Int Int
+    deriving (Typeable, Data, Show, Eq)
+
+instance Binary Main.Color where
+  put (RGB a b c) = putWord8 0 >> put a >> put b >> put c
+  put (CMYK a b c d) = putWord8 1 >> put a >> put b >> put c >> put d
+  get = do
+    tag_ <- getWord8
+    case tag_ of
+      0 -> get >>= \a -> get >>= \b -> get >>= \c -> return (RGB a b c)
+      1 -> get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> return (CMYK a b c d)
+
+data Computer = Laptop { weight :: Int }
+              | Desktop { speed :: Int, memory :: Int }
+    deriving (Typeable, Data, Show, Eq)
+
+instance Binary Main.Computer where
+  put (Laptop a) = putWord8 0 >> put a
+  put (Desktop a b) = putWord8 1 >> put a >> put b
+  get = do
+    tag_ <- getWord8
+    case tag_ of
+      0 -> get >>= \a -> return (Laptop a)
+      1 -> get >>= \a -> get >>= \b -> return (Desktop a b)
+
+-- | All drinks mankind will ever need
+data Drinks = Beer Bool{-ale?-}
+            | Coffee
+            | Tea
+            | EnergyDrink
+            | Water
+            | Wine
+            | Whisky
+    deriving (Typeable, Data, Show, Eq)
+
+instance Binary Main.Drinks where
+  put (Beer a) = putWord8 0 >> put a
+  put Coffee = putWord8 1
+  put Tea = putWord8 2
+  put EnergyDrink = putWord8 3
+  put Water = putWord8 4
+  put Wine = putWord8 5
+  put Whisky = putWord8 6
+  get = do
+    tag_ <- getWord8
+    case tag_ of
+      0 -> get >>= \a -> return (Beer a)
+      1 -> return Coffee
+      2 -> return Tea
+      3 -> return EnergyDrink
+      4 -> return Water
+      5 -> return Wine
+      6 -> return Whisky
