Flatbuffer
This is a flatbuffers implementation in Elixir.
In contrast to existing implementations there is no need to compile code from a schema. Instead, data and schemas are processed dynamically at runtime, offering greater flexibility.
Using Flatbuffer
Schema file:
table Root {
foreground:Color;
background:Color;
}
table Color {
red: ubyte;
green: ubyte;
blue: ubyte;
}
root_type Root;Parsing the schema:
iex(1)> {:ok, schema} = Flatbuffer.Schema.from_file("Example.fbs")
{:ok,
%Flatbuffer.Schema{
entities: %{
"Color" => {:table,
%{
fields: [
red: {:ubyte, %{default: 0}},
green: {:ubyte, %{default: 0}},
blue: {:ubyte, %{default: 0}}
],
indices: %{
blue: {2, {:ubyte, %{default: 0}}},
green: {1, {:ubyte, %{default: 0}}},
red: {0, {:ubyte, %{default: 0}}}
}
}},
"Root" => {:table,
%{
fields: [
foreground: {:table, %{name: "Color"}},
background: {:table, %{name: "Color"}}
],
indices: %{
foreground: {0, {:table, %{name: "Color"}}},
background: {1, {:table, %{name: "Color"}}}
}
}}
},
root_type: {:table, %{name: "Root"}},
id: nil
}}Serializing data:
iex(2)> color_scheme = %{foreground: %{red: 128, green: 20, blue: 255}, background: %{red: 0, green: 100, blue: 128}}
iex(3)> color_scheme_fb = Flatbuffer.to_binary(color_scheme, schema)
<<16, 0, 0, 0, 0, 0, 0, 0, 8, 0, 12, 0, 4, 0, 8, 0, 8, 0, 0, 0, 18, 0, 0,
0, 31, 0, 0, 0, 10, 0, 7, 0, 4, 0, 5, 0, 6, 0, 10, 0, 0, 0, 128, 20,
255, 10, 0, 6, 0, 0, ...>>
So we can read the whole thing which converts it back into a map:
iex(4)> Flatbuffer.read!(color_scheme_fb, schema)
%{
foreground: %{blue: 255, green: 20, red: 128},
background: %{blue: 128, green: 100, red: 0}
}
Or we can get a value from the buffer without decoding the whole thing. This
can be done either with an atom key (for the root-table fields) or with a
key-path composed of a list of atoms and integers:
iex(5)> Flatbuffer.get(color_scheme_fb, [:background], schema)
%{blue: 128, green: 100, red: 0}
iex(6)> Flatbuffer.get(color_scheme_fb, [:background, :green], schema)
100Conveniences:
For schemas that will be often used or that need to be included with an
application, you can use Flatbuffer.use/1 to compile the schema into a
module:
defmodule ColorScheme do
use Flatbuffer,
path: "priv/fb",
schema: "color_scheme.fbs"
end
The schema (and any includes) will be read and parsed, and then compiled into
the module. The source files for the schema do not need to be read again or
included with the application. The functions of Flatbuffer are available in
the module, but with the schema predefined.
For example:
iex> color_scheme = %{foreground: %{red: 128, green: 20, blue: 255}, background: %{red: 0, green: 100, blue: 128}}
iex(2)> color_scheme_fb = ColorScheme.to_binary(color_scheme)
<<16, 0, 0, 0, 0, 0, 0, 0, 8, 0, 12, 0, 4, 0, 8, 0, 8, 0, 0, 0, 18, 0, 0,
0, 31, 0, 0, 0, 10, 0, 7, 0, 4, 0, 5, 0, 6, 0, 10, 0, 0, 0, 128, 20,
255, 10, 0, 6, 0, 0, ...>>
We can get a value from the buffer without decoding the whole thing. This
can be done either with an atom key (for the root-table fields) or with a
key-path composed of a list of atoms and integers:
iex(3)> ColorScheme.get(color_scheme_fb, :background)
%{blue: 128, green: 100, red: 0}
iex(4)> ColorScheme.get(color_scheme_fb, [:background, :green])
100Comparing Flatbuffer to flatc
features both in Flatbuffer and flatc
- tables
- scalars
- strings
- vflatbufferrs
- structs
- unions
- enums
- defaults
- file identifier + validation
- random access
- validate file identifiers
- includes
features only in flatcs
- shared strings
- shared vtables
- alignment
- additional attributes