diff --git a/benchmark/Benchmark.hs b/benchmark/Benchmark.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Benchmark.hs
@@ -0,0 +1,5 @@
+import qualified Criterion.Main
+import qualified OctaneBench
+
+main :: IO ()
+main = Criterion.Main.defaultMain [OctaneBench.benchmarks]
diff --git a/benchmark/Octane/MainBench.hs b/benchmark/Octane/MainBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/MainBench.hs
@@ -0,0 +1,8 @@
+module Octane.MainBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Main"
+    [
+    ]
diff --git a/benchmark/Octane/Type/ActorBench.hs b/benchmark/Octane/Type/ActorBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/ActorBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.ActorBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Actor"
+    [
+    ]
diff --git a/benchmark/Octane/Type/CacheItemBench.hs b/benchmark/Octane/Type/CacheItemBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/CacheItemBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.CacheItemBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "CacheItem"
+    [
+    ]
diff --git a/benchmark/Octane/Type/CachePropertyBench.hs b/benchmark/Octane/Type/CachePropertyBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/CachePropertyBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.CachePropertyBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "CacheProperty"
+    [
+    ]
diff --git a/benchmark/Octane/Type/KeyFrameBench.hs b/benchmark/Octane/Type/KeyFrameBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/KeyFrameBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.KeyFrameBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "KeyFrame"
+    [
+    ]
diff --git a/benchmark/Octane/Type/MarkBench.hs b/benchmark/Octane/Type/MarkBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/MarkBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.MarkBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Mark"
+    [
+    ]
diff --git a/benchmark/Octane/Type/MessageBench.hs b/benchmark/Octane/Type/MessageBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/MessageBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.MessageBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Message"
+    [
+    ]
diff --git a/benchmark/Octane/Type/Primitive/BooleanBench.hs b/benchmark/Octane/Type/Primitive/BooleanBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/BooleanBench.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.BooleanBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Boolean"
+    [ bench "decode basic" (whnf decodeBoolean "\0")
+    , bench "encode basic" (whnf Binary.encode (NewBoolean False))
+    ]
+
+decodeBoolean :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Boolean)
+decodeBoolean = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/Primitive/DictionaryBench.hs b/benchmark/Octane/Type/Primitive/DictionaryBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/DictionaryBench.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.DictionaryBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.Map as Map
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Dictionary"
+    [ bench "decode basic" (whnf decodeBooleanDictionary "\5\0\0\0None\0")
+    , bench "encode basic" (whnf Binary.encode (NewDictionary Map.empty :: Dictionary Boolean))
+    ]
+
+decodeDictionary :: (Binary.Binary a) => BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Dictionary a)
+decodeDictionary = Binary.decodeOrFail
+
+decodeBooleanDictionary :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Dictionary Boolean)
+decodeBooleanDictionary = decodeDictionary
diff --git a/benchmark/Octane/Type/Primitive/Float32LEBench.hs b/benchmark/Octane/Type/Primitive/Float32LEBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/Float32LEBench.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.Float32LEBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Float32LE"
+    [ bench "decode basic" (whnf decodeFloat32LE "\0\0\0\0")
+    , bench "encode basic" (whnf Binary.encode (NewFloat32LE 0.0))
+    ]
+
+decodeFloat32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Float32LE)
+decodeFloat32LE = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/Primitive/Int32LEBench.hs b/benchmark/Octane/Type/Primitive/Int32LEBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/Int32LEBench.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.Int32LEBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Int32LE"
+    [ bench "decode basic" (whnf decodeInt32LE "\0\0\0\0")
+    , bench "encode basic" (whnf Binary.encode (NewInt32LE 0))
+    ]
+
+decodeInt32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Int32LE)
+decodeInt32LE = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/Primitive/Int64LEBench.hs b/benchmark/Octane/Type/Primitive/Int64LEBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/Int64LEBench.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.Int64LEBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Int64LE"
+    [ bench "decode basic" (whnf decodeInt64LE "\0\0\0\0")
+    , bench "encode basic" (whnf Binary.encode (NewInt64LE 0))
+    ]
+
+decodeInt64LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Int64LE)
+decodeInt64LE = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/Primitive/ListBench.hs b/benchmark/Octane/Type/Primitive/ListBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/ListBench.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.ListBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "List"
+    [ bench "decode basic" (whnf decodeBooleanList "\0\0\0\0")
+    , bench "encode basic" (whnf Binary.encode (NewList [] :: List Boolean))
+    ]
+
+decodeList :: (Binary.Binary a) => BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, List a)
+decodeList = Binary.decodeOrFail
+
+decodeBooleanList :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, List Boolean)
+decodeBooleanList = decodeList
diff --git a/benchmark/Octane/Type/Primitive/PCStringBench.hs b/benchmark/Octane/Type/Primitive/PCStringBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/PCStringBench.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.PCStringBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "PCString"
+    [ bench "decode basic" (whnf decodePCString "\1\0\0\0\0")
+    , bench "encode basic" (whnf Binary.encode (NewPCString ""))
+    ]
+
+decodePCString :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, PCString)
+decodePCString = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/PrimitiveBench.hs b/benchmark/Octane/Type/PrimitiveBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/PrimitiveBench.hs
@@ -0,0 +1,21 @@
+module Octane.Type.PrimitiveBench (benchmarks) where
+
+import Criterion
+import qualified Octane.Type.Primitive.BooleanBench
+import qualified Octane.Type.Primitive.DictionaryBench
+import qualified Octane.Type.Primitive.Float32LEBench
+import qualified Octane.Type.Primitive.Int32LEBench
+import qualified Octane.Type.Primitive.Int64LEBench
+import qualified Octane.Type.Primitive.ListBench
+import qualified Octane.Type.Primitive.PCStringBench
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Primitive"
+    [ Octane.Type.Primitive.BooleanBench.benchmarks
+    , Octane.Type.Primitive.DictionaryBench.benchmarks
+    , Octane.Type.Primitive.Float32LEBench.benchmarks
+    , Octane.Type.Primitive.Int32LEBench.benchmarks
+    , Octane.Type.Primitive.Int64LEBench.benchmarks
+    , Octane.Type.Primitive.ListBench.benchmarks
+    , Octane.Type.Primitive.PCStringBench.benchmarks
+    ]
diff --git a/benchmark/Octane/Type/PropertyBench.hs b/benchmark/Octane/Type/PropertyBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/PropertyBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.PropertyBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Property"
+    [
+    ]
diff --git a/benchmark/Octane/Type/ReplayBench.hs b/benchmark/Octane/Type/ReplayBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/ReplayBench.hs
@@ -0,0 +1,8 @@
+module Octane.Type.ReplayBench (benchmarks) where
+
+import Criterion
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Replay"
+    [
+    ]
diff --git a/benchmark/Octane/TypeBench.hs b/benchmark/Octane/TypeBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/TypeBench.hs
@@ -0,0 +1,25 @@
+module Octane.TypeBench (benchmarks) where
+
+import Criterion
+import qualified Octane.Type.ActorBench
+import qualified Octane.Type.CacheItemBench
+import qualified Octane.Type.CachePropertyBench
+import qualified Octane.Type.KeyFrameBench
+import qualified Octane.Type.MarkBench
+import qualified Octane.Type.MessageBench
+import qualified Octane.Type.PrimitiveBench
+import qualified Octane.Type.PropertyBench
+import qualified Octane.Type.ReplayBench
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Type"
+    [ Octane.Type.ActorBench.benchmarks
+    , Octane.Type.CacheItemBench.benchmarks
+    , Octane.Type.CachePropertyBench.benchmarks
+    , Octane.Type.KeyFrameBench.benchmarks
+    , Octane.Type.MarkBench.benchmarks
+    , Octane.Type.MessageBench.benchmarks
+    , Octane.Type.PrimitiveBench.benchmarks
+    , Octane.Type.PropertyBench.benchmarks
+    , Octane.Type.ReplayBench.benchmarks
+    ]
diff --git a/benchmark/OctaneBench.hs b/benchmark/OctaneBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/OctaneBench.hs
@@ -0,0 +1,11 @@
+module OctaneBench (benchmarks) where
+
+import Criterion
+import qualified Octane.MainBench
+import qualified Octane.TypeBench
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Octane"
+    [ Octane.MainBench.benchmarks
+    , Octane.TypeBench.benchmarks
+    ]
diff --git a/library/Octane/Main.hs b/library/Octane/Main.hs
--- a/library/Octane/Main.hs
+++ b/library/Octane/Main.hs
@@ -2,7 +2,6 @@
 
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Lazy as BSL
-import qualified Data.IntMap as IntMap
 import qualified Data.Map as Map
 import Octane.Core
 import Octane.Type
@@ -105,11 +104,6 @@
         putStrLn ""
 
         putStrLn "# OBJECTS #\n"
-        mapM_
-            (\ (index, object) -> do
-                putStrLn (show index ++ "\t=> " ++ show (getPCString object)))
-            (IntMap.assocs (getObjectMap (replayObjectMap replay)))
-        putStrLn ""
 
         putStrLn "# NAMES #\n"
         mapM_
@@ -119,29 +113,8 @@
         putStrLn ""
 
         putStrLn "# ACTORS #\n"
-        mapM_
-            (\ (index, actor) -> do
-                putStrLn (show index ++ "\t=> " ++ show (getPCString actor)))
-            (IntMap.assocs (getActorMap (replayActorMap replay)))
-        putStrLn ""
 
         putStrLn "# CACHE #\n"
-        mapM_
-            (\ cacheItem -> do
-                let a = cacheItem & cacheItemTag & getInt32LE & fromIntegral
-                let b = replay & replayObjectMap & getObjectMap & IntMap.lookup a & fmap getPCString
-                putStrLn ("ID:\t" ++ show a ++ " (" ++ show b ++ ")")
-                putStrLn ("Start:\t" ++ show (getInt32LE (cacheItemStart cacheItem)))
-                putStrLn ("End:\t" ++ show (getInt32LE (cacheItemEnd cacheItem)))
-                putStrLn "Properties:"
-                mapM_
-                    (\ cacheProperty -> do
-                        let c = cacheProperty & cachePropertyIndex & getInt32LE & fromIntegral
-                        let d = replay & replayObjectMap & getObjectMap & IntMap.lookup c & fmap getPCString
-                        putStrLn ("- " ++ show (getInt32LE (cachePropertyTag cacheProperty)) ++ "\t=> " ++ show c ++ " (" ++ show d ++ ")"))
-                    (getList (cacheItemCacheProperties cacheItem))
-                putStrLn "")
-            (getList (replayCacheItems replay))
 
 debugProperty :: Property -> IO ()
 debugProperty property = case property of
diff --git a/library/Octane/Type.hs b/library/Octane/Type.hs
--- a/library/Octane/Type.hs
+++ b/library/Octane/Type.hs
@@ -1,25 +1,21 @@
 module Octane.Type
     ( module Octane.Type.Actor
-    , module Octane.Type.ActorMap
     , module Octane.Type.CacheItem
     , module Octane.Type.CacheProperty
     , module Octane.Type.KeyFrame
     , module Octane.Type.Mark
     , module Octane.Type.Message
-    , module Octane.Type.ObjectMap
     , module Octane.Type.Primitive
     , module Octane.Type.Property
     , module Octane.Type.Replay
     ) where
 
 import Octane.Type.Actor
-import Octane.Type.ActorMap
 import Octane.Type.CacheItem
 import Octane.Type.CacheProperty
 import Octane.Type.KeyFrame
 import Octane.Type.Mark
 import Octane.Type.Message
-import Octane.Type.ObjectMap
 import Octane.Type.Primitive
 import Octane.Type.Property
 import Octane.Type.Replay
diff --git a/library/Octane/Type/ActorMap.hs b/library/Octane/Type/ActorMap.hs
deleted file mode 100644
--- a/library/Octane/Type/ActorMap.hs
+++ /dev/null
@@ -1,32 +0,0 @@
-module Octane.Type.ActorMap (ActorMap(..)) where
-
-import qualified Data.IntMap as IntMap
-import Octane.Core
-import Octane.Type.Actor
-import Octane.Type.Primitive.PCString
-import Octane.Type.Primitive.Int32LE
-import Octane.Type.Primitive.List
-
-newtype ActorMap = NewActorMap
-    { getActorMap :: IntMap.IntMap PCString
-    } deriving (Show)
-
-instance Binary ActorMap where
-    get = do
-        (NewList actors) <- get
-        actors & map toTuple & IntMap.fromList & NewActorMap & return
-
-    put (NewActorMap actors) = do
-        actors & IntMap.assocs & map fromTuple & NewList & put
-
-toTuple :: Actor -> (Int, PCString)
-toTuple actor =
-    ( actor & actorTag & getInt32LE & fromIntegral
-    , actor & actorName
-    )
-
-fromTuple :: (Int, PCString) -> Actor
-fromTuple (tag, name) = NewActor
-    { actorName = name
-    , actorTag = tag & fromIntegral & NewInt32LE
-    }
diff --git a/library/Octane/Type/ObjectMap.hs b/library/Octane/Type/ObjectMap.hs
deleted file mode 100644
--- a/library/Octane/Type/ObjectMap.hs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Octane.Type.ObjectMap (ObjectMap(..)) where
-
-import qualified Data.IntMap as IntMap
-import Octane.Core
-import Octane.Type.Primitive.PCString
-import Octane.Type.Primitive.List
-
-newtype ObjectMap = NewObjectMap
-    { getObjectMap :: IntMap PCString
-    } deriving (Show)
-
-instance Binary ObjectMap where
-    get = do
-        NewList objects <- get
-        objects & zip [0 ..] & IntMap.fromAscList & NewObjectMap & return
-
-    put (NewObjectMap objects) = do
-        objects & IntMap.elems & NewList & put
diff --git a/library/Octane/Type/Primitive/Dictionary.hs b/library/Octane/Type/Primitive/Dictionary.hs
--- a/library/Octane/Type/Primitive/Dictionary.hs
+++ b/library/Octane/Type/Primitive/Dictionary.hs
@@ -8,24 +8,24 @@
 
 newtype Dictionary a = NewDictionary
     { getDictionary :: Map PCString a
-    } deriving (Show)
+    } deriving (Eq, Show)
 
 instance (Binary a) => Binary (Dictionary a) where
     get = do
-        row <- getRow
-        if Map.null row
+        element <- getElement
+        if Map.null element
         then do
-            row & NewDictionary & return
+            element & NewDictionary & return
         else do
-            NewDictionary rows <- get
-            rows & Map.union row & NewDictionary & return
+            NewDictionary elements <- get
+            elements & Map.union element & NewDictionary & return
 
-    put (NewDictionary rows) = do
-        rows & Map.assocs & mapM_ putRow
+    put (NewDictionary elements) = do
+        elements & Map.assocs & mapM_ putElement
         "None" & NewPCString & put
 
-getRow :: (Binary a) => Get (Map PCString a)
-getRow = do
+getElement :: (Binary a) => Get (Map PCString a)
+getElement = do
     key <- get
     if key == NewPCString "None"
     then do
@@ -35,7 +35,7 @@
         return (Map.singleton key value)
 
 
-putRow :: (Binary a) => (PCString, a) -> Put
-putRow (key, value) = do
+putElement :: (Binary a) => (PCString, a) -> Put
+putElement (key, value) = do
     key & put
     value & put
diff --git a/library/Octane/Type/Primitive/List.hs b/library/Octane/Type/Primitive/List.hs
--- a/library/Octane/Type/Primitive/List.hs
+++ b/library/Octane/Type/Primitive/List.hs
@@ -5,7 +5,7 @@
 
 newtype List a = NewList
     { getList :: [a]
-    } deriving (Show)
+    } deriving (Eq, Show)
 
 instance (Binary a) => Binary (List a) where
     get = do
diff --git a/library/Octane/Type/Replay.hs b/library/Octane/Type/Replay.hs
--- a/library/Octane/Type/Replay.hs
+++ b/library/Octane/Type/Replay.hs
@@ -2,12 +2,11 @@
 
 import qualified Data.ByteString as BS
 import Octane.Core
-import Octane.Type.ActorMap
+import Octane.Type.Actor
 import Octane.Type.CacheItem
 import Octane.Type.KeyFrame
 import Octane.Type.Mark
 import Octane.Type.Message
-import Octane.Type.ObjectMap
 import Octane.Type.Primitive.PCString
 import Octane.Type.Primitive.Int32LE
 import Octane.Type.Primitive.List
@@ -29,9 +28,9 @@
     , replayMessages :: List Message
     , replayMarks :: List Mark
     , replayPackages :: List PCString
-    , replayObjectMap :: ObjectMap
+    , replayObjects :: List PCString
     , replayNames :: List PCString
-    , replayActorMap :: ActorMap
+    , replayActors :: List Actor
     , replayCacheItems :: List CacheItem
     } deriving (Show)
 
@@ -51,9 +50,9 @@
         messages <- get
         marks <- get
         packages <- get
-        objectMap <- get
+        objects <- get
         names <- get
-        actorMap <- get
+        actors <- get
         cacheItems <- get
         return NewReplay
             { replaySize1 = size1
@@ -70,9 +69,9 @@
             , replayMessages = messages
             , replayMarks = marks
             , replayPackages = packages
-            , replayObjectMap = objectMap
+            , replayObjects = objects
             , replayNames = names
-            , replayActorMap = actorMap
+            , replayActors = actors
             , replayCacheItems = cacheItems
             }
 
@@ -91,9 +90,9 @@
         replay & replayMessages & put
         replay & replayMarks & put
         replay & replayPackages & put
-        replay & replayObjectMap & put
+        replay & replayObjects & put
         replay & replayNames & put
-        replay & replayActorMap & put
+        replay & replayActors & put
         replay & replayCacheItems & put
 
 getFrameBytes :: Get ByteString
diff --git a/octane.cabal b/octane.cabal
--- a/octane.cabal
+++ b/octane.cabal
@@ -1,5 +1,5 @@
 name: octane
-version: 0.2.0
+version: 0.2.1
 cabal-version: >=1.10
 build-type: Simple
 license: MIT
@@ -25,13 +25,11 @@
         Octane.Main
         Octane.Type
         Octane.Type.Actor
-        Octane.Type.ActorMap
         Octane.Type.CacheItem
         Octane.Type.CacheProperty
         Octane.Type.KeyFrame
         Octane.Type.Mark
         Octane.Type.Message
-        Octane.Type.ObjectMap
         Octane.Type.Primitive
         Octane.Type.Primitive.Boolean
         Octane.Type.Primitive.Float32LE
@@ -71,6 +69,7 @@
         base -any,
         binary -any,
         bytestring -any,
+        containers -any,
         octane -any,
         tasty ==0.11.*,
         tasty-hspec ==1.1.*
@@ -81,13 +80,11 @@
         Octane.MainSpec
         Octane.TypeSpec
         Octane.Type.ActorSpec
-        Octane.Type.ActorMapSpec
         Octane.Type.CacheItemSpec
         Octane.Type.CachePropertySpec
         Octane.Type.KeyFrameSpec
         Octane.Type.MarkSpec
         Octane.Type.MessageSpec
-        Octane.Type.ObjectMapSpec
         Octane.Type.PrimitiveSpec
         Octane.Type.Primitive.BooleanSpec
         Octane.Type.Primitive.Float32LESpec
@@ -98,4 +95,38 @@
         Octane.Type.Primitive.DictionarySpec
         Octane.Type.PropertySpec
         Octane.Type.ReplaySpec
+    ghc-options: -threaded -Wall
+
+benchmark octane-benchmark
+    type: exitcode-stdio-1.0
+    main-is: Benchmark.hs
+    build-depends:
+        base -any,
+        binary -any,
+        bytestring -any,
+        containers -any,
+        octane -any,
+        criterion ==1.1.*
+    default-language: Haskell2010
+    hs-source-dirs: benchmark
+    other-modules:
+        OctaneBench
+        Octane.MainBench
+        Octane.TypeBench
+        Octane.Type.ActorBench
+        Octane.Type.CacheItemBench
+        Octane.Type.CachePropertyBench
+        Octane.Type.KeyFrameBench
+        Octane.Type.MarkBench
+        Octane.Type.MessageBench
+        Octane.Type.PrimitiveBench
+        Octane.Type.Primitive.BooleanBench
+        Octane.Type.Primitive.DictionaryBench
+        Octane.Type.Primitive.Float32LEBench
+        Octane.Type.Primitive.Int32LEBench
+        Octane.Type.Primitive.Int64LEBench
+        Octane.Type.Primitive.ListBench
+        Octane.Type.Primitive.PCStringBench
+        Octane.Type.PropertyBench
+        Octane.Type.ReplayBench
     ghc-options: -threaded -Wall
diff --git a/test-suite/Octane/Type/ActorMapSpec.hs b/test-suite/Octane/Type/ActorMapSpec.hs
deleted file mode 100644
--- a/test-suite/Octane/Type/ActorMapSpec.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Octane.Type.ActorMapSpec (spec) where
-
-import Test.Tasty.Hspec
-
-spec :: Spec
-spec = describe "ActorMap" $ do
-    return ()
diff --git a/test-suite/Octane/Type/ObjectMapSpec.hs b/test-suite/Octane/Type/ObjectMapSpec.hs
deleted file mode 100644
--- a/test-suite/Octane/Type/ObjectMapSpec.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Octane.Type.ObjectMapSpec (spec) where
-
-import Test.Tasty.Hspec
-
-spec :: Spec
-spec = describe "ObjectMap" $ do
-    return ()
diff --git a/test-suite/Octane/Type/Primitive/BooleanSpec.hs b/test-suite/Octane/Type/Primitive/BooleanSpec.hs
--- a/test-suite/Octane/Type/Primitive/BooleanSpec.hs
+++ b/test-suite/Octane/Type/Primitive/BooleanSpec.hs
@@ -5,19 +5,19 @@
 import qualified Data.Binary as Binary
 import qualified Data.Binary.Get as Binary
 import qualified Data.ByteString.Lazy as BSL
-import qualified Octane as Octane
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "Boolean" $ do
     it "can be decoded" $ do
-        decodeBoolean "\0" `shouldBe` Right ("", 1, Octane.NewBoolean False)
-        decodeBoolean "\1" `shouldBe` Right ("", 1, Octane.NewBoolean True)
+        decodeBoolean "\0" `shouldBe` Right ("", 1, NewBoolean False)
+        decodeBoolean "\1" `shouldBe` Right ("", 1, NewBoolean True)
     it "can be encoded" $ do
-        Binary.encode (Octane.NewBoolean False) `shouldBe` "\0"
-        Binary.encode (Octane.NewBoolean True) `shouldBe` "\1"
+        Binary.encode (NewBoolean False) `shouldBe` "\0"
+        Binary.encode (NewBoolean True) `shouldBe` "\1"
     it "does not raise a runtime error when decoding garbage" $ do
         decodeBoolean "garbage" `shouldBe` Left ("arbage", 1, "out of bounds")
 
-decodeBoolean :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Octane.Boolean)
+decodeBoolean :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Boolean)
 decodeBoolean = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/DictionarySpec.hs b/test-suite/Octane/Type/Primitive/DictionarySpec.hs
--- a/test-suite/Octane/Type/Primitive/DictionarySpec.hs
+++ b/test-suite/Octane/Type/Primitive/DictionarySpec.hs
@@ -1,7 +1,24 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 module Octane.Type.Primitive.DictionarySpec (spec) where
 
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.Map as Map
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "Dictionary" $ do
-    return ()
+    it "can be decoded" $ do
+        decodeDictionary "\5\0\0\0None\0" `shouldBe` Right ("", 9, NewDictionary Map.empty :: Dictionary Boolean)
+        decodeDictionary "\6\0\0\0Hello\0\6\0\0\0World\0\5\0\0\0None\0" `shouldBe` Right ("", 29, NewDictionary (Map.singleton (NewPCString "Hello") (NewPCString "World")))
+        decodeDictionary "\7\0\0\0falsey\0\0\7\0\0\0truthy\0\1\5\0\0\0None\0" `shouldBe` Right ("", 33, NewDictionary (Map.fromList [(NewPCString "truthy", NewBoolean True), (NewPCString "falsey", NewBoolean False)]))
+    it "can be encoded" $ do
+        Binary.encode (NewDictionary Map.empty :: Dictionary Boolean) `shouldBe` "\5\0\0\0None\0"
+        Binary.encode (NewDictionary (Map.singleton (NewPCString "Hello") (NewPCString "World"))) `shouldBe` "\6\0\0\0Hello\0\6\0\0\0World\0\5\0\0\0None\0"
+        Binary.encode (NewDictionary (Map.fromList [(NewPCString "truthy", NewBoolean True), (NewPCString "falsey", NewBoolean False)])) `shouldBe` "\7\0\0\0falsey\0\0\7\0\0\0truthy\0\1\5\0\0\0None\0"
+
+decodeDictionary :: (Binary.Binary a) => BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Dictionary a)
+decodeDictionary = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/Float32LESpec.hs b/test-suite/Octane/Type/Primitive/Float32LESpec.hs
--- a/test-suite/Octane/Type/Primitive/Float32LESpec.hs
+++ b/test-suite/Octane/Type/Primitive/Float32LESpec.hs
@@ -5,17 +5,17 @@
 import qualified Data.Binary as Binary
 import qualified Data.Binary.Get as Binary
 import qualified Data.ByteString.Lazy as BSL
-import qualified Octane as Octane
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "Float32LE" $ do
     it "can be decoded" $ do
-        decodeFloat32LE "\0\0\0\0" `shouldBe` Right ("", 4, Octane.NewFloat32LE 0.0)
-        decodeFloat32LE "\0\0\128\63" `shouldBe` Right ("", 4, Octane.NewFloat32LE 1.0)
+        decodeFloat32LE "\0\0\0\0" `shouldBe` Right ("", 4, NewFloat32LE 0.0)
+        decodeFloat32LE "\0\0\128\63" `shouldBe` Right ("", 4, NewFloat32LE 1.0)
     it "can be encoded" $ do
-        Binary.encode (Octane.NewFloat32LE 0.0) `shouldBe` "\0\0\0\0"
-        Binary.encode (Octane.NewFloat32LE 1.0) `shouldBe` "\0\0\128\63"
+        Binary.encode (NewFloat32LE 0.0) `shouldBe` "\0\0\0\0"
+        Binary.encode (NewFloat32LE 1.0) `shouldBe` "\0\0\128\63"
 
-decodeFloat32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Octane.Float32LE)
+decodeFloat32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Float32LE)
 decodeFloat32LE = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/Int32LESpec.hs b/test-suite/Octane/Type/Primitive/Int32LESpec.hs
--- a/test-suite/Octane/Type/Primitive/Int32LESpec.hs
+++ b/test-suite/Octane/Type/Primitive/Int32LESpec.hs
@@ -5,17 +5,17 @@
 import qualified Data.Binary as Binary
 import qualified Data.Binary.Get as Binary
 import qualified Data.ByteString.Lazy as BSL
-import qualified Octane as Octane
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "Int32LE" $ do
     it "can be decoded" $ do
-        decodeInt32LE "\0\0\0\0" `shouldBe` Right ("", 4, Octane.NewInt32LE 0)
-        decodeInt32LE "\1\0\0\0" `shouldBe` Right ("", 4, Octane.NewInt32LE 1)
+        decodeInt32LE "\0\0\0\0" `shouldBe` Right ("", 4, NewInt32LE 0)
+        decodeInt32LE "\1\0\0\0" `shouldBe` Right ("", 4, NewInt32LE 1)
     it "can be encoded" $ do
-        Binary.encode (Octane.NewInt32LE 0) `shouldBe` "\0\0\0\0"
-        Binary.encode (Octane.NewInt32LE 1) `shouldBe` "\1\0\0\0"
+        Binary.encode (NewInt32LE 0) `shouldBe` "\0\0\0\0"
+        Binary.encode (NewInt32LE 1) `shouldBe` "\1\0\0\0"
 
-decodeInt32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Octane.Int32LE)
+decodeInt32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Int32LE)
 decodeInt32LE = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/Int64LESpec.hs b/test-suite/Octane/Type/Primitive/Int64LESpec.hs
--- a/test-suite/Octane/Type/Primitive/Int64LESpec.hs
+++ b/test-suite/Octane/Type/Primitive/Int64LESpec.hs
@@ -5,17 +5,17 @@
 import qualified Data.Binary as Binary
 import qualified Data.Binary.Get as Binary
 import qualified Data.ByteString.Lazy as BSL
-import qualified Octane as Octane
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "Int64LE" $ do
     it "can be decoded" $ do
-        decodeInt64LE "\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, Octane.NewInt64LE 0)
-        decodeInt64LE "\1\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, Octane.NewInt64LE 1)
+        decodeInt64LE "\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, NewInt64LE 0)
+        decodeInt64LE "\1\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, NewInt64LE 1)
     it "can be encoded" $ do
-        Binary.encode (Octane.NewInt64LE 0) `shouldBe` "\0\0\0\0\0\0\0\0"
-        Binary.encode (Octane.NewInt64LE 1) `shouldBe` "\1\0\0\0\0\0\0\0"
+        Binary.encode (NewInt64LE 0) `shouldBe` "\0\0\0\0\0\0\0\0"
+        Binary.encode (NewInt64LE 1) `shouldBe` "\1\0\0\0\0\0\0\0"
 
-decodeInt64LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Octane.Int64LE)
+decodeInt64LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Int64LE)
 decodeInt64LE = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/ListSpec.hs b/test-suite/Octane/Type/Primitive/ListSpec.hs
--- a/test-suite/Octane/Type/Primitive/ListSpec.hs
+++ b/test-suite/Octane/Type/Primitive/ListSpec.hs
@@ -1,7 +1,23 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 module Octane.Type.Primitive.ListSpec (spec) where
 
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
-spec = describe "ListSpec" $ do
-    return ()
+spec = describe "List" $ do
+    it "can be decoded" $ do
+        decodeList "\0\0\0\0" `shouldBe` Right ("", 4, NewList [] :: List Boolean)
+        decodeList "\1\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, NewList [NewInt32LE 0])
+        decodeList "\2\0\0\0\0\1" `shouldBe` Right ("", 6, NewList [NewBoolean False, NewBoolean True])
+    it "can be encoded" $ do
+        Binary.encode (NewList [] :: List Boolean) `shouldBe` "\0\0\0\0"
+        Binary.encode (NewList [NewInt32LE 0]) `shouldBe` "\1\0\0\0\0\0\0\0"
+        Binary.encode (NewList [NewBoolean False, NewBoolean True]) `shouldBe` "\2\0\0\0\0\1"
+
+decodeList :: (Binary.Binary a) => BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, List a)
+decodeList = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/PCStringSpec.hs b/test-suite/Octane/Type/Primitive/PCStringSpec.hs
--- a/test-suite/Octane/Type/Primitive/PCStringSpec.hs
+++ b/test-suite/Octane/Type/Primitive/PCStringSpec.hs
@@ -5,21 +5,21 @@
 import qualified Data.Binary as Binary
 import qualified Data.Binary.Get as Binary
 import qualified Data.ByteString.Lazy as BSL
-import qualified Octane as Octane
+import Octane
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "PCString" $ do
     it "can be decoded" $ do
-        decodePCString "\1\0\0\0\0" `shouldBe` Right ("", 5, Octane.NewPCString "")
-        decodePCString "\6\0\0\0ascii\0" `shouldBe` Right ("", 10, Octane.NewPCString "ascii")
-        decodePCString "\8\0\0\0\251\241\239\231\248d\233\0" `shouldBe` Right ("", 12, Octane.NewPCString "ûñïçødé")
+        decodePCString "\1\0\0\0\0" `shouldBe` Right ("", 5, NewPCString "")
+        decodePCString "\6\0\0\0ascii\0" `shouldBe` Right ("", 10, NewPCString "ascii")
+        decodePCString "\8\0\0\0\251\241\239\231\248d\233\0" `shouldBe` Right ("", 12, NewPCString "ûñïçødé")
     it "can be encoded" $ do
-        Binary.encode (Octane.NewPCString "") `shouldBe` "\1\0\0\0\0"
-        Binary.encode (Octane.NewPCString "ascii") `shouldBe` "\6\0\0\0ascii\0"
-        Binary.encode (Octane.NewPCString "ûñïçødé") `shouldBe` "\8\0\0\0\251\241\239\231\248d\233\0"
+        Binary.encode (NewPCString "") `shouldBe` "\1\0\0\0\0"
+        Binary.encode (NewPCString "ascii") `shouldBe` "\6\0\0\0ascii\0"
+        Binary.encode (NewPCString "ûñïçødé") `shouldBe` "\8\0\0\0\251\241\239\231\248d\233\0"
     it "does not decode strings of length 0" $ do
         decodePCString "\0\0\0\0" `shouldBe` Left ("", 4, "invalid size")
 
-decodePCString :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Octane.PCString)
+decodePCString :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, PCString)
 decodePCString = Binary.decodeOrFail
diff --git a/test-suite/Octane/TypeSpec.hs b/test-suite/Octane/TypeSpec.hs
--- a/test-suite/Octane/TypeSpec.hs
+++ b/test-suite/Octane/TypeSpec.hs
@@ -1,13 +1,11 @@
 module Octane.TypeSpec (spec) where
 
 import qualified Octane.Type.ActorSpec
-import qualified Octane.Type.ActorMapSpec
 import qualified Octane.Type.CacheItemSpec
 import qualified Octane.Type.CachePropertySpec
 import qualified Octane.Type.KeyFrameSpec
 import qualified Octane.Type.MarkSpec
 import qualified Octane.Type.MessageSpec
-import qualified Octane.Type.ObjectMapSpec
 import qualified Octane.Type.PrimitiveSpec
 import qualified Octane.Type.PropertySpec
 import qualified Octane.Type.ReplaySpec
@@ -16,13 +14,11 @@
 spec :: Spec
 spec = describe "Type" $ do
     Octane.Type.ActorSpec.spec
-    Octane.Type.ActorMapSpec.spec
     Octane.Type.CacheItemSpec.spec
     Octane.Type.CachePropertySpec.spec
     Octane.Type.KeyFrameSpec.spec
     Octane.Type.MarkSpec.spec
     Octane.Type.MessageSpec.spec
-    Octane.Type.ObjectMapSpec.spec
     Octane.Type.PrimitiveSpec.spec
     Octane.Type.PropertySpec.spec
     Octane.Type.ReplaySpec.spec
