Home | History | Annotate | Download | only in source
      1 Use in Rust    {#flatbuffers_guide_use_rust}
      2 ==========
      3 
      4 ## Before you get started
      5 
      6 Before diving into the FlatBuffers usage in Rust, it should be noted that
      7 the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
      8 to general FlatBuffers usage in all of the supported languages (including Rust).
      9 This page is designed to cover the nuances of FlatBuffers usage, specific to
     10 Rust.
     11 
     12 #### Prerequisites
     13 
     14 This page assumes you have written a FlatBuffers schema and compiled it
     15 with the Schema Compiler. If you have not, please see
     16 [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
     17 and [Writing a schema](@ref flatbuffers_guide_writing_schema).
     18 
     19 Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
     20 matter), you've generated a Rust file called `mygame_generated.rs` using the
     21 compiler (e.g. `flatc --rust mygame.fbs` or via helpers listed in "Useful
     22 tools created by others" section bellow), you can now start using this in
     23 your program by including the file. As noted, this header relies on the crate
     24 `flatbuffers`, which should be in your include `Cargo.toml`.
     25 
     26 ## FlatBuffers Rust library code location
     27 
     28 The code for the FlatBuffers Rust library can be found at
     29 `flatbuffers/rust`. You can browse the library code on the
     30 [FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/rust).
     31 
     32 ## Testing the FlatBuffers Rust library
     33 
     34 The code to test the Rust library can be found at `flatbuffers/tests/rust_usage_test`.
     35 The test code itself is located in
     36 [integration_test.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/tests/integration_test.rs)
     37 
     38 This test file requires `flatc` to be present. To review how to build the project,
     39 please read the [Building](@ref flatbuffers_guide_building) documenation.
     40 
     41 To run the tests, execute `RustTest.sh` from the `flatbuffers/tests` directory.
     42 For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
     43 run: `cd tests && ./RustTest.sh`.
     44 
     45 *Note: The shell script requires [Rust](https://www.rust-lang.org) to
     46 be installed.*
     47 
     48 ## Using the FlatBuffers Rust library
     49 
     50 *Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
     51 example of how to use FlatBuffers in Rust.*
     52 
     53 FlatBuffers supports both reading and writing FlatBuffers in Rust.
     54 
     55 To use FlatBuffers in your code, first generate the Rust modules from your
     56 schema with the `--rust` option to `flatc`. Then you can import both FlatBuffers
     57 and the generated code to read or write FlatBuffers.
     58 
     59 For example, here is how you would read a FlatBuffer binary file in Rust:
     60 First, include the library and generated code. Then read the file into
     61 a `u8` vector, which you pass, as a byte slice, to `get_root_as_monster()`.
     62 
     63 This full example program is available in the Rust test suite:
     64 [monster_example.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/bin/monster_example.rs)
     65 
     66 It can be run by `cd`ing to the `rust_usage_test` directory and executing: `cargo run monster_example`.
     67 
     68 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
     69     extern crate flatbuffers;
     70 
     71     #[path = "../../monster_test_generated.rs"]
     72     mod monster_test_generated;
     73     pub use monster_test_generated::my_game;
     74 
     75     use std::io::Read;
     76 
     77     fn main() {
     78         let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap();
     79         let mut buf = Vec::new();
     80         f.read_to_end(&mut buf).expect("file reading failed");
     81 
     82         let monster = my_game::example::get_root_as_monster(&buf[..]);
     83 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     84 
     85 `monster` is of type `Monster`, and points to somewhere *inside* your
     86 buffer (root object pointers are not the same as `buffer_pointer` !).
     87 If you look in your generated header, you'll see it has
     88 convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
     89 
     90 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
     91         println!("{}", monster.hp());     // `80`
     92         println!("{}", monster.mana());   // default value of `150`
     93         println!("{:?}", monster.name()); // Some("MyMonster")
     94     }
     95 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     96 
     97 *Note: That we never stored a `mana` value, so it will return the default.*
     98 
     99 ## Direct memory access
    100 
    101 As you can see from the above examples, all elements in a buffer are
    102 accessed through generated accessors. This is because everything is
    103 stored in little endian format on all platforms (the accessor
    104 performs a swap operation on big endian machines), and also because
    105 the layout of things is generally not known to the user.
    106 
    107 For structs, layout is deterministic and guaranteed to be the same
    108 across platforms (scalars are aligned to their
    109 own size, and structs themselves to their largest member), and you
    110 are allowed to access this memory directly by using `safe_slice` and
    111 on the reference to a struct, or even an array of structs.
    112 
    113 To compute offsets to sub-elements of a struct, make sure they
    114 are structs themselves, as then you can use the pointers to
    115 figure out the offset without having to hardcode it. This is
    116 handy for use of arrays of structs with calls like `glVertexAttribPointer`
    117 in OpenGL or similar APIs.
    118 
    119 It is important to note is that structs are still little endian on all
    120 machines, so only use tricks like this if you can guarantee you're not
    121 shipping on a big endian machine (using an `#[cfg(target_endian = "little")]`
    122 attribute would be wise).
    123 
    124 The special function `safe_slice` is implemented on Vector objects that are
    125 represented in memory the same way as they are represented on the wire. This
    126 function is always available on vectors of struct, bool, u8, and i8. It is
    127 conditionally-compiled on little-endian systems for all the remaining scalar
    128 types.
    129 
    130 The FlatBufferBuilder function `create_vector_direct` is implemented for all
    131 types that are endian-safe to write with a `memcpy`. It is the write-equivalent
    132 of `safe_slice`.
    133 
    134 ## Access of untrusted buffers
    135 
    136 The generated accessor functions access fields over offsets, which is
    137 very quick. These offsets are used to index into Rust slices, so they are
    138 bounds-checked by the Rust runtime. However, our Rust implementation may
    139 change: we may convert access functions to use direct pointer dereferencing, to
    140 improve lookup speed. As a result, users should not rely on the aforementioned
    141 bounds-checking behavior.
    142 
    143 When you're processing large amounts of data from a source you know (e.g.
    144 your own generated data on disk), this is acceptable, but when reading
    145 data from the network that can potentially have been modified by an
    146 attacker, this is undesirable.
    147 
    148 The C++ port provides a buffer verifier. At this time, Rust does not. Rust may
    149 provide a verifier in a future version. In the meantime, Rust users can access
    150 the buffer verifier generated by the C++ port through a foreign function
    151 interface (FFI).
    152 
    153 ## Threading
    154 
    155 Reading a FlatBuffer does not touch any memory outside the original buffer,
    156 and is entirely read-only (all immutable), so is safe to access from multiple
    157 threads even without synchronisation primitives.
    158 
    159 Creating a FlatBuffer is not thread safe. All state related to building
    160 a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
    161 outside of it is touched. To make this thread safe, either do not
    162 share instances of FlatBufferBuilder between threads (recommended), or
    163 manually wrap it in synchronisation primitives. There's no automatic way to
    164 accomplish this, by design, as we feel multithreaded construction
    165 of a single buffer will be rare, and synchronisation overhead would be costly.
    166 
    167 ## Useful tools created by others
    168 
    169 * [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler
    170 (flatc) as API for transparent `.fbs` to `.rs` code-generation via Cargo
    171 build scripts integration.
    172 
    173 <br>
    174