Data.Binary.Tagged

binary-tagged-0.1.3.1: Tagged binary serialisation.

Copyright | (C) 2015 Oleg Grenrus
License | BSD3
Maintainer | Oleg Grenrus <oleg.grenrus@iki.fi>
Safe Haskell | None
Language | Haskell2010

Data.Binary.Tagged

Contents

- Data
- Serialisation
- IO functions for serialisation
- Class
  - Type level calculations
- Generic derivation
  - GHC
  - SOP
  - SOP direct
- Hash

Description

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 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
  - = NominalType String
  - | NominalNewtype String StructuralInfo
  - | StructuralInfo String [[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 m = SumUpTo (n + m) + m
- type SumUpTo n = Div2 (n * (n + 1))
- type family Div2 n :: Nat
- 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 a

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

Constructors

BinaryTagged |
Fields unBinaryTagged :: a

Instances

Monad (BinaryTagged k v) |
Functor (BinaryTagged k v) |
Applicative (BinaryTagged k v) |
Foldable (BinaryTagged k v) |
Traversable (BinaryTagged k v) |
Generic1 (BinaryTagged k v) |
Eq a => Eq (BinaryTagged k v a) |
Ord a => Ord (BinaryTagged k v a) |
Read a => Read (BinaryTagged k v a) |
Show a => Show (BinaryTagged k v a) |
Generic (BinaryTagged k v a) |
Monoid a => Monoid (BinaryTagged k v a) |
(Binary a, HasStructuralInfo a, KnownNat v) => Binary (BinaryTagged Nat v a) | Version and structure hash are prepended to serialised stream
type Rep1 (BinaryTagged k v) |
type Rep (BinaryTagged k v 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

Data type structure, with (some) nominal information.

Constructors

NominalType String |
NominalNewtype String StructuralInfo |
StructuralInfo String [[StructuralInfo]] |

Instances

Eq StructuralInfo |
Ord StructuralInfo |
Show StructuralInfo |
Generic StructuralInfo |
Binary StructuralInfo |
HasSemanticVersion StructuralInfo |
HasStructuralInfo StructuralInfo |
type Rep StructuralInfo |
type SemanticVersion StructuralInfo = 0 |

# Serialisation

taggedEncode :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => a -> ByteString

Tagged version of `encode`

taggedDecode :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => ByteString -> a

Tagged version of `decode`

taggedDecodeOrFail :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => ByteString -> Either (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)

Tagged version of `decodeOrFail`

# IO functions for serialisation

taggedEncodeFile :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> a -> IO ()

Tagged version of `encodeFile`

taggedDecodeFile :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> IO a

Tagged version of `decodeFile`

taggedDecodeFileOrFail :: forall a. (HasStructuralInfo a, HasSemanticVersion a, Binary a) => FilePath -> IO (Either (ByteOffset, String) a)

Tagged version of `decodeFileOrFail`

# Class

class HasStructuralInfo a where

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

Minimal complete definition

Nothing

Methods

structuralInfo :: Proxy a -> StructuralInfo

Instances

HasStructuralInfo Bool |
HasStructuralInfo Char |
HasStructuralInfo Double | Since binary-tagged-0.1.3.0
HasStructuralInfo Float | Since binary-tagged-0.1.3.0
HasStructuralInfo Int |
HasStructuralInfo Int8 |
HasStructuralInfo Int16 |
HasStructuralInfo Int32 |
HasStructuralInfo Int64 |
HasStructuralInfo Integer |
HasStructuralInfo Ordering | Since binary-tagged-0.1.3.0
HasStructuralInfo Word |
HasStructuralInfo Word8 |
HasStructuralInfo Word16 |
HasStructuralInfo Word32 |
HasStructuralInfo Word64 |
HasStructuralInfo () | Since binary-tagged-0.1.3.0
HasStructuralInfo ByteString |
HasStructuralInfo ByteString |
HasStructuralInfo Text |
HasStructuralInfo UTCTime |
HasStructuralInfo Value |
HasStructuralInfo Text |
HasStructuralInfo E0 |
HasStructuralInfo E1 |
HasStructuralInfo E2 |
HasStructuralInfo E3 |
HasStructuralInfo E6 |
HasStructuralInfo E9 |
HasStructuralInfo E12 |
HasStructuralInfo Version | Since binary-tagged-0.1.3.0
HasStructuralInfo IntSet |
HasStructuralInfo LocalTime |
HasStructuralInfo TimeOfDay |
HasStructuralInfo TimeZone |
HasStructuralInfo NominalDiffTime |
HasStructuralInfo Day |
HasStructuralInfo UniversalTime |
HasStructuralInfo DiffTime |
HasStructuralInfo StructuralInfo |
HasStructuralInfo a => HasStructuralInfo [a] |
HasStructuralInfo a => HasStructuralInfo (Ratio a) |
HasStructuralInfo a => HasStructuralInfo (Maybe a) |
HasStructuralInfo a => HasStructuralInfo (Fixed a) | Since binary-tagged-0.1.3.0
HasStructuralInfo a => HasStructuralInfo (Sum a) |
HasStructuralInfo a => HasStructuralInfo (Product a) |
HasStructuralInfo a => HasStructuralInfo (IntMap a) |
HasStructuralInfo a => HasStructuralInfo (Set a) |
HasStructuralInfo a => HasStructuralInfo (Seq a) |
HasStructuralInfo a => HasStructuralInfo (HashSet a) |
HasStructuralInfo a => HasStructuralInfo (Vector a) |
HasStructuralInfo a => HasStructuralInfo (Vector a) |
HasStructuralInfo a => HasStructuralInfo (Vector a) |
(HasStructuralInfo a, HasStructuralInfo b) => HasStructuralInfo (Either a b) |
(HasStructuralInfo a, HasStructuralInfo b) => HasStructuralInfo (a, b) |
(HasStructuralInfo k, HasStructuralInfo v) => HasStructuralInfo (HashMap k v) |
(HasStructuralInfo k, HasStructuralInfo v) => HasStructuralInfo (Map k v) |
(HasStructuralInfo i, HasStructuralInfo e) => HasStructuralInfo (UArray i e) |
(HasStructuralInfo i, HasStructuralInfo e) => HasStructuralInfo (Array i e) |
(HasStructuralInfo a, HasStructuralInfo b, HasStructuralInfo c) => HasStructuralInfo (a, b, c) |
(HasStructuralInfo a, HasStructuralInfo b, HasStructuralInfo c, HasStructuralInfo d) => HasStructuralInfo (a, b, c, d) |

class KnownNat (SemanticVersion a) => HasSemanticVersion a

A helper type family for `encodeTaggedFile` and `decodeTaggedFile`.

The default definition is ``SemanticVersion` a = 0`

Associated Types

type SemanticVersion a :: Nat

Instances

HasSemanticVersion Bool |
HasSemanticVersion Char |
HasSemanticVersion Double | Since binary-tagged-0.1.3.0
HasSemanticVersion Float | Since binary-tagged-0.1.3.0
HasSemanticVersion Int |
HasSemanticVersion Int8 |
HasSemanticVersion Int16 |
HasSemanticVersion Int32 |
HasSemanticVersion Int64 |
HasSemanticVersion Integer |
HasSemanticVersion Ordering | Since binary-tagged-0.1.3.0
HasSemanticVersion Word |
HasSemanticVersion Word8 |
HasSemanticVersion Word16 |
HasSemanticVersion Word32 |
HasSemanticVersion Word64 |
HasSemanticVersion () | Since binary-tagged-0.1.3.0
HasSemanticVersion ByteString |
HasSemanticVersion ByteString |
HasSemanticVersion Text |
HasSemanticVersion UTCTime |
HasSemanticVersion Value |
HasSemanticVersion Text |
HasSemanticVersion Version | Since binary-tagged-0.1.3.0
HasSemanticVersion IntSet |
HasSemanticVersion LocalTime |
HasSemanticVersion TimeOfDay |
HasSemanticVersion TimeZone |
HasSemanticVersion NominalDiffTime |
HasSemanticVersion Day |
HasSemanticVersion UniversalTime |
HasSemanticVersion DiffTime |
HasSemanticVersion StructuralInfo |
HasSemanticVersion a => HasSemanticVersion [a] |
HasSemanticVersion a => HasSemanticVersion (Ratio a) |
HasSemanticVersion a => HasSemanticVersion (Maybe a) |
HasSemanticVersion (Fixed a) | Since binary-tagged-0.1.3.0
HasSemanticVersion a => HasSemanticVersion (Sum a) |
HasSemanticVersion a => HasSemanticVersion (Product a) |
HasSemanticVersion a => HasSemanticVersion (IntMap a) |
HasSemanticVersion a => HasSemanticVersion (Set a) |
HasSemanticVersion a => HasSemanticVersion (Seq a) |
HasSemanticVersion a => HasSemanticVersion (HashSet a) |
HasSemanticVersion a => HasSemanticVersion (Vector a) |
HasSemanticVersion a => HasSemanticVersion (Vector a) |
HasSemanticVersion a => HasSemanticVersion (Vector a) |
(HasSemanticVersion a, HasSemanticVersion b, KnownNat (SemanticVersion (Either a b))) => HasSemanticVersion (Either a b) |
(HasSemanticVersion a, HasSemanticVersion b, KnownNat (SemanticVersion (a, b))) => HasSemanticVersion (a, b) |
(HasSemanticVersion k, HasSemanticVersion v, KnownNat (SemanticVersion (HashMap k v))) => HasSemanticVersion (HashMap k v) |
(HasSemanticVersion k, HasSemanticVersion v, KnownNat (SemanticVersion (Map k v))) => HasSemanticVersion (Map k v) |
(HasSemanticVersion i, HasSemanticVersion e, KnownNat (SemanticVersion (UArray i e))) => HasSemanticVersion (UArray i e) |
(HasSemanticVersion i, HasSemanticVersion e, KnownNat (SemanticVersion (Array i e))) => HasSemanticVersion (Array i e) |
(HasSemanticVersion a, HasSemanticVersion b, HasSemanticVersion c, KnownNat (SemanticVersion (a, b, c))) => HasSemanticVersion (a, b, c) | Since binary-tagged-0.1.3.0
(HasSemanticVersion a, HasSemanticVersion b, HasSemanticVersion c, HasSemanticVersion d, KnownNat (SemanticVersion (a, b, c, d))) => HasSemanticVersion (a, b, c, d) | Since binary-tagged-0.1.3.0

type Version = Word32

Type the semantic version is serialised with.

## Type level calculations

type Interleave n m = SumUpTo (n + m) + m

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`

type SumUpTo n = Div2 (n * (n + 1))

type family Div2 n :: Nat

Equations

Div2 0 = 0 |
Div2 1 = 0 |
Div2 n = 1 + Div2 (n - 2) |

# Generic derivation

## GHC

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

## SOP

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

## SOP direct

sopStructuralInfoS :: forall xss. (All2 HasStructuralInfo xss, SListI2 xss) => DatatypeInfo xss -> StructuralInfo

sopNominalTypeS :: DatatypeInfo xss -> StructuralInfo

sopStructuralInfo1S :: StructuralInfo -> DatatypeInfo xss -> StructuralInfo

# Hash

structuralInfoSha1Digest :: StructuralInfo -> Digest SHA1State

structuralInfoSha1ByteStringDigest :: StructuralInfo -> ByteString