flatbuffers: Haskell implementation of the FlatBuffers protocol.
This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.
There are lots of examples in the test/Examples folder and the THSpec module.
In particular, test/Examples/schema.fbs and test/Examples/vector_of_unions.fbs contain a variety of data structures and Examples.HandWritten demonstrates what the code generated by mkFlatBuffers would look like.
Enums
enum Color: short {
Red, Green, Blue
}
Given the enum declarationa above, the following code will be generated:
data Color
= ColorRed
| ColorGreen
| ColorBlue
deriving (Eq, Show, Read, Ord, Bounded)
toColor :: Int16 -> Maybe Color
fromColor :: Color -> Int16
colorName :: Color -> Text
Usage:
table Monster {
color: Color;
}
data Monster
monster :: Maybe Int16 -> WriteTable Monster
monsterColor :: Table Monster -> Either ReadError Int16
-- Writing
byteString = encode $
monster (Just (fromColor ColorBlue))
-- Reading
readMonster :: ByteString -> Either ReadError Text
readMonster byteString = do
someMonster <- decode byteString
i <- monsterColor someMonster
case toColor i of
Just color -> Right ("This monster is " <> colorName color)
Nothing -> Left ("Unknown color: " <> show i) -- Forwards compatibility
Bit flags / Bitmasks
enum Colors: uint16 (bit_flags) {
Red, Green, Blue
}
Given the enum declarationa above, the following code will be generated:
data Monster
monster :: WriteStruct Coord -> WriteTable Monster
monsterPosition :: Table Monster -> Either ReadError (Struct Coord)
-- Writing
byteString = encode $
monster (coord 123 456)
-- Reading
readMonster :: ByteString -> Either ReadError String
readMonster byteString = do
someMonster <- decode byteString
pos <- monsterPosition someMonster
x <- coordX pos
y <- coordY pos
Right ("Monster is located at " <> show x <> ", " <> show y)
data Character
character :: WriteUnion Weapon -> WriteTable Character
characterWeapon :: Table Character -> Either ReadError (Union Weapon)
-- Writing
byteString = encode $
character
(weaponSword (sword (Just 1000)))
-- Reading
readCharacter :: ByteString -> Either ReadError String
readCharacter byteString = do
someCharacter <- decode byteString
weapon <- characterWeapon someCharacter
case weapon of
Union (WeaponSword sword) -> do
power <- swordPower sword
Right ("Weilding a sword with " <> show power <> " Power.")
Union (WeaponAxe axe) -> do
power <- axePower axe
Right ("Weilding an axe with " <> show power <> " Power.")
UnionNone -> Right "Character has no weapon"
UnionUnknown byte -> Left "Unknown weapon" -- Forwards compatibility
Note that, like in the official FlatBuffers implementation, unions are always optional.
Adding the required attribute to a union field has no effect.
To create a character with no weapon, use none :: WriteUnion a
Typically, a FlatBuffer binary buffer is not self-describing, i.e. it needs you to know its schema to parse it correctly. But if you want to use a FlatBuffer as a file format, it would be convenient to be able to have a "magic number" in there, like most file formats have, to be able to do a sanity check to see if you're reading the kind of file you're expecting.
Now, you can always prefix a FlatBuffer with your own file header, but FlatBuffers has a built-in way to add an identifier to a FlatBuffer that takes up minimal space, and keeps the buffer compatible with buffers that don't have such an identifier.