Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
This meta-module exists only for documentational purposes; the library functionality is found in Data.Binary.Typed.
Motivation
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
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
This time decode
raises an error: the incoming data is tagged
as an Int
, but is attempted to be decoded as Bool
.
Basic usage
This package is typically used for debugging purposes. Hashed32
type
information keeps the size overhead relatively low, but requires a certain
amount of computational ressources. It is reliable at detecting errors, but
not very good at telling specifics about it. If a problem is identified, the
typing level can be increased to Shown
or Full
, providing information
about the involved types. If performance is critical, Untyped
"typed"
encoding can be used, with minimal overhead compared to using Binary
directly.
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
Hashed32
val dec =decodeTyped
enc ::Either
String
Bool
in
Using encodeTyped
in particular has a significant advantage: when used to
create new specialized encoding functions, the type information has to be
calculated only once, and can be shared among further invocations of the
function. In other words, using
encodeInt ::Int
->ByteString
encodeInt =encodeTyped
Hashed32
is much more efficient than
encodeInt ::Int
->ByteString
encodeInt =encode
.typed
Hashed32
since the latter recalculates the hash of "Int" on every invocation.
API overview
The core definitions in Data.Binary.Typed are:
Typed
(the main type)typed
(constructTyped
values)TypeFormat
(a helper type fortyped
)erase
(deconstructTyped
vales)
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 inTyped
s)reValue
(change value, but don't recompute type representation)reType
(change type representation, but keep value)preserialize
(compute serialized type representation and cache it, useful as an optimization)
Lastly, there are a number of encoding/decoding functions:
encodeTyped
(pack inTyped
and thenencode
, but more efficient)decodeTyped
(decodeTyped
ByteString
to
)Either
String
adecodeTypedOrFail
(likedecodeTyped
, but with more meta information)unsafeDecodeTyped
(which throws a runtime error on type mismatch)
(The Data.Binary.Typed.Debug module shares the same API.)