Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- class SafeCopy (MigrateFrom a) => Migrate a where
- type MigrateFrom a
- migrate :: MigrateFrom a -> a
- newtype Reverse a = Reverse {
- unReverse :: a
- data Kind a where
- isPrimitive :: Kind a -> Bool
- newtype Prim a = Prim {
- getPrimitive :: a
- class Typeable a => SafeCopy a where
- version :: Version a
- kind :: Kind a
- getCopy :: Contained (Get a)
- putCopy :: a -> Contained Put
- internalConsistency :: Consistency a
- objectProfile :: Profile a
- errorTypeName :: Proxy a -> String
- class GPutCopy f p where
- type SafeCopy' a = SafeCopy a
- class GPutFields f p where
- class GGetCopy f p where
- class GGetFields f p where
- data DatatypeInfo
- = ConstructorCount { }
- | ConstructorInfo { }
- getSafeGetGeneric :: forall a. SafeCopy a => StateT (Map TypeRep Int32) Get (Get a)
- getSafePutGeneric :: forall a. SafeCopy a => (a -> Contained Put) -> a -> RWST () [Put] (Set TypeRep) PutM ()
- type GSafeCopy a = (SafeCopy a, Generic a, GPutCopy (Rep a) DatatypeInfo, Constructors a)
- safePutGeneric :: forall a. GSafeCopy a => a -> Put
- putCopyDefault :: forall a. GSafeCopy a => a -> Contained Put
- constructGetterFromVersion :: SafeCopy a => Version a -> Kind a -> Either String (Get a)
- safeGet :: SafeCopy a => Get a
- getSafeGet :: forall a. SafeCopy a => Get (Get a)
- safePut :: SafeCopy a => a -> Put
- getSafePut :: forall a. SafeCopy a => PutM (a -> Put)
- extended_extension :: (Migrate a, Migrate (Reverse a)) => Kind a
- extended_base :: Migrate (Reverse a) => Kind a
- extension :: Migrate a => Kind a
- base :: Kind a
- primitive :: Kind a
- newtype Version a = Version {}
- castVersion :: Version a -> Version b
- newtype Contained a = Contained {
- unsafeUnPack :: a
- contain :: a -> Contained a
- data Profile a
- mkProfile :: SafeCopy a => Proxy a -> Profile a
- data Consistency a
- availableVersions :: SafeCopy a => Proxy a -> [Int32]
- getForwardKind :: Migrate (Reverse a) => Kind a -> Kind (MigrateFrom (Reverse a))
- validChain :: SafeCopy a => Proxy a -> Bool
- checkConsistency :: (SafeCopy a, MonadFail m) => Proxy a -> m b -> m b
- unpureCheckConsistency :: SafeCopy a => Proxy a -> b -> b
- computeConsistency :: forall a. SafeCopy a => Proxy a -> Consistency a
- isObviouslyConsistent :: Kind a -> Bool
- proxyFromConsistency :: Consistency a -> Proxy a
- proxyFromKind :: Kind a -> Proxy a
- consistentFromProxy :: SafeCopy a => Proxy a -> Consistency a
- versionFromProxy :: SafeCopy a => Proxy a -> Version a
- versionFromKind :: SafeCopy a => Kind a -> Version a
- versionFromReverseKind :: SafeCopy (MigrateFrom (Reverse a)) => Kind a -> Version (MigrateFrom (Reverse a))
- kindFromProxy :: SafeCopy a => Proxy a -> Kind a
- data Proxy a = Proxy
- mkProxy :: a -> Proxy a
- asProxyType :: a -> Proxy a -> a
- deriveSafeCopy :: Version a -> Name -> Name -> Q [Dec]
- deriveSafeCopyIndexedType :: Version a -> Name -> Name -> [Name] -> Q [Dec]
- deriveSafeCopySimple :: Version a -> Name -> Name -> Q [Dec]
- deriveSafeCopySimpleIndexedType :: Version a -> Name -> Name -> [Name] -> Q [Dec]
- deriveSafeCopyHappstackData :: Version a -> Name -> Name -> Q [Dec]
- deriveSafeCopyHappstackDataIndexedType :: Version a -> Name -> Name -> [Name] -> Q [Dec]
- data DeriveType
- forceTag :: DeriveType -> Bool
- tyVarName :: TyVarBndr -> Name
- internalDeriveSafeCopy :: DeriveType -> Version a -> Name -> Name -> Q [Dec]
- internalDeriveSafeCopy' :: DeriveType -> Version a -> Name -> Name -> Info -> Q [Dec]
- internalDeriveSafeCopyIndexedType :: DeriveType -> Version a -> Name -> Name -> [Name] -> Q [Dec]
- internalDeriveSafeCopyIndexedType' :: DeriveType -> Version a -> Name -> Name -> [Name] -> Info -> Q [Dec]
- mkPutCopy :: DeriveType -> [(Integer, Con)] -> DecQ
- mkGetCopy :: DeriveType -> String -> [(Integer, Con)] -> DecQ
- mkSafeFunctions :: String -> Name -> Con -> Q ([StmtQ], Type -> Name)
- followSynonyms :: Type -> Q Type
- conSize :: Con -> Int
- conName :: Con -> Name
- conTypes :: Con -> [Type]
- typeName :: Type -> String
Documentation
class SafeCopy (MigrateFrom a) => Migrate a where Source #
The central mechanism for dealing with version control.
This type class specifies what data migrations can happen and how they happen.
type MigrateFrom a Source #
This is the type we're extending. Each type capable of migration can only extend one other type.
migrate :: MigrateFrom a -> a Source #
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.
Instances
Migrate Double Source # | |
Defined in Data.SafeCopy.Instances type MigrateFrom Double Source # | |
Migrate Float Source # | |
Defined in Data.SafeCopy.Instances type MigrateFrom Float Source # |
This is a wrapper type used migrating backwards in the chain of compatible types.
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
) tell 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 an extension of a previous type.
isPrimitive :: Kind a -> Bool Source #
Wrapper for data that was saved without a version tag.
Prim | |
|
class Typeable a => SafeCopy a where Source #
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
.
Nothing
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'.
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
.
getCopy :: Contained (Get a) Source #
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.
default getCopy :: (GGetCopy (Rep a) DatatypeInfo, Constructors a) => Contained (Get a) Source #
putCopy :: a -> Contained Put Source #
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 'safePut, instead.
default putCopy :: (GPutCopy (Rep a) DatatypeInfo, Constructors a) => a -> Contained Put Source #
internalConsistency :: Consistency a Source #
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.
objectProfile :: Profile a Source #
Version profile.
errorTypeName :: Proxy a -> String Source #
The name of the type. This is only used in error message strings.
Instances
class GPutFields f p where Source #
gputFields traverses the fields of a constructor and returns a put for the safecopy versions and a put for the field values.
Instances
GPutFields (V1 :: Type -> Type) p Source # | |
Defined in Data.SafeCopy.SafeCopy | |
GPutFields (U1 :: Type -> Type) p Source # | |
Defined in Data.SafeCopy.SafeCopy | |
SafeCopy a => GPutFields (K1 R a :: Type -> Type) p Source # | |
(GPutFields f p, GPutFields g p) => GPutFields (f :*: g) p Source # | |
Defined in Data.SafeCopy.SafeCopy | |
GPutFields f p => GPutFields (M1 S c f) p Source # | |
class GGetCopy f p where Source #
Instances
(GGetCopy f p, GGetCopy g p, p ~ DatatypeInfo) => GGetCopy (f :+: g) p Source # | |
(GGetCopy f p, p ~ DatatypeInfo) => GGetCopy (M1 D d f) p Source # | The M1 type has a fourth type parameter p: newtype M1 i (c :: Meta) (f :: k -> *) (p :: k) = M1 {unM1 :: f p} Note that the type of the M1 field is |
GGetFields f p => GGetCopy (M1 C c f) p Source # | |
class GGetFields f p where Source #
Instances
GGetFields (V1 :: Type -> Type) p Source # | |
GGetFields (U1 :: Type -> Type) p Source # | |
SafeCopy a => GGetFields (K1 R a :: Type -> Type) p Source # | |
(GGetFields f p, GGetFields g p) => GGetFields (f :*: g) p Source # | |
GGetFields f p => GGetFields (M1 S c f) p Source # | |
data DatatypeInfo Source #
Instances
Show DatatypeInfo Source # | |
Defined in Data.SafeCopy.SafeCopy showsPrec :: Int -> DatatypeInfo -> ShowS # show :: DatatypeInfo -> String # showList :: [DatatypeInfo] -> ShowS # |
getSafeGetGeneric :: forall a. SafeCopy a => StateT (Map TypeRep Int32) Get (Get a) Source #
Whereas the other getSafeGet
is only run when we know we need a
version, this one is run for every field and must decide whether to
read a version or not. It constructs a Map TypeRep Int32 and reads
when the new TypeRep is not in the map.
getSafePutGeneric :: forall a. SafeCopy a => (a -> Contained Put) -> a -> RWST () [Put] (Set TypeRep) PutM () Source #
This version returns (Put, Put), the collected version tags and
the collected serialized fields. The original getSafePut
result
type prevents doing this because each fields may have a different
type. Maybe you can show me a better way
type GSafeCopy a = (SafeCopy a, Generic a, GPutCopy (Rep a) DatatypeInfo, Constructors a) Source #
safePutGeneric :: forall a. GSafeCopy a => a -> Put Source #
Generic only version of safePut. Instead of calling putCopy
it
calls putCopyDefault
, a copy of the implementation of the
SafeCopy
default method for putCopy
.
putCopyDefault :: forall a. GSafeCopy a => a -> Contained Put Source #
See safePutGeneric
. A copy of the code in the default
implementation of the putCopy method.
safeGet :: SafeCopy a => Get a Source #
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.
getSafeGet :: forall a. SafeCopy a => Get (Get a) Source #
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
.
safePut :: SafeCopy a => a -> Put Source #
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.
getSafePut :: forall a. SafeCopy a => PutM (a -> Put) Source #
Serialize the version tag and return the associated putter. This is useful
when serializing multiple values with the same version. See getSafeGet
.
extended_extension :: (Migrate a, Migrate (Reverse a)) => Kind a Source #
The extended_extension kind lets the system know that there is at least one previous and one future version of this type.
extended_base :: Migrate (Reverse a) => Kind a Source #
The extended_base kind lets the system know that there is at least one future version of this type.
extension :: Migrate a => Kind a Source #
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.
A simple numeric version id.
castVersion :: Version a -> Version b Source #
To ensure that no-one reads or writes values without handling versions
correctly, 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.
Contained | |
|
getForwardKind :: Migrate (Reverse a) => Kind a -> Kind (MigrateFrom (Reverse a)) Source #
unpureCheckConsistency :: SafeCopy a => Proxy a -> b -> b Source #
PutM doesn't have reasonable fail
implementation.
It just throws an unpure exception anyway.
computeConsistency :: forall a. SafeCopy a => Proxy a -> Consistency a Source #
isObviouslyConsistent :: Kind a -> Bool Source #
proxyFromConsistency :: Consistency a -> Proxy a Source #
proxyFromKind :: Kind a -> Proxy a Source #
consistentFromProxy :: SafeCopy a => Proxy a -> Consistency a Source #
versionFromReverseKind :: SafeCopy (MigrateFrom (Reverse a)) => Kind a -> Version (MigrateFrom (Reverse a)) Source #
asProxyType :: a -> Proxy a -> a Source #
deriveSafeCopy :: Version a -> Name -> Name -> Q [Dec] Source #
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 (T0 arg1 arg2) = contain $ do put_b <- getSafePut put_Int <- getSafePut put_b arg1 put_Int arg2 return () 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 (C arg1 arg2) = contain $ do putWord8 0 put_a <- getSafePut put_a arg1 put_a arg2 return () putCopy (D arg1 arg2) = contain $ do putWord8 1 put_b <- getSafePut put_Int <- getSafePut put_b arg1 put_Int arg2 return () 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.
deriveSafeCopySimple :: Version a -> Name -> Name -> Q [Dec] Source #
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 (C arg1 arg2) = contain $ do putWord8 0 safePut arg1 safePut arg2 return () putCopy (D arg1 arg2) = contain $ do putWord8 1 safePut arg1 safePut arg2 return () 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.
deriveSafeCopyHappstackData :: Version a -> Name -> Name -> Q [Dec] Source #
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 (T0 arg1 arg2) = contain $ do putWord8 0 safePut arg1 safePut arg2 return () 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.
forceTag :: DeriveType -> Bool Source #
internalDeriveSafeCopy :: DeriveType -> Version a -> Name -> Name -> Q [Dec] Source #
internalDeriveSafeCopy' :: DeriveType -> Version a -> Name -> Name -> Info -> Q [Dec] Source #
internalDeriveSafeCopyIndexedType :: DeriveType -> Version a -> Name -> Name -> [Name] -> Q [Dec] Source #
internalDeriveSafeCopyIndexedType' :: DeriveType -> Version a -> Name -> Name -> [Name] -> Info -> Q [Dec] Source #
followSynonyms :: Type -> Q Type Source #
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.