Copyright | (C) 2015 Oleg Grenrus |
---|---|
License | BSD3 |
Maintainer | Oleg Grenrus <oleg.grenrus@iki.fi> |
Safe Haskell | None |
Language | Haskell2010 |
Structurally tag binary serialisation stream.
Say you have:
data Record = Record { _recordFields :: HM.HashMap Text (Integer, ByteString) , _recordEnabled :: Bool } deriving (Eq, Show, Generic) instance Binary Record instance HasStructuralInfo Record instance HasSemanticVersion Record
then you can serialise and deserialise Record
values with a structure tag by simply
encodeTaggedFile "cachefile" record decodeTaggedFile "cachefile" :: IO Record
If structure of Record
changes in between, deserialisation will fail early.
Synopsis
- newtype BinaryTagged (v :: k) a = BinaryTagged {
- unBinaryTagged :: a
- type BinaryTagged' a = BinaryTagged (SemanticVersion a) a
- binaryTag :: Proxy v -> a -> BinaryTagged v a
- binaryTag' :: HasSemanticVersion a => a -> BinaryTagged' a
- binaryUntag :: Proxy v -> BinaryTagged v a -> a
- binaryUntag' :: HasSemanticVersion a => BinaryTagged' a -> a
- data StructuralInfo
- taggedEncode :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => a -> ByteString
- taggedDecode :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => ByteString -> a
- taggedDecodeOrFail :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => ByteString -> Either (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
- taggedEncodeFile :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> a -> IO ()
- taggedDecodeFile :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> IO a
- taggedDecodeFileOrFail :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> IO (Either (ByteOffset, String) a)
- class HasStructuralInfo a where
- structuralInfo :: Proxy a -> StructuralInfo
- class KnownNat (SemanticVersion a) => HasSemanticVersion (a :: *) where
- type SemanticVersion a :: Nat
- type Version = Word32
- type Interleave (n :: Nat) (m :: Nat) = SumUpTo (n + m) + m
- type SumUpTo (n :: Nat) = Div2 (n * (n + 1))
- type family Div2 (n :: Nat) :: Nat where ...
- ghcStructuralInfo :: (Generic a, All2 HasStructuralInfo (GCode a), GDatatypeInfo a, SListI2 (GCode a)) => Proxy a -> StructuralInfo
- ghcNominalType :: (Generic a, GDatatypeInfo a) => Proxy a -> StructuralInfo
- ghcStructuralInfo1 :: forall f a. (Generic1 f, GDatatypeInfo (f a), HasStructuralInfo a) => Proxy (f a) -> StructuralInfo
- sopStructuralInfo :: forall a. (Generic a, HasDatatypeInfo a, All2 HasStructuralInfo (Code a)) => Proxy a -> StructuralInfo
- sopNominalType :: forall a. (Generic a, HasDatatypeInfo a) => Proxy a -> StructuralInfo
- sopStructuralInfo1 :: forall f a. (Generic (f a), HasDatatypeInfo (f a), HasStructuralInfo a) => Proxy (f a) -> StructuralInfo
- sopStructuralInfoS :: forall xss. (All2 HasStructuralInfo xss, SListI2 xss) => DatatypeInfo xss -> StructuralInfo
- sopNominalTypeS :: DatatypeInfo xss -> StructuralInfo
- sopStructuralInfo1S :: StructuralInfo -> DatatypeInfo xss -> StructuralInfo
- structuralInfoSha1Digest :: StructuralInfo -> Digest SHA1State
- structuralInfoSha1ByteStringDigest :: StructuralInfo -> ByteString
Data
newtype BinaryTagged (v :: k) a Source #
Binary
serialisable class, which tries to be less error-prone to data structure changes.
Values are serialised with header consisting of version v
and hash of structuralInfo
.
Instances
type BinaryTagged' a = BinaryTagged (SemanticVersion a) a Source #
binaryTag :: Proxy v -> a -> BinaryTagged v a Source #
binaryTag' :: HasSemanticVersion a => a -> BinaryTagged' a Source #
binaryUntag :: Proxy v -> BinaryTagged v a -> a Source #
binaryUntag' :: HasSemanticVersion a => BinaryTagged' a -> a Source #
data StructuralInfo Source #
Data type structure, with (some) nominal information.
Instances
Serialisation
taggedEncode :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => a -> ByteString Source #
Tagged version of encode
taggedDecode :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => ByteString -> a Source #
Tagged version of decode
taggedDecodeOrFail :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => ByteString -> Either (ByteString, ByteOffset, String) (ByteString, ByteOffset, a) Source #
Tagged version of decodeOrFail
IO functions for serialisation
taggedEncodeFile :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> a -> IO () Source #
Tagged version of encodeFile
taggedDecodeFile :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> IO a Source #
Tagged version of decodeFile
taggedDecodeFileOrFail :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> IO (Either (ByteOffset, String) a) Source #
Tagged version of decodeFileOrFail
Class
class HasStructuralInfo a where Source #
Type class providing StructuralInfo
for each data type.
For regular non-recursive ADTs HasStructuralInfo
can be derived generically.
data Record = Record { a :: Int, b :: Bool, c :: [Char] } deriving (Generic) instance hasStructuralInfo Record
For stable types, you can provide only type name
instance HasStructuralInfo Int where structuralInfo = ghcNominalType -- infer name from Generic information instance HasStructuralInfo Integer where structuralInfo _ = NominalType "Integer"
Recursive type story is a bit sad atm. If the type structure is stable, you can do:
instance HasStructuralInfo a => HasStructuralInfo [a] where structuralInfo = ghcStructuralInfo1
Nothing
structuralInfo :: Proxy a -> StructuralInfo Source #
structuralInfo :: (Generic a, All2 HasStructuralInfo (GCode a), GDatatypeInfo a, SListI2 (GCode a)) => Proxy a -> StructuralInfo Source #
Instances
class KnownNat (SemanticVersion a) => HasSemanticVersion (a :: *) Source #
A helper type family for encodeTaggedFile
and decodeTaggedFile
.
The default definition is SemanticVersion
a = 0
type SemanticVersion a :: Nat Source #
Instances
Type level calculations
type Interleave (n :: Nat) (m :: Nat) = SumUpTo (n + m) + m Source #
Interleaving
3 | 9 . . . . 2 | 5 8 . . . 1 | 2 4 7 11 . 0 | 0 1 3 6 10 ----------------- 0 1 2 3 4
This can be calculated by f x y = sum ([0..x+y]) + y
Generic derivation
GHC
ghcStructuralInfo :: (Generic a, All2 HasStructuralInfo (GCode a), GDatatypeInfo a, SListI2 (GCode a)) => Proxy a -> StructuralInfo Source #
ghcNominalType :: (Generic a, GDatatypeInfo a) => Proxy a -> StructuralInfo Source #
ghcStructuralInfo1 :: forall f a. (Generic1 f, GDatatypeInfo (f a), HasStructuralInfo a) => Proxy (f a) -> StructuralInfo Source #
SOP
sopStructuralInfo :: forall a. (Generic a, HasDatatypeInfo a, All2 HasStructuralInfo (Code a)) => Proxy a -> StructuralInfo Source #
sopNominalType :: forall a. (Generic a, HasDatatypeInfo a) => Proxy a -> StructuralInfo Source #
sopStructuralInfo1 :: forall f a. (Generic (f a), HasDatatypeInfo (f a), HasStructuralInfo a) => Proxy (f a) -> StructuralInfo Source #
SOP direct
sopStructuralInfoS :: forall xss. (All2 HasStructuralInfo xss, SListI2 xss) => DatatypeInfo xss -> StructuralInfo Source #
sopNominalTypeS :: DatatypeInfo xss -> StructuralInfo Source #
sopStructuralInfo1S :: StructuralInfo -> DatatypeInfo xss -> StructuralInfo Source #