diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,23 @@
+0.9.1
+=====
+
+ - fixed tests to work with QuickCheck-2.8.2
+ - add SafeCopy instance for Word
+ - updates for template-haskell 2.11
+ - export some internal TH derivation helpers
+
+0.9.0
+=====
+
+This version changes the way `Float` and `Double` are serialized to a
+more compact format. Old data should be migrated automatically. As a
+result, however, the `Float` and `Double` data serialized by this version can not be read
+by older versions of `safecopy`.
+
+This change originated as a modification to the way `cereal` 0.5 serializes `Float` and `Double`.
+
+[https://github.com/GaloisInc/cereal/commit/47d839609413e3e9d1147b99c34ae421ae36bced](https://github.com/GaloisInc/cereal/commit/47d839609413e3e9d1147b99c34ae421ae36bced)
+
+[https://github.com/GaloisInc/cereal/issues/35](https://github.com/GaloisInc/cereal/issues/35)
+
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/safecopy-store.cabal b/safecopy-store.cabal
new file mode 100644
--- /dev/null
+++ b/safecopy-store.cabal
@@ -0,0 +1,66 @@
+-- safecopy.cabal auto-generated by cabal init. For additional
+-- options, see
+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
+-- The name of the package.
+Name:                safecopy-store
+Version:             0.9.2
+Synopsis:            Binary serialization with version control.
+Description:         Fork of safecopy that uses store instead of cereal.
+Homepage:            https://github.com/NCrashed/safecopy
+License:             PublicDomain
+Author:              David Himmelstrup, Felipe Lessa, Anton Gushcha
+Maintainer:          Anton Gushcha <ncrashed@gmail.com>
+-- Copyright:
+Category:            Data, Parsing
+Build-type:          Simple
+Extra-source-files: CHANGELOG.md
+Cabal-version:       >=1.8
+tested-with:         GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.2, GHC==8.0.1
+
+Source-repository head
+  type:          git
+  location:      git://github.com/NCrashed/safecopy.git
+
+Library
+  -- Modules exported by the library.
+  Exposed-modules:     Data.SafeCopy.Store
+                       Data.SafeCopy.Store.Internal
+
+  Hs-Source-Dirs:      src/
+
+  -- Packages needed in order to build this package.
+  Build-depends:       base >=4.5 && <5,
+                       array < 0.6,
+                       bytestring < 0.11,
+                       containers >= 0.3 && < 0.6,
+                       old-time < 1.2,
+                       store >= 0.3 && < 0.4,
+                       store-core >= 0.3 && < 0.4,
+                       template-haskell < 2.12,
+                       text < 1.3,
+                       time < 1.7,
+                       vector >= 0.10 && < 0.12
+
+  -- Modules not exported by this package.
+  Other-modules:       Data.SafeCopy.Store.Instances, Data.SafeCopy.Store.SafeCopy,
+                       Data.SafeCopy.Store.Derive, Data.SafeCopy.Store.Encode
+
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  -- Build-tools:
+
+  GHC-Options:         -Wall
+
+  if(impl(ghc >= 7.2.1))
+    cpp-options: -DDEFAULT_SIGNATURES
+
+  if(impl(ghc >= 7.1))
+    cpp-options: -DSAFE_HASKELL
+
+Test-suite instances
+  Type:                exitcode-stdio-1.0
+  Main-is:             instances.hs
+  Hs-Source-Dirs:      test/
+  GHC-Options:         -Wall -threaded -rtsopts -with-rtsopts=-N
+  Build-depends:       base, store, template-haskell, safecopy-store,
+                       containers, time, array, vector, lens >= 4.7 && < 5.0,
+                       lens-action, tasty, tasty-quickcheck, quickcheck-instances, QuickCheck
diff --git a/src/Data/SafeCopy/Store.hs b/src/Data/SafeCopy/Store.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/SafeCopy/Store.hs
@@ -0,0 +1,116 @@
+{-# LANGUAGE CPP #-}
+#ifdef SAFE_HASKELL
+{-# LANGUAGE Trustworthy #-}
+#endif
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.SafeCopy
+-- Copyright   :  PublicDomain
+--
+-- Maintainer  :  lemmih@gmail.com
+-- Portability :  non-portable (uses GHC extensions)
+--
+-- SafeCopy extends the parsing and serialization capabilities of Data.Serialize
+-- to include nested version control. Nested version control means that you
+-- can change the definition and binary format of a type nested deep within
+-- other types without problems.
+--
+-- Consider this scenario. You want to store your contact list on disk
+-- and so write the following code:
+--
+-- @
+--type Name     = String
+--type Address  = String
+--data Contacts = Contacts [(Name, Address)]
+--instance SafeCopy Contacts where
+--     putCopy (Contacts list) = contain $ safePut list
+--     getCopy = contain $ Contacts \<$\> safeGet
+-- @
+--
+-- At this point, everything is fine. You get the awesome speed of Data.Serialize
+-- together with Haskell's ease of use. However, things quickly take a U-turn for the worse
+-- when you realize that you want to keep phone numbers as well as names and
+-- addresses. Being the experienced coder that you are, you see that using a 3-tuple
+-- isn't very pretty and you'd rather use a record. At first you fear that this
+-- change in structure will invalidate all your old data. Those fears are quickly quelled,
+-- though, when you remember how nifty SafeCopy is. With renewed enthusiasm,
+-- you set out and write the following code:
+--
+-- @
+--type Name = String
+--type Address = String
+--type Phone = String
+--
+--{- We rename our old Contacts structure -}
+--data Contacts_v0 = Contacts_v0 [(Name, Address)]
+--instance SafeCopy Contacts_v0 where
+--     putCopy (Contacts_v0 list) = contain $ safePut list
+--     getCopy = contain $ Contacts_v0 \<$\> safeGet
+--
+--data Contact = Contact { name    :: Name
+--                        , address :: Address
+--                        , phone   :: Phone }
+--instance SafeCopy Contact where
+--    putCopy Contact{..} = contain $ do safePut name; safePut address; safePut phone
+--    getCopy = contain $ Contact \<$\> safeGet \<*\> safeGet \<*\> safeGet
+--
+--data Contacts = Contacts [Contact]
+--instance SafeCopy Contacts where
+--     version = 2
+--     kind = extension
+--     putCopy (Contacts contacts) = contain $ safePut contacts
+--     getCopy = contain $ Contacts \<$\> safeGet
+--
+--{- Here the magic happens: -}
+--instance Migrate Contacts where
+--     type MigrateFrom Contacts = Contacts_v0
+--     migrate (Contacts_v0 contacts) = Contacts [ Contact{ name    = name
+--                                                        , address = address
+--                                                        , phone   = \"\" }
+--                                               | (name, address) <- contacts ]
+-- @
+--
+-- With this, you reflect on your code and you are happy. You feel confident in the safety of
+-- your data and you know you can remove @Contacts_v0@ once you no longer wish to support
+-- that legacy format.
+module Data.SafeCopy.Store
+    (
+      safeGet
+    , safePut
+    , SafeCopy(version, kind, getCopy, putCopy, objectProfile, errorTypeName)
+    , Encode
+    , runEncode
+    , PeekException
+    , Profile(..)
+    , Prim(..)
+    , Migrate(..)
+    , Reverse(..)
+    , Kind
+    , extension
+    , extended_extension
+    , extended_base
+    , base
+    , Contained
+    , contain
+    , Version
+
+      -- * Template haskell functions
+    , deriveSafeCopy
+    , deriveSafeCopyIndexedType
+    , deriveSafeCopySimple
+    , deriveSafeCopySimpleIndexedType
+    , deriveSafeCopyHappstackData
+    , deriveSafeCopyHappstackDataIndexedType
+
+      -- * Rarely used functions
+    , getSafeGet
+    , getSafePut
+    , primitive
+    ) where
+
+import Data.SafeCopy.Store.Derive
+import Data.SafeCopy.Store.Encode
+import Data.SafeCopy.Store.Instances ()
+import Data.SafeCopy.Store.SafeCopy
+import Data.Store
diff --git a/src/Data/SafeCopy/Store/Derive.hs b/src/Data/SafeCopy/Store/Derive.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/SafeCopy/Store/Derive.hs
@@ -0,0 +1,462 @@
+{-# LANGUAGE TemplateHaskell, CPP #-}
+
+-- Hack for bug in older Cabal versions
+#ifndef MIN_VERSION_template_haskell
+#define MIN_VERSION_template_haskell(x,y,z) 1
+#endif
+
+module Data.SafeCopy.Store.Derive where
+
+import Data.Store
+import Data.SafeCopy.Store.Encode
+import Data.SafeCopy.Store.SafeCopy
+
+#if MIN_VERSION_template_haskell(2,8,0)
+import Language.Haskell.TH hiding (Kind)
+#else
+import Language.Haskell.TH hiding (Kind(..))
+#endif
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
+import Control.Monad
+import Data.Maybe (fromMaybe)
+#ifdef __HADDOCK__
+import Data.Word (Word8) -- Haddock
+#endif
+
+-- | Derive an instance of 'SafeCopy'.
+--
+--   When serializing, we put a 'Word8' describing the
+--   constructor (if the data type has more than one
+--   constructor).  For each type used in the constructor, we
+--   call 'getSafePut' (which immediately serializes the version
+--   of the type).  Then, for each field in the constructor, we
+--   use one of the put functions obtained in the last step.
+--
+--   For example, given the data type and the declaration below
+--
+--   @
+--data T0 b = T0 b Int
+--deriveSafeCopy 1 'base ''T0
+--   @
+--
+--   we generate
+--
+--   @
+--instance (SafeCopy a, SafeCopy b) =>
+--         SafeCopy (T0 b) where
+--    putCopy a@(T0 arg1 arg2) = contain $ do put_b   <- getSafePut
+--                                            put_Int <- getSafePut
+--                                            put_b   arg1
+--                                            put_Int arg2
+--                                            return a
+--    getCopy = contain $ do get_b   <- getSafeGet
+--                           get_Int <- getSafeGet
+--                           return T0 \<*\> get_b \<*\> get_Int
+--    version = 1
+--    kind = base
+--   @
+--
+--   And, should we create another data type as a newer version of @T0@, such as
+--
+--   @
+--data T a b = C a a | D b Int
+--deriveSafeCopy 2 'extension ''T
+--
+--instance SafeCopy b => Migrate (T a b) where
+--  type MigrateFrom (T a b) = T0 b
+--  migrate (T0 b i) = D b i
+--   @
+--
+--   we generate
+--
+--   @
+--instance (SafeCopy a, SafeCopy b) =>
+--         SafeCopy (T a b) where
+--    putCopy a@(C arg1 arg2) = contain $ do putWord8 0
+--                                           put_a <- getSafePut
+--                                           put_a arg1
+--                                           put_a arg2
+--                                           return a
+--    putCopy a@(D arg1 arg2) = contain $ do putWord8 1
+--                                           put_b   <- getSafePut
+--                                           put_Int <- getSafePut
+--                                           put_b   arg1
+--                                           put_Int arg2
+--                                           return a
+--    getCopy = contain $ do tag <- getWord8
+--                           case tag of
+--                             0 -> do get_a <- getSafeGet
+--                                     return C \<*\> get_a \<*\> get_a
+--                             1 -> do get_b   <- getSafeGet
+--                                     get_Int <- getSafeGet
+--                                     return D \<*\> get_b \<*\> get_Int
+--                             _ -> fail $ \"Could not identify tag \\\"\" ++
+--                                         show tag ++ \"\\\" for type Main.T \" ++
+--                                         \"that has only 2 constructors.  \" ++
+--                                         \"Maybe your data is corrupted?\"
+--    version = 2
+--    kind = extension
+--   @
+--
+--   Note that by using getSafePut, we saved 4 bytes in the case
+--   of the @C@ constructor.  For @D@ and @T0@, we didn't save
+--   anything.  The instance derived by this function always use
+--   at most the same space as those generated by
+--   'deriveSafeCopySimple', but never more (as we don't call
+--   'getSafePut'/'getSafeGet' for types that aren't needed).
+--
+--   Note that you may use 'deriveSafeCopySimple' with one
+--   version of your data type and 'deriveSafeCopy' in another
+--   version without any problems.
+deriveSafeCopy :: Version a -> Name -> Name -> Q [Dec]
+deriveSafeCopy = internalDeriveSafeCopy Normal
+
+deriveSafeCopyIndexedType :: Version a -> Name -> Name -> [Name] -> Q [Dec]
+deriveSafeCopyIndexedType = internalDeriveSafeCopyIndexedType Normal
+
+-- | Derive an instance of 'SafeCopy'.  The instance derived by
+--   this function is simpler than the one derived by
+--   'deriveSafeCopy' in that we always use 'safePut' and
+--   'safeGet' (instead of 'getSafePut' and 'getSafeGet').
+--
+--   When serializing, we put a 'Word8' describing the
+--   constructor (if the data type has more than one constructor)
+--   and, for each field of the constructor, we use 'safePut'.
+--
+--   For example, given the data type and the declaration below
+--
+--   @
+--data T a b = C a a | D b Int
+--deriveSafeCopySimple 1 'base ''T
+--   @
+--
+--   we generate
+--
+--   @
+--instance (SafeCopy a, SafeCopy b) =>
+--         SafeCopy (T a b) where
+--    putCopy a@(C arg1 arg2) = contain $ do putWord8 0
+--                                           safePut arg1
+--                                           safePut arg2
+--                                           return a
+--    putCopy a@(D arg1 arg2) = contain $ do putWord8 1
+--                                           safePut arg1
+--                                           safePut arg2
+--                                           return a
+--    getCopy = contain $ do tag <- getWord8
+--                           case tag of
+--                             0 -> do return C \<*\> safeGet \<*\> safeGet
+--                             1 -> do return D \<*\> safeGet \<*\> safeGet
+--                             _ -> fail $ \"Could not identify tag \\\"\" ++
+--                                         show tag ++ \"\\\" for type Main.T \" ++
+--                                         \"that has only 2 constructors.  \" ++
+--                                         \"Maybe your data is corrupted?\"
+--    version = 1
+--    kind = base
+--   @
+--
+--   Using this simpler instance means that you may spend more
+--   bytes when serializing data.  On the other hand, it is more
+--   straightforward and may match any other format you used in
+--   the past.
+--
+--   Note that you may use 'deriveSafeCopy' with one version of
+--   your data type and 'deriveSafeCopySimple' in another version
+--   without any problems.
+deriveSafeCopySimple :: Version a -> Name -> Name -> Q [Dec]
+deriveSafeCopySimple = internalDeriveSafeCopy Simple
+
+deriveSafeCopySimpleIndexedType :: Version a -> Name -> Name -> [Name] -> Q [Dec]
+deriveSafeCopySimpleIndexedType = internalDeriveSafeCopyIndexedType Simple
+
+-- | Derive an instance of 'SafeCopy'.  The instance derived by
+--   this function should be compatible with the instance derived
+--   by the module @Happstack.Data.SerializeTH@ of the
+--   @happstack-data@ package.  The instances use only 'safePut'
+--   and 'safeGet' (as do the instances created by
+--   'deriveSafeCopySimple'), but we also always write a 'Word8'
+--   tag, even if the data type isn't a sum type.
+--
+--   For example, given the data type and the declaration below
+--
+--   @
+--data T0 b = T0 b Int
+--deriveSafeCopy 1 'base ''T0
+--   @
+--
+--   we generate
+--
+--   @
+--instance (SafeCopy a, SafeCopy b) =>
+--         SafeCopy (T0 b) where
+--    putCopy a@(T0 arg1 arg2) = contain $ do putWord8 0
+--                                            safePut arg1
+--                                            safePut arg2
+--                                            return a
+--    getCopy = contain $ do tag <- getWord8
+--                           case tag of
+--                             0 -> do return T0 \<*\> safeGet \<*\> safeGet
+--                             _ -> fail $ \"Could not identify tag \\\"\" ++
+--                                         show tag ++ \"\\\" for type Main.T0 \" ++
+--                                         \"that has only 1 constructors.  \" ++
+--                                         \"Maybe your data is corrupted?\"
+--    version = 1
+--    kind = base
+--   @
+--
+--   This instance always consumes at least the same space as
+--   'deriveSafeCopy' or 'deriveSafeCopySimple', but may use more
+--   because of the useless tag.  So we recomend using it only if
+--   you really need to read a previous version in this format,
+--   and not for newer versions.
+--
+--   Note that you may use 'deriveSafeCopy' with one version of
+--   your data type and 'deriveSafeCopyHappstackData' in another version
+--   without any problems.
+deriveSafeCopyHappstackData :: Version a -> Name -> Name -> Q [Dec]
+deriveSafeCopyHappstackData = internalDeriveSafeCopy HappstackData
+
+deriveSafeCopyHappstackDataIndexedType :: Version a -> Name -> Name -> [Name] -> Q [Dec]
+deriveSafeCopyHappstackDataIndexedType = internalDeriveSafeCopyIndexedType HappstackData
+
+data DeriveType = Normal | Simple | HappstackData
+
+forceTag :: DeriveType -> Bool
+forceTag HappstackData = True
+forceTag _             = False
+
+tyVarName :: TyVarBndr -> Name
+tyVarName (PlainTV n) = n
+#if MIN_VERSION_template_haskell(2,10,0)
+tyVarName (KindedTV n _) = n
+#endif
+
+internalDeriveSafeCopy :: DeriveType -> Version a -> Name -> Name -> Q [Dec]
+internalDeriveSafeCopy deriveType versionId kindName tyName = do
+  info <- reify tyName
+  internalDeriveSafeCopy' deriveType versionId kindName tyName info
+
+internalDeriveSafeCopy' :: DeriveType -> Version a -> Name -> Name -> Info -> Q [Dec]
+internalDeriveSafeCopy' deriveType versionId kindName tyName info = do
+  case info of
+#if MIN_VERSION_template_haskell(2,11,0)
+    TyConI (DataD context _name tyvars _kind cons _derivs)
+#else
+    TyConI (DataD context _name tyvars cons _derivs)
+#endif
+      | length cons > 255 -> fail $ "Can't derive SafeCopy instance for: " ++ show tyName ++
+                                    ". The datatype must have less than 256 constructors."
+      | otherwise         -> worker context tyvars (zip [0..] cons)
+
+#if MIN_VERSION_template_haskell(2,11,0)
+    TyConI (NewtypeD context _name tyvars _kind con _derivs) ->
+#else
+    TyConI (NewtypeD context _name tyvars con _derivs) ->
+#endif
+      worker context tyvars [(0, con)]
+
+    FamilyI _ insts -> do
+      decs <- forM insts $ \inst ->
+        case inst of
+#if MIN_VERSION_template_haskell(2,11,0)
+          DataInstD context _name ty _kind cons _derivs ->
+#else
+          DataInstD context _name ty cons _derivs ->
+#endif
+              worker' (foldl appT (conT tyName) (map return ty)) context [] (zip [0..] cons)
+
+#if MIN_VERSION_template_haskell(2,11,0)
+          NewtypeInstD context _name ty _kind con _derivs ->
+#else
+          NewtypeInstD context _name ty con _derivs ->
+#endif
+              worker' (foldl appT (conT tyName) (map return ty)) context [] [(0, con)]
+          _ -> fail $ "Can't derive SafeCopy instance for: " ++ show (tyName, inst)
+      return $ concat decs
+    _ -> fail $ "Can't derive SafeCopy instance for: " ++ show (tyName, info)
+  where
+    worker = worker' (conT tyName)
+    worker' tyBase context tyvars cons =
+      let ty = foldl appT tyBase [ varT $ tyVarName var | var <- tyvars ]
+#if MIN_VERSION_template_haskell(2,10,0)
+          safeCopyClass args = foldl appT (conT ''SafeCopy) args
+#else
+          safeCopyClass args = classP ''SafeCopy args
+#endif
+      in (:[]) <$> instanceD (cxt $ [safeCopyClass [varT $ tyVarName var] | var <- tyvars] ++ map return context)
+                                       (conT ''SafeCopy `appT` ty)
+                                       [ mkPutCopy deriveType cons
+                                       , mkGetCopy deriveType (show tyName) cons
+                                       , valD (varP 'version) (normalB $ litE $ integerL $ fromIntegral $ unVersion versionId) []
+                                       , valD (varP 'kind) (normalB (varE kindName)) []
+                                       , funD 'errorTypeName [clause [wildP] (normalB $ litE $ StringL (show tyName)) []]
+                                       ]
+
+internalDeriveSafeCopyIndexedType :: DeriveType -> Version a -> Name -> Name -> [Name] -> Q [Dec]
+internalDeriveSafeCopyIndexedType deriveType versionId kindName tyName tyIndex' = do
+  info <- reify tyName
+  internalDeriveSafeCopyIndexedType' deriveType versionId kindName tyName tyIndex' info
+
+internalDeriveSafeCopyIndexedType' :: DeriveType -> Version a -> Name -> Name -> [Name] -> Info -> Q [Dec]
+internalDeriveSafeCopyIndexedType' deriveType versionId kindName tyName tyIndex' info = do
+  tyIndex <- mapM conT tyIndex'
+  case info of
+    FamilyI _ insts -> do
+      decs <- forM insts $ \inst ->
+        case inst of
+#if MIN_VERSION_template_haskell(2,11,0)
+          DataInstD context _name ty _kind cons _derivs
+#else
+          DataInstD context _name ty cons _derivs
+#endif
+            | ty == tyIndex ->
+              worker' (foldl appT (conT tyName) (map return ty)) context [] (zip [0..] cons)
+            | otherwise ->
+              return []
+
+#if MIN_VERSION_template_haskell(2,11,0)
+          NewtypeInstD context _name ty _kind con _derivs
+#else
+          NewtypeInstD context _name ty con _derivs
+#endif
+            | ty == tyIndex ->
+              worker' (foldl appT (conT tyName) (map return ty)) context [] [(0, con)]
+            | otherwise ->
+              return []
+          _ -> fail $ "Can't derive SafeCopy instance for: " ++ show (tyName, inst)
+      return $ concat decs
+    _ -> fail $ "Can't derive SafeCopy instance for: " ++ show (tyName, info)
+  where
+    typeNameStr = unwords $ map show (tyName:tyIndex')
+    worker' tyBase context tyvars cons =
+      let ty = foldl appT tyBase [ varT $ tyVarName var | var <- tyvars ]
+#if MIN_VERSION_template_haskell(2,10,0)
+          safeCopyClass args = foldl appT (conT ''SafeCopy) args
+#else
+          safeCopyClass args = classP ''SafeCopy args
+#endif
+      in (:[]) <$> instanceD (cxt $ [safeCopyClass [varT $ tyVarName var] | var <- tyvars] ++ map return context)
+                                       (conT ''SafeCopy `appT` ty)
+                                       [ mkPutCopy deriveType cons
+                                       , mkGetCopy deriveType typeNameStr cons
+                                       , valD (varP 'version) (normalB $ litE $ integerL $ fromIntegral $ unVersion versionId) []
+                                       , valD (varP 'kind) (normalB (varE kindName)) []
+                                       , funD 'errorTypeName [clause [wildP] (normalB $ litE $ StringL typeNameStr) []]
+                                       ]
+
+mkPutCopy :: DeriveType -> [(Integer, Con)] -> DecQ
+mkPutCopy deriveType cons = funD 'putCopy $ map mkPutClause cons
+    where
+      manyConstructors = length cons > 1 || forceTag deriveType
+      mkPutClause (conNumber, con)
+          = do putVars <- replicateM (conSize con) (newName "arg")
+               (putFunsDecs, putFuns) <- case deriveType of
+                                           Normal -> mkSafeFunctions "safePut_" 'getSafePut con
+                                           _      -> return ([], const 'safePut)
+               asName <- newName "a"
+               let putClause   = asP asName $ conP (conName con) (map varP putVars)
+                   putCopyBody = varE 'contain `appE` doE (
+                                   [ bindS wildP $ varE 'pokeE `appE` litE (IntegerL conNumber) | manyConstructors ] ++
+                                   putFunsDecs ++
+                                   [ bindS wildP $ varE (putFuns typ) `appE` varE var | (typ, var) <- zip (conTypes con) putVars ] ++
+                                   [ noBindS $ varE 'return `appE` varE asName ])
+               clause [putClause] (normalB putCopyBody) []
+
+mkGetCopy :: DeriveType -> String -> [(Integer, Con)] -> DecQ
+mkGetCopy deriveType tyName cons = valD (varP 'getCopy) (normalB $ varE 'contain `appE` mkLabel) []
+    where
+      mkLabel = getCopyBody
+      getCopyBody
+          = case cons of
+              [(_, con)] | not (forceTag deriveType) -> mkGetBody con
+              _ -> do
+                tagVar <- newName "tag"
+                doE [ bindS (varP tagVar) (varE 'poke)
+                    , noBindS $ caseE (varE tagVar) (
+                        [ match (litP $ IntegerL i) (normalB $ mkGetBody con) [] | (i, con) <- cons ] ++
+                        [ match wildP (normalB $ varE 'fail `appE` errorMsg tagVar) [] ]) ]
+      mkGetBody con
+          = do (getFunsDecs, getFuns) <- case deriveType of
+                                           Normal -> mkSafeFunctions "safeGet_" 'getSafeGet con
+                                           _      -> return ([], const 'safeGet)
+               let getBase = appE (varE 'return) (conE (conName con))
+                   getArgs = foldl (\a t -> infixE (Just a) (varE '(<*>)) (Just (varE (getFuns t)))) getBase (conTypes con)
+               doE (getFunsDecs ++ [noBindS getArgs])
+      errorMsg tagVar = infixE (Just $ strE str1) (varE '(++)) $ Just $
+                        infixE (Just tagStr) (varE '(++)) (Just $ strE str2)
+          where
+            strE = litE . StringL
+            tagStr = varE 'show `appE` varE tagVar
+            str1 = "Could not identify tag \""
+            str2 = concat [ "\" for type "
+                          , show tyName
+                          , " that has only "
+                          , show (length cons)
+                          , " constructors.  Maybe your data is corrupted?" ]
+
+mkSafeFunctions :: String -> Name -> Con -> Q ([StmtQ], Type -> Name)
+mkSafeFunctions name baseFun con = do let origTypes = conTypes con
+                                      realTypes <- mapM followSynonyms origTypes
+                                      finish (zip origTypes realTypes) <$> foldM go ([], []) realTypes
+    where go (ds, fs) t
+              | found     = return (ds, fs)
+              | otherwise = do funVar <- newName (name ++ typeName t)
+                               return ( bindS (varP funVar) (varE baseFun) : ds
+                                      , (t, funVar) : fs )
+              where found = any ((== t) . fst) fs
+          finish
+            :: [(Type, Type)]            -- "dictionary" from synonyms(or not) to real types
+            -> ([StmtQ], [(Type, Name)]) -- statements
+            -> ([StmtQ], Type -> Name)   -- function body and name-generator
+          finish typeList (ds, fs) = (reverse ds, getName)
+              where getName typ = fromMaybe err $ lookup typ typeList >>= flip lookup fs
+                    err = error "mkSafeFunctions: never here"
+
+-- | Follow type synonyms.  This allows us to see, for example,
+-- that @[Char]@ and @String@ are the same type and we just need
+-- to call 'getSafePut' or 'getSafeGet' once for both.
+followSynonyms :: Type -> Q Type
+followSynonyms t@(ConT name)
+    = maybe (return t) followSynonyms =<<
+      recover (return Nothing) (do info <- reify name
+                                   return $ case info of
+                                              TyVarI _ ty            -> Just ty
+                                              TyConI (TySynD _ _ ty) -> Just ty
+                                              _                      -> Nothing)
+followSynonyms (AppT ty1 ty2) = liftM2 AppT (followSynonyms ty1) (followSynonyms ty2)
+followSynonyms (SigT ty k)    = liftM (flip SigT k) (followSynonyms ty)
+followSynonyms t              = return t
+
+conSize :: Con -> Int
+conSize (NormalC _name args) = length args
+conSize (RecC _name recs)    = length recs
+conSize InfixC{}             = 2
+conSize ForallC{}            = error "Found constructor with existentially quantified binder. Cannot derive SafeCopy for it."
+#if MIN_VERSION_template_haskell(2,11,0)
+conSize GadtC{}              = error "Found GADT constructor. Cannot derive SafeCopy for it."
+conSize RecGadtC{}           = error "Found GADT constructor. Cannot derive SafeCopy for it."
+#endif
+
+conName :: Con -> Name
+conName (NormalC name _args) = name
+conName (RecC name _recs)    = name
+conName (InfixC _ name _)    = name
+conName _                    = error "conName: never here"
+
+conTypes :: Con -> [Type]
+conTypes (NormalC _name args)       = [t | (_, t)    <- args]
+conTypes (RecC _name args)          = [t | (_, _, t) <- args]
+conTypes (InfixC (_, t1) _ (_, t2)) = [t1, t2]
+conTypes _                          = error "conName: never here"
+
+typeName :: Type -> String
+typeName (VarT name) = nameBase name
+typeName (ConT name) = nameBase name
+typeName (TupleT n)  = "Tuple" ++ show n
+typeName ArrowT      = "Arrow"
+typeName ListT       = "List"
+typeName (AppT t u)  = typeName t ++ typeName u
+typeName (SigT t _k) = typeName t
+typeName _           = "_"
diff --git a/src/Data/SafeCopy/Store/Encode.hs b/src/Data/SafeCopy/Store/Encode.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/SafeCopy/Store/Encode.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Data.SafeCopy.Store.Encode where
+
+import Data.ByteString (ByteString)
+import Data.Monoid
+import Data.Store
+import Data.Store.Core
+
+data Encode a = Encode {-# UNPACK #-} !Int !(Poke ()) !a
+
+instance Monoid a => Monoid (Encode a) where
+  mempty = Encode 0 (Poke $ \_ offset -> pure (offset, ())) mempty
+  {-# INLINE mempty #-}
+
+  (Encode len1 f1 a1) `mappend` (Encode len2 f2 a2) = Encode (len1 + len2) (f1 *> f2) (a1 <> a2)
+  {-# INLINE mappend #-}
+
+instance Functor Encode where
+  fmap f (Encode l p a) = Encode l p (f a)
+  {-# INLINE fmap #-}
+
+instance Applicative Encode where
+  pure = Encode 0 (Poke $ \_ offset -> pure (offset, ()))
+  {-# INLINE pure #-}
+
+  (Encode len1 f1 af) <*> (Encode len2 f2 b) = Encode (len1 + len2) (f1 *> f2) (af b)
+  {-# INLINE (<*>) #-}
+
+instance Monad Encode where
+  return = pure
+  {-# INLINE return #-}
+
+  (Encode len1 f1 a) >>= ef = case ef a of
+    Encode len2 f2 b -> Encode (len1 + len2) (f1 *> f2) b
+  {-# INLINE (>>=) #-}
+
+getEncodeLen :: Encode a -> Int
+getEncodeLen (Encode len _ _) = len
+{-# INLINE getEncodeLen #-}
+
+runEncode :: Encode a -> ByteString
+runEncode (Encode len f _) = unsafeEncodeWith f len
+{-# INLINE runEncode #-}
+
+pokeE :: forall a . Store a => a -> Encode a
+pokeE v = Encode len (poke v) v
+  where
+    len = case (size :: Size a) of
+      VarSize sf -> sf v
+      ConstSize cs -> cs
+{-# INLINE pokeE #-}
diff --git a/src/Data/SafeCopy/Store/Instances.hs b/src/Data/SafeCopy/Store/Instances.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/SafeCopy/Store/Instances.hs
@@ -0,0 +1,468 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, UndecidableInstances, TypeFamilies #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Data.SafeCopy.Store.Instances where
+
+import Data.SafeCopy.Store.SafeCopy
+import Data.SafeCopy.Store.Encode
+
+#if !MIN_VERSION_base(4,8,0)
+import           Control.Applicative
+#endif
+import           Control.Monad
+import qualified Data.Array as Array
+import qualified Data.Array.Unboxed as UArray
+import qualified Data.Array.IArray as IArray
+import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Char8 as B
+import qualified Data.Foldable as Foldable
+import           Data.Fixed (HasResolution, Fixed)
+import           Data.Int
+import qualified Data.IntMap as IntMap
+import qualified Data.IntSet as IntSet
+import           Data.Ix
+import qualified Data.Map as Map
+import           Data.Ratio (Ratio, (%), numerator, denominator)
+import qualified Data.Sequence as Sequence
+import           Data.Store
+import qualified Data.Set as Set
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TL
+import           Data.Time.Calendar (Day(..))
+import           Data.Time.Clock (DiffTime, NominalDiffTime, UniversalTime(..), UTCTime(..))
+import           Data.Time.Clock.TAI (AbsoluteTime, taiEpoch, addAbsoluteTime, diffAbsoluteTime)
+import           Data.Time.LocalTime (LocalTime(..), TimeOfDay(..), TimeZone(..), ZonedTime(..))
+import qualified Data.Tree as Tree
+#if MIN_VERSION_base(4,7,0)
+import           Data.Typeable hiding (Proxy)
+#else
+import           Data.Typeable
+#endif
+import           Data.Word
+import           System.Time (ClockTime(..), TimeDiff(..), CalendarTime(..), Month(..))
+import qualified System.Time as OT
+import qualified Data.Vector as V
+import qualified Data.Vector.Generic as VG
+import qualified Data.Vector.Primitive as VP
+import qualified Data.Vector.Storable as VS
+import qualified Data.Vector.Unboxed as VU
+
+instance SafeCopy a => SafeCopy (Prim a) where
+  kind = primitive
+  getCopy = contain $
+            do e <- unsafeUnPack getCopy
+               return $ Prim e
+  putCopy (Prim e)
+    = contain $ unsafeUnPack (putCopy e) >> pure (Prim e)
+
+instance SafeCopy a => SafeCopy [a] where
+  getCopy = contain $ do
+    n <- peek
+    g <- getSafeGet
+    go g [] n
+      where
+        go :: Peek a -> [a] -> Int -> Peek [a]
+        go _ as 0 = return (reverse as)
+        go g as i = do x <- g
+                       x `seq` go g (x:as) (i - 1)
+  putCopy lst = contain $ do void $ pokeE (length lst)
+                             getSafePut >>= forM lst
+  errorTypeName = typeName1
+
+instance SafeCopy a => SafeCopy (Maybe a) where
+    getCopy = contain $ do n <- peek
+                           if n then fmap Just safeGet
+                                else return Nothing
+    putCopy (Just a) = contain $ pokeE True >> safePut a >> pure (Just a)
+    putCopy Nothing = contain $ pokeE False >> pure Nothing
+    errorTypeName = typeName1
+
+instance (SafeCopy a, Ord a) => SafeCopy (Set.Set a) where
+    getCopy = contain $ fmap Set.fromDistinctAscList safeGet
+    putCopy a = contain $ safePut (Set.toAscList a) >> pure a
+    errorTypeName = typeName1
+
+instance (SafeCopy a, SafeCopy b, Ord a) => SafeCopy (Map.Map a b) where
+    getCopy = contain $ fmap Map.fromDistinctAscList safeGet
+    putCopy a = contain $ safePut (Map.toAscList a) >> pure a
+    errorTypeName = typeName2
+
+instance (SafeCopy a) => SafeCopy (IntMap.IntMap a) where
+    getCopy = contain $ fmap IntMap.fromDistinctAscList safeGet
+    putCopy a = contain $ safePut (IntMap.toAscList a) >> pure a
+    errorTypeName = typeName1
+
+instance SafeCopy IntSet.IntSet where
+    getCopy = contain $ fmap IntSet.fromDistinctAscList safeGet
+    putCopy a = contain $ safePut (IntSet.toAscList a) >> pure a
+    errorTypeName = typeName
+
+instance (SafeCopy a) => SafeCopy (Sequence.Seq a) where
+    getCopy = contain $ fmap Sequence.fromList safeGet
+    putCopy a = contain $ safePut (Foldable.toList a) >> pure a
+    errorTypeName = typeName1
+
+instance (SafeCopy a) => SafeCopy (Tree.Tree a) where
+    getCopy = contain $ liftM2 Tree.Node safeGet safeGet
+    putCopy a@(Tree.Node root sub) = contain $ safePut root >> safePut sub >> pure a
+    errorTypeName = typeName1
+
+iarray_getCopy :: (Ix i, SafeCopy e, SafeCopy i, IArray.IArray a e) => Contained (Peek (a i e))
+iarray_getCopy = contain $ do getIx <- getSafeGet
+                              liftM3 mkArray getIx getIx safeGet
+    where
+      mkArray l h = IArray.listArray (l, h)
+{-# INLINE iarray_getCopy #-}
+
+iarray_putCopy :: (Ix i, SafeCopy e, SafeCopy i, IArray.IArray a e) => a i e -> Contained (Encode (a i e))
+iarray_putCopy arr = contain $ do putIx <- getSafePut
+                                  let (l,h) = IArray.bounds arr
+                                  _ <- putIx l >> putIx h
+                                  _ <- safePut (IArray.elems arr)
+                                  pure arr
+{-# INLINE iarray_putCopy #-}
+
+instance (Ix i, SafeCopy e, SafeCopy i) => SafeCopy (Array.Array i e) where
+    getCopy = iarray_getCopy
+    putCopy = iarray_putCopy
+    errorTypeName = typeName2
+
+instance (IArray.IArray UArray.UArray e, Ix i, SafeCopy e, SafeCopy i) => SafeCopy (UArray.UArray i e) where
+    getCopy = iarray_getCopy
+    putCopy = iarray_putCopy
+    errorTypeName = typeName2
+
+instance (SafeCopy a, SafeCopy b) => SafeCopy (a,b) where
+    getCopy = contain $ liftM2 (,) safeGet safeGet
+    putCopy (a,b) = contain $ safePut a >> safePut b >> pure (a,b)
+    errorTypeName = typeName2
+instance (SafeCopy a, SafeCopy b, SafeCopy c) => SafeCopy (a,b,c) where
+    getCopy = contain $ liftM3 (,,) safeGet safeGet safeGet
+    putCopy (a,b,c) = contain $ safePut a >> safePut b >> safePut c >> pure (a,b,c)
+instance (SafeCopy a, SafeCopy b, SafeCopy c, SafeCopy d) => SafeCopy (a,b,c,d) where
+    getCopy = contain $ liftM4 (,,,) safeGet safeGet safeGet safeGet
+    putCopy (a,b,c,d) = contain $ safePut a >> safePut b >> safePut c >> safePut d >> pure (a,b,c,d)
+instance (SafeCopy a, SafeCopy b, SafeCopy c, SafeCopy d, SafeCopy e) =>
+         SafeCopy (a,b,c,d,e) where
+    getCopy = contain $ liftM5 (,,,,) safeGet safeGet safeGet safeGet safeGet
+    putCopy (a,b,c,d,e) = contain $ safePut a >> safePut b >> safePut c >> safePut d >> safePut e >> pure (a,b,c,d,e)
+instance (SafeCopy a, SafeCopy b, SafeCopy c, SafeCopy d, SafeCopy e, SafeCopy f) =>
+         SafeCopy (a,b,c,d,e,f) where
+    getCopy = contain $ (,,,,,) <$> safeGet <*> safeGet <*> safeGet <*> safeGet <*> safeGet <*> safeGet
+    putCopy (a,b,c,d,e,f) = contain $ safePut a >> safePut b >> safePut c >> safePut d >>
+                                      safePut e >> safePut f >> pure (a,b,c,d,e,f)
+instance (SafeCopy a, SafeCopy b, SafeCopy c, SafeCopy d, SafeCopy e, SafeCopy f, SafeCopy g) =>
+         SafeCopy (a,b,c,d,e,f,g) where
+    getCopy = contain $ (,,,,,,) <$> safeGet <*> safeGet <*> safeGet <*> safeGet <*>
+                                     safeGet <*> safeGet <*> safeGet
+    putCopy (a,b,c,d,e,f,g) = contain $ safePut a >> safePut b >> safePut c >> safePut d >>
+                                        safePut e >> safePut f >> safePut g >> pure (a,b,c,d,e,f,g)
+
+
+instance SafeCopy Int where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Integer where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+
+-- | cereal change the formats for Float/Double in 0.5.*
+--
+-- https://github.com/GaloisInc/cereal/commit/47d839609413e3e9d1147b99c34ae421ae36bced
+-- https://github.com/GaloisInc/cereal/issues/35
+newtype CerealFloat040 = CerealFloat040 { unCerealFloat040 :: Float} deriving (Show, Typeable)
+instance SafeCopy CerealFloat040 where
+    getCopy = contain (CerealFloat040 <$> liftM2 encodeFloat peek peek)
+    putCopy a@(CerealFloat040 float) = contain $ pokeE (decodeFloat float) >> pure a
+    errorTypeName = typeName
+
+instance Migrate Float where
+  type MigrateFrom Float = CerealFloat040
+  migrate (CerealFloat040 d) = d
+
+instance SafeCopy Float where
+  version = Version 1
+  kind = extension
+  getCopy = contain peek
+  putCopy = contain . pokeE
+  errorTypeName = typeName
+
+-- | cereal change the formats for Float/Double in 0.5.*
+--
+-- https://github.com/GaloisInc/cereal/commit/47d839609413e3e9d1147b99c34ae421ae36bced
+-- https://github.com/GaloisInc/cereal/issues/35
+newtype CerealDouble040 = CerealDouble040 { unCerealDouble040 :: Double} deriving (Show, Typeable)
+instance SafeCopy CerealDouble040 where
+    getCopy = contain (CerealDouble040 <$> liftM2 encodeFloat peek peek)
+    putCopy a@(CerealDouble040 double) = contain $ pokeE (decodeFloat double) >> pure a
+    errorTypeName = typeName
+
+instance Migrate Double where
+  type MigrateFrom Double = CerealDouble040
+  migrate (CerealDouble040 d) = d
+
+instance SafeCopy Double where
+  version = Version 1
+  kind = extension
+  getCopy = contain peek
+  putCopy = contain . pokeE
+  errorTypeName = typeName
+
+instance Store Ordering
+
+instance SafeCopy L.ByteString where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy B.ByteString where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Char where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Word where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Word8 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Word16 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Word32 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Word64 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Ordering where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Int8 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Int16 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Int32 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Int64 where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance (Integral a, SafeCopy a) => SafeCopy (Ratio a) where
+    getCopy   = contain $ do n <- safeGet
+                             d <- safeGet
+                             return (n % d)
+    putCopy r = contain $ do void $ safePut (numerator   r)
+                             void $ safePut (denominator r)
+                             pure r
+    errorTypeName = typeName1
+instance (HasResolution a, Fractional (Fixed a)) => SafeCopy (Fixed a) where
+    getCopy   = contain $ fromRational <$> safeGet
+    putCopy a = contain $ safePut (toRational a) >> pure a
+    errorTypeName = typeName1
+
+instance SafeCopy () where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance SafeCopy Bool where
+    getCopy = contain peek; putCopy = contain . pokeE; errorTypeName = typeName
+instance (SafeCopy a, SafeCopy b) => SafeCopy (Either a b) where
+    getCopy = contain $ do n <- peek
+                           if n then fmap Right safeGet
+                                else fmap Left safeGet
+    putCopy e@(Right a) = contain $ pokeE True >> safePut a >> pure e
+    putCopy e@(Left a) = contain $ pokeE False >> safePut a >> pure e
+
+    errorTypeName = typeName2
+
+--  instances for 'text' library
+
+instance SafeCopy T.Text where
+    kind = base
+    getCopy = contain $ T.decodeUtf8 <$> safeGet
+    putCopy e = contain $ safePut (T.encodeUtf8 e) >> pure e
+    errorTypeName = typeName
+
+instance SafeCopy TL.Text where
+    kind = base
+    getCopy = contain $ TL.decodeUtf8 <$> safeGet
+    putCopy e = contain $ safePut (TL.encodeUtf8 e) >> pure e
+    errorTypeName = typeName
+
+-- instances for 'time' library
+
+instance SafeCopy Day where
+    kind = base
+    getCopy = contain $ ModifiedJulianDay <$> safeGet
+    putCopy e = contain $ safePut (toModifiedJulianDay e) >> pure e
+    errorTypeName = typeName
+
+instance SafeCopy DiffTime where
+    kind = base
+    getCopy = contain $ fromRational <$> safeGet
+    putCopy e = contain $ safePut (toRational e) >> pure e
+    errorTypeName = typeName
+
+instance SafeCopy UniversalTime where
+    kind = base
+    getCopy = contain $ ModJulianDate <$> safeGet
+    putCopy e = contain $ safePut (getModJulianDate e) >> pure e
+    errorTypeName = typeName
+
+instance SafeCopy UTCTime where
+    kind = base
+    getCopy   = contain $ do day      <- safeGet
+                             diffTime <- safeGet
+                             return (UTCTime day diffTime)
+    putCopy u = contain $ do void $ safePut (utctDay u)
+                             void $ safePut (utctDayTime u)
+                             pure u
+    errorTypeName = typeName
+
+instance SafeCopy NominalDiffTime where
+    kind = base
+    getCopy = contain $ fromRational <$> safeGet
+    putCopy e = contain $ safePut (toRational e) >> pure e
+    errorTypeName = typeName
+
+instance SafeCopy TimeOfDay where
+    kind = base
+    getCopy   = contain $ do hour <- safeGet
+                             mins <- safeGet
+                             sec  <- safeGet
+                             return (TimeOfDay hour mins sec)
+    putCopy t = contain $ do void $ safePut (todHour t)
+                             void $ safePut (todMin t)
+                             void $ safePut (todSec t)
+                             pure t
+    errorTypeName = typeName
+
+instance SafeCopy TimeZone where
+    kind = base
+    getCopy   = contain $ do mins       <- safeGet
+                             summerOnly <- safeGet
+                             zoneName   <- safeGet
+                             return (TimeZone mins summerOnly zoneName)
+    putCopy t = contain $ do void $ safePut (timeZoneMinutes t)
+                             void $ safePut (timeZoneSummerOnly t)
+                             void $ safePut (timeZoneName t)
+                             pure t
+    errorTypeName = typeName
+
+instance SafeCopy LocalTime where
+    kind = base
+    getCopy   = contain $ do day <- safeGet
+                             tod <- safeGet
+                             return (LocalTime day tod)
+    putCopy t = contain $ do void $ safePut (localDay t)
+                             void $ safePut (localTimeOfDay t)
+                             pure t
+    errorTypeName = typeName
+
+instance SafeCopy ZonedTime where
+    kind = base
+    getCopy   = contain $ do localTime <- safeGet
+                             timeZone  <- safeGet
+                             return (ZonedTime localTime timeZone)
+    putCopy t = contain $ do void $ safePut (zonedTimeToLocalTime t)
+                             void $ safePut (zonedTimeZone t)
+                             pure t
+    errorTypeName = typeName
+
+instance SafeCopy AbsoluteTime where
+  getCopy = contain $ fmap toAbsoluteTime safeGet
+    where
+      toAbsoluteTime :: DiffTime -> AbsoluteTime
+      toAbsoluteTime dt = addAbsoluteTime dt taiEpoch
+  putCopy e = contain $ safePut (fromAbsoluteTime e) >> pure e
+    where
+      fromAbsoluteTime :: AbsoluteTime -> DiffTime
+      fromAbsoluteTime at = diffAbsoluteTime at taiEpoch
+  errorTypeName = typeName
+
+-- instances for old-time
+
+instance SafeCopy ClockTime where
+    kind = base
+    getCopy = contain $ do secs <- safeGet
+                           pico <- safeGet
+                           return (TOD secs pico)
+    putCopy e@(TOD secs pico) =
+              contain $ do void $ safePut secs
+                           void $ safePut pico
+                           pure e
+
+instance SafeCopy TimeDiff where
+    kind = base
+    getCopy   = contain $ do year    <- peek
+                             month   <- peek
+                             day     <- peek
+                             hour    <- peek
+                             mins    <- peek
+                             sec     <- peek
+                             pico    <- peek
+                             return (TimeDiff year month day hour mins sec pico)
+    putCopy t = contain $ do void $ pokeE (tdYear t)
+                             void $ pokeE (tdMonth t)
+                             void $ pokeE (tdDay t)
+                             void $ pokeE (tdHour t)
+                             void $ pokeE (tdMin t)
+                             void $ pokeE (tdSec t)
+                             void $ pokeE (tdPicosec t)
+                             pure t
+
+instance SafeCopy OT.Day where
+    kind = base ; getCopy = contain $ toEnum <$> peek ; putCopy a = contain $ pokeE (fromEnum a) >> pure a
+
+instance SafeCopy Month where
+    kind = base ; getCopy = contain $ toEnum <$> peek ; putCopy a = contain $ pokeE (fromEnum a) >> pure a
+
+
+instance SafeCopy CalendarTime where
+    kind = base
+    getCopy   = contain $ do year   <- peek
+                             month  <- safeGet
+                             day    <- peek
+                             hour   <- peek
+                             mins   <- peek
+                             sec    <- peek
+                             pico   <- peek
+                             wday   <- safeGet
+                             yday   <- peek
+                             tzname <- safeGet
+                             tz     <- peek
+                             dst    <- peek
+                             return (CalendarTime year month day hour mins sec pico wday yday tzname tz dst)
+    putCopy t = contain $ do void $ pokeE   (ctYear t)
+                             void $ safePut (ctMonth t)
+                             void $ pokeE   (ctDay t)
+                             void $ pokeE   (ctHour t)
+                             void $ pokeE   (ctMin t)
+                             void $ pokeE   (ctSec t)
+                             void $ pokeE   (ctPicosec t)
+                             void $ safePut (ctWDay t)
+                             void $ pokeE   (ctYDay t)
+                             void $ safePut (ctTZName t)
+                             void $ pokeE   (ctTZ t)
+                             void $ pokeE   (ctIsDST t)
+                             pure t
+
+typeName :: Typeable a => Proxy a -> String
+typeName proxy = show (typeOf (undefined `asProxyType` proxy))
+
+typeName1 :: (Typeable c) => Proxy (c a) -> String
+typeName1 proxy = show (typeOf1 (undefined `asProxyType` proxy))
+
+typeName2 :: (Typeable c) => Proxy (c a b) -> String
+typeName2 proxy = show (typeOf2 (undefined `asProxyType` proxy))
+
+getGenericVector :: (SafeCopy a, VG.Vector v a) => Contained (Peek (v a))
+getGenericVector = contain $ do n <- peek
+                                getSafeGet >>= VG.replicateM n
+
+putGenericVector :: (SafeCopy a, VG.Vector v a) => v a -> Contained (Encode (v a))
+putGenericVector v = contain $ do void $ pokeE (VG.length v)
+                                  getSafePut >>= VG.forM v
+
+instance SafeCopy a => SafeCopy (V.Vector a) where
+    getCopy = getGenericVector
+    putCopy = putGenericVector
+
+instance (SafeCopy a, VP.Prim a) => SafeCopy (VP.Vector a) where
+    getCopy = getGenericVector
+    putCopy = putGenericVector
+
+instance (SafeCopy a, VS.Storable a) => SafeCopy (VS.Vector a) where
+    getCopy = getGenericVector
+    putCopy = putGenericVector
+
+instance (SafeCopy a, VU.Unbox a) => SafeCopy (VU.Vector a) where
+    getCopy = getGenericVector
+    putCopy = putGenericVector
diff --git a/src/Data/SafeCopy/Store/Internal.hs b/src/Data/SafeCopy/Store/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/SafeCopy/Store/Internal.hs
@@ -0,0 +1,9 @@
+module Data.SafeCopy.Store.Internal (
+    module Data.SafeCopy.Store.SafeCopy
+  , module Data.SafeCopy.Store.Encode
+  , module Data.SafeCopy.Store.Derive
+  ) where
+
+import Data.SafeCopy.Store.Derive
+import Data.SafeCopy.Store.Encode
+import Data.SafeCopy.Store.SafeCopy
diff --git a/src/Data/SafeCopy/Store/SafeCopy.hs b/src/Data/SafeCopy/Store/SafeCopy.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/SafeCopy/Store/SafeCopy.hs
@@ -0,0 +1,394 @@
+{-# LANGUAGE GADTs, TypeFamilies, FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE CPP #-}
+#ifdef DEFAULT_SIGNATURES
+{-# LANGUAGE DefaultSignatures #-}
+#endif
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.SafeCopy.SafeCopy
+-- Copyright   :  PublicDomain
+--
+-- Maintainer  :  lemmih@gmail.com
+-- Portability :  non-portable (uses GHC extensions)
+--
+-- SafeCopy extends the parsing and serialization capabilities of Data.Binary
+-- to include nested version control. Nested version control means that you
+-- can change the defintion and binary format of a type nested deep within
+-- other types without problems.
+--
+module Data.SafeCopy.Store.SafeCopy where
+
+import Data.Store
+import Data.SafeCopy.Store.Encode
+
+import Control.Monad
+import Data.Int (Int32)
+import Data.List
+
+-- | The central mechanism for dealing with version control.
+--
+--   This type class specifies what data migrations can happen
+--   and how they happen.
+class SafeCopy (MigrateFrom a) => Migrate a where
+    -- | This is the type we're extending. Each type capable of migration can
+    --   only extend one other type.
+    type MigrateFrom a
+
+    -- | This method specifies how to migrate from the older type to the newer
+    --   one. It will never be necessary to use this function manually as it
+    --   all taken care of internally in the library.
+    migrate :: MigrateFrom a -> a
+
+-- | This is a wrapper type used migrating backwards in the chain of compatible types.
+newtype Reverse a = Reverse { unReverse :: a }
+
+-- | The kind of a data type determines how it is tagged (if at all).
+--
+--   Primitives kinds (see 'primitive') are not tagged with a version
+--   id and hence cannot be extended later.
+--
+--   Extensions (see 'extension') tells the system that there exists
+--   a previous version of the data type which should be migrated if
+--   needed.
+--
+--   There is also a default kind which is neither primitive nor is
+--   an extension of a previous type.
+data Kind a where
+    Primitive :: Kind a
+    Base      :: Kind a
+    Extends   :: (Migrate a) => Proxy (MigrateFrom a) -> Kind a
+    Extended  :: (Migrate (Reverse a)) => Kind a -> Kind a
+
+isPrimitive :: Kind a -> Bool
+isPrimitive Primitive = True
+isPrimitive _ = False
+
+-- | Wrapper for data that was saved without a version tag.
+newtype Prim a = Prim { getPrimitive :: a }
+
+-- | The centerpiece of this library. Defines a version for a data type
+--   together with how it should be serialized/parsed.
+--
+--   Users should define instances of 'SafeCopy' for their types
+--   even though 'getCopy' and 'putCopy' can't be used directly.
+--   To serialize/parse a data type using 'SafeCopy', see 'safeGet'
+--   and 'safePut'.
+class SafeCopy a where
+    -- | The version of the type.
+    --
+    --   Only used as a key so it must be unique (this is checked at run-time)
+    --   but doesn't have to be sequential or continuous.
+    --
+    --   The default version is '0'.
+    version :: Version a
+    version = Version 0
+
+    -- | The kind specifies how versions are dealt with. By default,
+    --   values are tagged with their version id and don't have any
+    --   previous versions. See 'extension' and the much less used
+    --   'primitive'.
+    kind :: Kind a
+    kind = Base
+
+    -- | This method defines how a value should be parsed without also worrying
+    --   about writing out the version tag. This function cannot be used directly.
+    --   One should use 'safeGet', instead.
+    getCopy  :: Contained (Peek a)
+
+    -- | This method defines how a value should be parsed without worrying about
+    --   previous versions or migrations. This function cannot be used directly.
+    --   One should use 'safeGet', instead.
+    putCopy  :: a -> Contained (Encode a)
+
+    -- | Internal function that should not be overrided.
+    --   @Consistent@ iff the version history is consistent
+    --   (i.e. there are no duplicate version numbers) and
+    --   the chain of migrations is valid.
+    --
+    --   This function is in the typeclass so that this
+    --   information is calculated only once during the program
+    --   lifetime, instead of everytime 'safeGet' or 'safePut' is
+    --   used.
+    internalConsistency :: Consistency a
+    internalConsistency = computeConsistency Proxy
+
+    -- | Version profile.
+    objectProfile :: Profile a
+    objectProfile = mkProfile Proxy
+
+    -- | The name of the type. This is only used in error
+    -- message strings.
+    -- Feel free to leave undefined in your instances.
+    errorTypeName :: Proxy a -> String
+    errorTypeName _ = "<unkown type>"
+
+#ifdef DEFAULT_SIGNATURES
+    default getCopy :: Store a => Contained (Peek a)
+    getCopy = contain peek
+
+    default putCopy :: Store a => a -> Contained (Encode a)
+    putCopy = contain . pokeE
+#endif
+
+
+-- constructGetterFromVersion :: SafeCopy a => Version a -> Kind (MigrateFrom (Reverse a)) -> Get (Peek a)
+constructGetterFromVersion :: SafeCopy a => Version a -> Kind a -> Either String (Peek a)
+constructGetterFromVersion diskVersion orig_kind =
+  worker False diskVersion orig_kind
+  where
+    worker :: forall a. SafeCopy a => Bool -> Version a -> Kind a -> Either String (Peek a)
+    worker fwd thisVersion thisKind
+      | version == thisVersion = return $ unsafeUnPack getCopy
+      | otherwise =
+        case thisKind of
+          Primitive -> Left $ errorMsg thisKind "Cannot migrate from primitive types."
+          Base      -> Left $ errorMsg thisKind versionNotFound
+          Extends b_proxy -> do
+            previousGetter <- worker fwd (castVersion diskVersion) (kindFromProxy b_proxy)
+            return $ fmap migrate previousGetter
+          Extended{} | fwd -> Left $ errorMsg thisKind versionNotFound
+          Extended a_kind -> do
+            let rev_proxy :: Proxy (MigrateFrom (Reverse a))
+                rev_proxy = Proxy
+                forwardGetter :: Either String (Peek a)
+                forwardGetter  = fmap (fmap (unReverse . migrate)) $ worker True (castVersion thisVersion) (kindFromProxy rev_proxy)
+                previousGetter :: Either String (Peek a)
+                previousGetter = worker fwd (castVersion thisVersion) a_kind
+            case forwardGetter of
+              Left{}    -> previousGetter
+              Right val -> Right val
+    versionNotFound   = "Cannot find getter associated with this version number: " ++ show diskVersion
+    errorMsg fail_kind msg =
+        concat
+         [ "safecopy: "
+         , errorTypeName (proxyFromKind fail_kind)
+         , ": "
+         , msg
+         ]
+
+-------------------------------------------------
+-- The public interface. These functions are used
+-- to parse/serialize and to create new parsers &
+-- serialisers.
+
+-- | Parse a version tagged data type and then migrate it to the desired type.
+--   Any serialized value has been extended by the return type can be parsed.
+safeGet :: SafeCopy a => Peek a
+safeGet
+    = join getSafeGet
+
+-- | Parse a version tag and return the corresponding migrated parser. This is
+--   useful when you can prove that multiple values have the same version.
+--   See 'getSafePut'.
+getSafeGet :: forall a. SafeCopy a => Peek (Peek a)
+getSafeGet
+    = checkConsistency proxy $
+      case kindFromProxy proxy of
+        Primitive -> return $ unsafeUnPack getCopy
+        a_kind    -> do v <- peek
+                        case constructGetterFromVersion v a_kind of
+                          Right getter -> return getter
+                          Left msg     -> fail msg
+    where proxy = Proxy :: Proxy a
+
+-- | Serialize a data type by first writing out its version tag. This is much
+--   simpler than the corresponding 'safeGet' since previous versions don't
+--   come into play.
+safePut :: SafeCopy a => a -> Encode a
+safePut a
+    = do putter <- getSafePut
+         putter a
+
+-- | Serialize the version tag and return the associated putter. This is useful
+--   when serializing multiple values with the same version. See 'getSafeGet'.
+getSafePut :: forall a. SafeCopy a => Encode (a -> Encode a)
+getSafePut
+    = checkConsistency proxy $
+      case kindFromProxy proxy of
+        Primitive -> return $ \a -> unsafeUnPack (putCopy $ asProxyType a proxy)
+        _         -> do _ <- pokeE (versionFromProxy proxy)
+                        return $ \a -> unsafeUnPack (putCopy $ asProxyType a proxy)
+    where proxy = Proxy :: Proxy a
+
+-- | The extended_base kind lets the system know that there is
+--   at least one future version of this type.
+extended_extension :: (SafeCopy a, Migrate a, Migrate (Reverse a)) => Kind a
+extended_extension = Extended extension
+
+-- | The extended_base kind lets the system know that there is
+--   at least one future version of this type.
+extended_base :: (Migrate (Reverse a)) => Kind a
+extended_base = Extended base
+
+-- | The extension kind lets the system know that there is
+--   at least one previous version of this type. A given data type
+--   can only extend a single other data type. However, it is
+--   perfectly fine to build chains of extensions. The migrations
+--   between each step is handled automatically.
+extension :: (SafeCopy a, Migrate a) => Kind a
+extension = Extends Proxy
+
+-- | The default kind. Does not extend any type.
+base :: Kind a
+base = Base
+
+-- | Primitive kinds aren't version tagged. This kind is used for small or built-in
+--   types that won't change such as 'Int' or 'Bool'.
+primitive :: Kind a
+primitive = Primitive
+
+-------------------------------------------------
+-- Data type versions. Essentially just a unique
+-- identifier used to lookup the corresponding
+-- parser function.
+
+-- | A simple numeric version id.
+newtype Version a = Version {unVersion :: Int32} deriving (Read,Show,Eq,Store)
+
+castVersion :: Version a -> Version b
+castVersion (Version a) = Version a
+
+instance Num (Version a) where
+    Version a + Version b = Version (a+b)
+    Version a - Version b = Version (a-b)
+    Version a * Version b = Version (a*b)
+    negate (Version a) = Version (negate a)
+    abs (Version a) = Version (abs a)
+    signum (Version a) = Version (signum a)
+    fromInteger i = Version (fromInteger i)
+
+-------------------------------------------------
+-- Container type to control the access to the
+-- parsers/putters.
+
+-- | To ensure that no-one reads or writes values without handling versions
+--   correct, it is necessary to restrict access to 'getCopy' and 'putCopy'.
+--   This is where 'Contained' enters the picture. It allows you to put
+--   values in to a container but not to take them out again.
+newtype Contained a = Contained {unsafeUnPack :: a}
+
+-- | Place a value in an unbreakable container.
+contain :: a -> Contained a
+contain = Contained
+
+-------------------------------------------------
+-- Consistency checking
+
+data Profile a =
+  PrimitiveProfile |
+  InvalidProfile String |
+  Profile
+  { profileCurrentVersion :: Int32
+  , profileSupportedVersions :: [Int32]
+  } deriving (Show)
+
+mkProfile :: SafeCopy a => Proxy a -> Profile a
+mkProfile a_proxy =
+  case computeConsistency a_proxy of
+    NotConsistent msg -> InvalidProfile msg
+    Consistent | isPrimitive (kindFromProxy a_proxy) -> PrimitiveProfile
+    Consistent ->
+      Profile{ profileCurrentVersion    = unVersion (versionFromProxy a_proxy)
+             , profileSupportedVersions = availableVersions a_proxy
+             }
+
+data Consistency a = Consistent | NotConsistent String
+
+availableVersions :: SafeCopy a => Proxy a -> [Int32]
+availableVersions a_proxy =
+  worker True (kindFromProxy a_proxy)
+  where
+    worker :: SafeCopy b => Bool -> Kind b -> [Int32]
+    worker fwd b_kind =
+      case b_kind of
+        Primitive         -> []
+        Base              -> [unVersion (versionFromKind b_kind)]
+        Extends b_proxy   -> unVersion (versionFromKind b_kind) : worker False (kindFromProxy b_proxy)
+        Extended sub_kind | fwd  -> worker False (getForwardKind sub_kind)
+        Extended sub_kind -> worker False sub_kind
+
+getForwardKind :: (Migrate (Reverse a)) => Kind a -> Kind (MigrateFrom (Reverse a))
+getForwardKind _ = kind
+
+-- Extend chains must end in a Base kind. Ending in a Primitive is an error.
+validChain :: SafeCopy a => Proxy a -> Bool
+validChain a_proxy =
+  worker (kindFromProxy a_proxy)
+  where
+    worker Primitive         = True
+    worker Base              = True
+    worker (Extends b_proxy) = check (kindFromProxy b_proxy)
+    worker (Extended a_kind)   = worker a_kind
+    check :: SafeCopy b => Kind b -> Bool
+    check b_kind
+              = case b_kind of
+                  Primitive       -> False
+                  Base            -> True
+                  Extends c_proxy -> check (kindFromProxy c_proxy)
+                  Extended sub_kind   -> check sub_kind
+
+-- Verify that the SafeCopy instance is consistent.
+checkConsistency :: (SafeCopy a, Monad m) => Proxy a -> m b -> m b
+checkConsistency proxy ks
+    = case consistentFromProxy proxy of
+        NotConsistent msg -> fail msg
+        Consistent        -> ks
+
+{-# INLINE computeConsistency #-}
+computeConsistency :: SafeCopy a => Proxy a -> Consistency a
+computeConsistency proxy
+    -- Match a few common cases before falling through to the general case.
+    -- This allows use to generate nearly all consistencies at compile-time.
+    | isObviouslyConsistent (kindFromProxy proxy)
+    = Consistent
+    | versions /= nub versions
+    = NotConsistent $ "Duplicate version tags: " ++ show versions
+    | not (validChain proxy)
+    = NotConsistent "Primitive types cannot be extended as they have no version tag."
+    | otherwise
+    = Consistent
+    where versions = availableVersions proxy
+
+isObviouslyConsistent :: Kind a -> Bool
+isObviouslyConsistent Primitive = True
+isObviouslyConsistent Base      = True
+isObviouslyConsistent _         = False
+
+-------------------------------------------------
+-- Small utility functions that mean we don't
+-- have to depend on ScopedTypeVariables.
+
+proxyFromConsistency :: Consistency a -> Proxy a
+proxyFromConsistency _ = Proxy
+
+proxyFromKind :: Kind a -> Proxy a
+proxyFromKind _ = Proxy
+
+consistentFromProxy :: SafeCopy a => Proxy a -> Consistency a
+consistentFromProxy _ = internalConsistency
+
+versionFromProxy :: SafeCopy a => Proxy a -> Version a
+versionFromProxy _ = version
+
+versionFromKind :: (SafeCopy a) => Kind a -> Version a
+versionFromKind _ = version
+
+versionFromReverseKind :: (SafeCopy a, SafeCopy (MigrateFrom (Reverse a))) => Kind a -> Version (MigrateFrom (Reverse a))
+versionFromReverseKind _ = version
+
+kindFromProxy :: SafeCopy a => Proxy a -> Kind a
+kindFromProxy _ = kind
+
+-------------------------------------------------
+-- Type proxies
+
+data Proxy a = Proxy
+
+mkProxy :: a -> Proxy a
+mkProxy _ = Proxy
+
+asProxyType :: a -> Proxy a -> a
+asProxyType a _ = a
diff --git a/test/instances.hs b/test/instances.hs
new file mode 100644
--- /dev/null
+++ b/test/instances.hs
@@ -0,0 +1,170 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+-- Hack for bug in older Cabal versions
+#ifndef MIN_VERSION_template_haskell
+#define MIN_VERSION_template_haskell(x,y,z) 1
+#endif
+
+import Control.Lens
+import Control.Lens.Action
+import Data.Array (Array)
+import Data.Array.Unboxed (UArray)
+import Data.Data.Lens
+import Data.Fixed (Fixed, E1)
+import Data.List
+import Data.SafeCopy.Store
+import Data.Store (decodeWith)
+import Data.Time (ZonedTime(..))
+import Data.Tree (Tree)
+import Language.Haskell.TH
+import Language.Haskell.TH.Syntax
+import Test.QuickCheck.Instances ()
+import Test.Tasty
+import Test.Tasty.QuickCheck hiding (Fixed, (===))
+
+#if ! MIN_VERSION_QuickCheck(2,9,0)
+instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f) =>
+         Arbitrary (a,b,c,d,e,f) where
+   arbitrary = (,,,,,) <$> arbitrary <*> arbitrary <*> arbitrary <*>
+                           arbitrary <*> arbitrary <*> arbitrary
+
+instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f, Arbitrary g) =>
+         Arbitrary (a,b,c,d,e,f,g) where
+   arbitrary = (,,,,,,) <$> arbitrary <*> arbitrary <*> arbitrary <*>
+                            arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
+#endif
+
+#if ! MIN_VERSION_QuickCheck(2,8,2)
+instance (Arbitrary a) => Arbitrary (V.Vector a) where
+   arbitrary = V.fromList <$> arbitrary
+
+instance (Arbitrary a, VP.Prim a) => Arbitrary (VP.Vector a) where
+   arbitrary = VP.fromList <$> arbitrary
+
+instance (Arbitrary a, VS.Storable a) => Arbitrary (VS.Vector a) where
+   arbitrary = VS.fromList <$> arbitrary
+
+instance (Arbitrary a, VU.Unbox a) => Arbitrary (VU.Vector a) where
+   arbitrary = VU.fromList <$> arbitrary
+#endif
+
+deriving instance (Arbitrary a) => Arbitrary (Prim a)
+deriving instance (Eq a) => Eq (Prim a)
+deriving instance (Show a) => Show (Prim a)
+
+deriving instance Eq ZonedTime
+#if ! MIN_VERSION_time(1,6,0)
+deriving instance Show UniversalTime
+#endif
+
+data Example = Example {
+    exampleField1 :: String
+  , exampleField2 :: Bool
+  } deriving (Show, Eq)
+
+deriveSafeCopy 1 'base ''Example
+
+instance Arbitrary Example where
+  arbitrary = Example <$> arbitrary <*> arbitrary
+
+-- | Equality on the 'Right' value, showing the unequal value on failure;
+-- or explicit failure using the 'Left' message without equality testing.
+(===) :: (Eq a, Show a) => Either PeekException a -> a -> Property
+Left  e === _ = counterexample (show e) False
+Right a === b = counterexample (show a) $ a == b
+
+-- | An instance for 'SafeCopy' makes a type isomorphic to a bytestring
+-- serialization, which is to say that @decode . encode = id@, i.e.
+-- @decode@ is the inverse of @encode@ if we ignore bottom.
+prop_inverse :: (SafeCopy a, Arbitrary a, Eq a, Show a) => a -> Property
+prop_inverse a = (decode . encode) a === a where
+    encode = runEncode . safePut
+    decode = decodeWith safeGet
+
+-- | Test the 'prop_inverse' property against all 'SafeCopy' instances
+-- (that also satisfy the rest of the constraints) defaulting any type
+-- variables to 'Int'.
+do let a = conT ''Int
+
+   -- types we skip because the Int defaulting doesn't type check
+   excluded <- sequence
+      [ [t| Fixed $a |]
+      ]
+
+   -- instead we include these hand-defaulted types
+   included <- sequence
+      [ [t| Fixed E1 |]
+      , [t| Example |]
+      ]
+
+   -- types whose samples grow exponentially and need a lower maxSize
+   downsized <- sequence
+      [ [t| Array $a $a |]
+      , [t| UArray $a $a |]
+      , [t| Tree $a |]
+      ]
+
+   safecopy <- reify ''SafeCopy
+   preds <- 'prop_inverse ^!! act reify . (template :: Traversal' Info Pred)
+#if !MIN_VERSION_template_haskell(2,10,0)
+   classes <- mapM reify [ name | ClassP name _ <- preds ]
+#else
+--   print preds
+
+   classes <-
+         case preds of
+           [ForallT _ cxt' _] ->
+              mapM reify [ name | AppT (ConT name) _ <- cxt' ]
+           _ -> error "FIXME: fix this code to handle this case."
+--   classes <- mapM reify [ ]
+#endif
+   def <- a
+
+#if MIN_VERSION_template_haskell(2,11,0)
+   let instances (ClassI _ decs) = [ typ | InstanceD _ _ (AppT _ typ) _ <- decs ]
+#else
+   let instances (ClassI _ decs) = [ typ | InstanceD _ (AppT _ typ) _ <- decs ]
+#endif
+       instances _ = []
+       types = map instances classes
+
+       defaulting (VarT _) = def
+       defaulting t = t
+       defaulted = transformOn (traverse.traverse) defaulting types
+       wanted = transformOn traverse defaulting $ instances safecopy
+
+       common = foldl1 intersect defaulted
+       untested = wanted \\ common
+       exclusive = filter (`notElem` excluded) common
+
+       downsize typ | typ `elem` downsized = [| mapSize (`div` 5) |]
+                    | otherwise            = [| id |]
+
+       unqualifying (Name occ _) = Name occ NameS
+       name = pprint . transformOnOf template template unqualifying
+
+       prop typ =
+           [| testProperty $(litE . stringL $ name typ)
+               ($(downsize typ) (prop_inverse :: $(return typ) -> Property)) |]
+
+       props = listE . map prop
+
+#if !MIN_VERSION_template_haskell(2,8,0)
+       -- 'report' throws warnings in template-haskell-2.8.0.0
+       reportWarning = report False
+#endif
+
+   mapM_ (\typ -> reportWarning $ "not tested: " ++ name typ) untested
+
+   [d| inversions :: [TestTree]
+       inversions = $(props included) ++ $(props exclusive) |]
+
+main :: IO ()
+main = defaultMain $ testGroup "SafeCopy instances"
+    [ testGroup "decode is the inverse of encode" inversions
+    ]
