{-| Description : Serializing and deserializing binary data in a version safe manner Copyright : 2020 Sven Bartscher License : MPL-2.0 Maintainer : sven.bartscher@weltraumschlangen.de Stability : experimental Portability : GHC This module provides an infrastructure based on cereal to encode binary data in a version safe way. Data encoded in this way can in later versions of your code still be loaded, given that sufficient migration paths have been defined in your code. Assuming you have the following structure: @ data Foo = Foo Bar Baz deriving Generic data Bar = Bar Int deriving Generic data Baz = Baz String BazSub deriving Generic data BazSub = BazSub Integer deriving Generic @ and you want to encode them into a binary format you call “FooFormat“, then you define the following instances and helper types: @ data FooFormat instance DefinedVersion FooFormat 0 where type PreviousVersion FooFormat 0 = 'Nothing instance 'VersionedSerialize' FooFormat 0 Foo where type 'MigrationType' FooFormat 0 Foo = ''Base' instance 'VersionedSerialize' FooFormat 0 Bar where type 'MigrationType' FooFormat 0 = ''Base' instance 'VersionedSerialize' FooFormat 0 Baz where type 'MigrationType' FooFormat 0 = ''Base' instance 'VersionedSerialize' FooFormat 0 BazSub where type 'MigrationType' FooFormat 0 = ''Base' @ Serialization methods will be automatically derived based on the 'GHC.Generics.Generic' instances. This defines your initial format. You can encode a value of @Foo@ like this: @ foo :: Foo foo = Foo (Bar 1) (Baz "abc" (BazSub 2)) encoded :: 'Data.ByteString.ByteString' encoded = 'Data.Serialize.runPut' $ 'runVersionedPut' @FooFormat @0 $ 'putVersioned' foo decoded :: Foo decoded = 'Data.Serialize.runGet' ('runVersionedGet' @FooFormat @0 $ 'getVersioned') encoded @ If you now want to change the definition of @BazSub@ to the following: @ data BazSub = BazSub String deriving Generic @ you need to keep the old structure structure under a different name (rename the defined instance of 'VersionedSerialize' as well) @ data BazSubV0 = BazSubV0 Integer deriving Generic @ additionally you need to define the following instances (but keep the old instances for version 0!): @ instance DefinedVersion FooFormat 1 where type DefinedVersion FooFormat 1 = 'Just 0 instance 'VersionedSerialize' FooFormat 1 Foo where type 'MigrationType' = ''Unchanged' instance 'VersionedSerialize' FooFormat 1 Bar where type 'MigrateType = ''Unchanged' instance 'VersionedSerialize' FooFormat 1 Baz where type 'MigrationType' = ''Unchanged' instance 'VersionedSerialize FooFormat 1 BazSub where type 'MigrationType' = ''RepresentationChanged' BazSubV0 'migrate' (BazSubV0 x) = BazSub $ show x @ With these instances you could still decode the data encoded in an earlier version and get them automatically migrated to the version you specified in the type of the call to 'versionedGet'. -} module Data.Serialize.Versioned ( VersionDomain(..) , DefinedVersion(..) , VersionedSerialize(..) , VersionedGettable(..) , MigrationType(..) , module Data.Serialize.Versioned.Get , module Data.Serialize.Versioned.Put ) where import Data.Serialize.Versioned.Get import Data.Serialize.Versioned.Put import Data.Serialize.Versioned.Versioned