HORIZON HASKELLDocslts/ghc-10.0.x8c2f8e82026-10-19Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · 8c2f8e8 · 2026-10-19

Modulesafecopy-0.10.4.3Haskell2010

Data.SafeCopy.Internal

  • 12 types
  • 6 classes
  • 54 values
  • Packagesafecopy-0.10.4.3
  • Exports73
  • LanguageHaskell2010
  • LicenceLicenseRef-PublicDomain
  • SourceSafeCopy.hs
valuebase :: Kind a
#

The default kind. Does not extend any type.

valueextension :: Migrate a => Kind a
#

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.

valuegetSafeGet :: SafeCopy a => Get (Get a)
#

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.

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.

valuegetSafePut :: SafeCopy a => PutM (a -> Put)
#

Serialize the version tag and return the associated putter. This is useful when serializing multiple values with the same version. See getSafeGet.

valueprimitive :: Kind a
#

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.

valuesafeGet :: SafeCopy a => Get a
#

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.

valuesafePut :: SafeCopy a => a -> Put
#

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.

newtypenewtype Contained a
#

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.

Constructors

classclass GGetCopy (f :: Type -> Type) p where
#

Methods

Instances3GGetCopy
  • (GGetCopy f p, GGetCopy g p, p ~ DatatypeInfo) => GGetCopy (f :+: g) pDefined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
  • GGetFields f p => GGetCopy (M1 C c f) pDefined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
  • (GGetCopy f p, p ~ DatatypeInfo) => GGetCopy (M1 D d f) pDefined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy

    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 f p, so in order to express this type we add a parameter of type p that we can apply to values of type f.

classclass GGetFields (f :: Type -> Type) p where
#

Methods

Instances5GGetFields
classclass GPutFields (f :: Type -> Type) p where
#

gputFields traverses the fields of a constructor and returns a put for the safecopy versions and a put for the field values.

Methods

Instances5GPutFields
datadata Kind a where
#

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.

Constructors

classclass SafeCopy (MigrateFrom a) => Migrate a where
#

The central mechanism for dealing with version control.

This type class specifies what data migrations can happen and how they happen.

Associated types

  • type family MigrateFrom a

    This is the type we're extending. Each type capable of migration can only extend one other type.

Methods

  • migrate :: MigrateFrom a -> 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.

Instances2Migrate
  • Migrate DoubleDefined in safecopy-0.10.4.3 · Data.SafeCopy.Instances · orphan
  • Migrate FloatDefined in safecopy-0.10.4.3 · Data.SafeCopy.Instances · orphan
familytype family MigrateFrom a
#

This is the type we're extending. Each type capable of migration can only extend one other type.

Instances2MigrateFrom
  • type MigrateFrom Double = CerealDouble040Defined in safecopy-0.10.4.3 · Data.SafeCopy.Instances · orphan
  • type MigrateFrom Float = CerealFloat040Defined in safecopy-0.10.4.3 · Data.SafeCopy.Instances · orphan
newtypenewtype Prim a
#

Wrapper for data that was saved without a version tag.

Constructors

Instances1SafeCopy
newtypenewtype Reverse a
#

This is a wrapper type used migrating backwards in the chain of compatible types.

Constructors

classclass Typeable a => SafeCopy a where
#

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.

Methods

  • version :: Version a

    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'.

  • kind :: Kind a

    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)

    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.

  • putCopy :: a -> Contained Put

    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.

  • internalConsistency :: Consistency 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.

  • objectProfile :: Profile a

    Version profile.

  • errorTypeName :: Proxy a -> String

    The name of the type. This is only used in error message strings.

Instances64SafeCopy, …
newtypenewtype Version a
#

A simple numeric version id.

Constructors

Instances5Eq, Num, Read, Show, Serialize
  • Eq (Version a)Defined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
  • Num (Version a)Defined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
  • Read (Version a)Defined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
  • Show (Version a)Defined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
  • Serialize (Version a)Defined in safecopy-0.10.4.3 · Data.SafeCopy.SafeCopy
valuederiveSafeCopy :: Version a -> Name -> Name -> Q [Dec]
#

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.

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.

valuederiveSafeCopySimple :: Version a -> Name -> Name -> Q [Dec]
#

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.