Skip to content

Commit c5f151a

Browse files
authored
Add fallible try_* API for rust FlatBufferBuilder (#8918)
* Add fallible try_* API for FlatBufferBuilder This is to support error propagation from Allocator trait. The Allocator grow_downwards() method returns Result<(), Self::Error>, but FlatBufferBuilder panics via .expect() when allocation fails instead of propagating the error. * Add rust fallible API docs
1 parent 3860f1c commit c5f151a

3 files changed

Lines changed: 680 additions & 99 deletions

File tree

docs/source/languages/rust.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,61 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
9797

9898
*Note: That we never stored a `mana` value, so it will return the default.*
9999

100+
## Fallible API and Custom Allocators
101+
102+
Every `FlatBufferBuilder` method that may allocate has a `try_*` counterpart
103+
(e.g. `try_create_string`, `try_push`, `try_finish`) that returns
104+
`Result<T, A::Error>` instead of panicking. This is useful when allocation
105+
failures must be handled gracefully: for example in `no_std` environments or
106+
with fixed-capacity buffers.
107+
108+
The existing panicking methods are unchanged and remain the simplest option
109+
when using the default allocator.
110+
111+
#### Custom allocators
112+
113+
Implement the `Allocator` trait and pass it to `FlatBufferBuilder::new_in()`:
114+
115+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
116+
use flatbuffers::{Allocator, FlatBufferBuilder};
117+
118+
struct MyAllocator { /* ... */ }
119+
120+
unsafe impl Allocator for MyAllocator {
121+
type Error = MyError;
122+
fn grow_downwards(&mut self) -> Result<(), Self::Error> { /* ... */ }
123+
fn len(&self) -> usize { /* ... */ }
124+
}
125+
126+
let alloc = MyAllocator::new(/* ... */);
127+
let mut builder = FlatBufferBuilder::new_in(alloc);
128+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129+
130+
The built-in `DefaultAllocator` uses `Vec<u8>` and sets `Error = Infallible`,
131+
so the `try_*` methods on a default builder can never fail.
132+
133+
#### Example: building a buffer with error propagation
134+
135+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
136+
fn build<A: flatbuffers::Allocator>(
137+
builder: &mut FlatBufferBuilder<A>,
138+
) -> Result<(), A::Error> {
139+
let name = builder.try_create_string("Orc")?;
140+
let inventory = builder.try_create_vector(&[0u8, 1, 2, 3, 4])?;
141+
142+
let table_start = builder.start_table();
143+
builder.try_push_slot_always(Monster::VT_NAME, name)?;
144+
builder.try_push_slot_always(Monster::VT_INVENTORY, inventory)?;
145+
builder.try_push_slot(Monster::VT_HP, 80i16, 100)?;
146+
let root = builder.try_end_table(table_start)?;
147+
148+
builder.try_finish(root, None)?;
149+
Ok(())
150+
}
151+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
152+
153+
See the `FlatBufferBuilder` rustdoc for the full list of `try_*` methods.
154+
100155
## Direct memory access
101156

102157
As you can see from the above examples, all elements in a buffer are

0 commit comments

Comments
 (0)