tagged-binary-0.2.0.1: Provides tools for serializing data tagged with type information.

Copyright(c) Justin Le 2015
LicenseMIT
Maintainerjustin@jle.im
Stabilityunstable
Portabilityportable
Safe HaskellNone
LanguageHaskell2010

Data.Binary.Tagged

Contents

Description

Provides tools for serializing and decoding data into ByteString tagged with information about its type. Really, most of this should be used by libraries and frameworks and abstracted over. Typical use cases are the polymorphic communication channels in distributed computing used by Cloud Haskell and distributed-process --- data of any type can come through the channel, and the framework can chose to ignore, queue, or accept data depending on the type the data is tagged with. Designed to work with cross-platform GHC backends like ghcjs.

When decoding data, the result is polymorphic, and you should either allow GHC to infer what you want somehow somewhere, or specify it explicitly.

Quick example:

> let x = encodeTagged (1 :: Int)
> decodeTagged x :: Maybe Bool
Nothing
> decodeTagged x :: Maybe Int
Just 1

The interface is very similar to that of Data.Dynamic.

Also provided here is the internal TagFingerprint data type, so that you can categorize, sort, and queue Tagged or ByteString based on the types they represent.

It might be significant to note that the current TagFingerprint implementation is a little shaky; it's a bit tricky getting all GHC platforms to agree on a meaningful TypeRep serialization, and we will have a better implementation eventually. For now, it just uses an MD5 hash of the string name of the type. So for now, don't encode/decode things with the same type name but exist in different modules (Data.Text.Text or Data.Text.Lazy.Text, for example) through the same polymorphic channel! This is a bit limiting, admittedly, but until I or the backend maintainers find out a way to ensure that type fingerprints match up per backend, be aware of this limitation.

Synopsis

Encoding and decoding tagged data

encodeTagged :: (Binary a, Typeable a) => a -> ByteString Source #

Encode data into a ByteString with its type data tagged.

Remember that for now, types are distinguished by their string names, so two types of the same name in different modules will not have unique tags.

decodeTagged :: (Binary a, Typeable a) => ByteString -> Maybe a Source #

Decode tagged data from a ByteString. The return type is polymorphic, so it'll attempt to decode it by inferred or specified type.

  • If the data is not decoded, Nothing is returned.
  • If successfully decoded data is tagged with a Fingerprint not matching the desired type, Nothing is also returned.
  • If the data is successfully decoded *and* the tagged Fingerprint matches the desired type, Just x is returned, where x is the originally encoded data (with its tag stripped).

bsFingerprint :: ByteString -> Maybe TagFingerprint Source #

With a ByteString, expecting tagged data, returns the Fingerprint that the data is tagged with. Returns Nothing if the data is not decodable as tagged data. Might accidentally decode untagged data though!

Manipulating

data Tagged a Source #

A data type tupling together data with a TagFingerprint, representing data tagged with its type.

It's best to interface directly with data using encodeTagged, decodeTagged, etc, using tag to tag data and extractTagged to extract data from valid tagged data. This type is exported mostly when you want to specifically decode a ByteString into tagged data, and manually extract it yourself. If you are writing a framework, it is preferred to handle this for the end user.

Instances

Eq a => Eq (Tagged a) Source # 

Methods

(==) :: Tagged a -> Tagged a -> Bool #

(/=) :: Tagged a -> Tagged a -> Bool #

Show a => Show (Tagged a) Source # 

Methods

showsPrec :: Int -> Tagged a -> ShowS #

show :: Tagged a -> String #

showList :: [Tagged a] -> ShowS #

Generic (Tagged a) Source # 

Associated Types

type Rep (Tagged a) :: * -> * #

Methods

from :: Tagged a -> Rep (Tagged a) x #

to :: Rep (Tagged a) x -> Tagged a #

Binary a => Binary (Tagged a) Source # 

Methods

put :: Tagged a -> Put #

get :: Get (Tagged a) #

putList :: [Tagged a] -> Put #

type Rep (Tagged a) Source # 
type Rep (Tagged a) = D1 (MetaData "Tagged" "Data.Binary.Tagged.Internal" "tagged-binary-0.2.0.1-Lc3n6I7VjZeMYbUEWKzSH" False) (C1 (MetaCons "Tagged" PrefixI False) ((:*:) (S1 (MetaSel (Nothing Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 TagFingerprint)) (S1 (MetaSel (Nothing Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 a))))

data TagFingerprint Source #

A data type representing a fingerprint for a Typeable type. Ideally, this would be Internal's own Fingerprint types; however, for some reason, the fingerprints for the same data type from the same modules differ between different GHC backends. So for now, it is just a ByteString representation of the name of the type. This is literally a bad idea, and so two types with the same name but from different modules will share a non-unique TagFingerprint. Hopefully in the future when I find out a way to fix this or the GHC backend maintainers find a way to provide consistent type fingerprints, this will be fixed.

This type is mostly used for the ability to categorized Tagged items by their type.

emptyTagFP gives a TagFingerprint that will most likely never be matched by any actual tag from a real type, so can be used as a test if needed. This replaces functionality that used to come from the Default instance.

typeFingerprint :: Typeable a => a -> TagFingerprint Source #

Compute the Fingerprint representing a type. It is non-strict on its parameter, so passing in undefined should work if you want to just get the Fingerprint of a specific type without having data of that type on hand:

typeFingerprint (undefined :: Int)