We can now construct a flatbuffer using encode and read it using decode:
{-# LANGUAGE OverloadedStrings #-}import Data.ByteString.Lazy(ByteString)import FlatBuffersimportqualified FlatBuffers.Vector as Vector-- WritingbyteString=encode$monster(Just"Poring")(Just50)(Vector.fromList2["Prontera Field","Payon Forest"])-- ReadingreadMonster::ByteString->EitherReadErrorStringreadMonsterbyteString=dosomeMonster<-decodebyteStringname<-monsterNamesomeMonsterhp<-monsterHpsomeMonsterlocations<-monsterLocationssomeMonster>>=Vector.toListRight("Monster: "<>showname<>" ("<>showhp<>" HP) can be found in "<>showlocations)
For the rest of this document, we'll assume these imports/extensions are enabled:
{-# LANGUAGE OverloadedStrings #-}import Data.ByteString.Lazy(ByteString)import Data.Text(Text)importqualified Data.Text as Textimport FlatBuffersimportqualified FlatBuffers.Vector as Vector
Codegen
You can check exactly which declarations were generated by browsing your module in ghci:
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:
-- WritingbyteString=encode$monster(coord123456)-- ReadingreadMonster::ByteString->EitherReadErrorStringreadMonsterbyteString=dosomeMonster<-decodebyteStringpos<-monsterPositionsomeMonsterx<-coordXposy<-coordYposRight("Monster is located at "<>showx<>", "<>showy)
-- WritingbyteString=encode$character(weaponSword(sword(Just1000)))-- ReadingreadCharacter::ByteString->EitherReadErrorStringreadCharacterbyteString=dosomeCharacter<-decodebyteStringweapon<-characterWeaponsomeCharactercaseweaponofUnion(WeaponSwordsword)->dopower<-swordPowerswordRight("Weilding a sword with "<>showpower<>" Power.")Union(WeaponAxeaxe)->dopower<-axePoweraxeRight("Weilding an axe with "<>showpower<>" Power.")UnionNone->Right"Character has no weapon"UnionUnknownbyte->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.