There are lots of examples in the test/Examples folder and the THSpec module.
In particular, test/Examples/schema.fbs contains 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 declaration 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 declaration 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.