binary-typed- Type-safe binary serialization

Safe HaskellSafe-Inferred




This meta-module exists only for documentational purposes; the library functionality is found in Data.Binary.Typed.



Standard Binary serializes to ByteString, which is an untyped format; deserialization of unexpected input usually results in unusable data.

This module defines a Typed type, which allows serializing both a value and the type of that value; deserialization can then check whether the received data was sent assuming the right type, and error messages may provide insight into the type mismatch.

For example, this uses Binary directly:

test1 = let val = 10 :: Int
            enc = encode val
            dec = decode enc :: Bool
        in  print dec

This behaves unexpectedly: An Int value is converted to a Bool, which corresponds to a wacky type coercion. The receiving end has no way of knowing what the incoming data should have been interpreted as.

Using Typed, this can be avoided:

test2 = let val = 10 :: Int
            enc = encode (typed Full val)
            dec = decode enc :: Typed Bool
        in  print dec

This time decode raises an error: the incoming data is tagged as an Int, but is attempted to be decoded as Bool.

Basic usage

For convenience, this module exports a couple of convenience functions that have the type-mangling baked in already. The above example could have been written as

test3 = let val = 10 :: Int
            enc = encodeTyped val
            dec = decodeTyped enc :: Either String Bool
        in  print dec

However, using encodeTyped is computationally inefficient when many messages of the same type are serialized, since it recomputes a serialized version of that type for every single serialized value from scratch. encodeTypedLike exists to remedy that: it takes a separately constructed Typed dummy value, and computes a new serialization function for that type out of it. This serialization function then re-uses the type representation of the dummy value, and simply replaces the contained value on each serialization so that no unnecessary overhead is introduced.

-- Computes Ints type representation 100 times:
manyIntsNaive = map encodeTyped [1..100 :: Int]

-- Much more efficient: prepare dummy value to precache the
-- type representation, computing it only once:
encodeInt = encodeTypedLike (typed Full (0 :: Int))
manyIntsCached = map encodeInt [1..100]

API overview

The core definitions in Data.Binary.Typed are:

In addition to those, a couple of useful helper functions with more efficient implementation than what the core definitions could offer:

  • mapTyped (change values contained in Typeds)
  • reValue (change value, but don't recompute type representation)
  • reType (change type representation, but keep value)
  • precache (compute serialized type representation, useful as an optimization)

Lastly, there are a number of encoding/decoding functions, mostly for convenience: