Files
flatbuffers/tests/rust_usage_test/benches/flatbuffers_benchmarks.rs
Max Burke 6da1cf79d9 [rust] Add use declarations to Rust-generated bindings for imported FB definitions (#5645)
* Bugfix for Rust generation of union fields named with language keywords

Looking at ParseField, it appears that in the case of unions, an extra field with a `UnionTypeFieldSuffix` is added to the type definition, however, if the name of this field is a keyword in the target language, it isn't escaped.

For example, if generating code for rust for a union field named `type`, flatc will generate a (non-keyword escaped) field named `type_type` for this hidden union field, and one (keyword escaped) called `type_` for the actual union contents.

When the union accessors are generated, they refer to this `type_type` field, but they will escape it mistakenly, generating code like this:

```
  #[inline]
  #[allow(non_snake_case)]
  pub fn type__as_int(&self) -> Option<Int<'a>> {
    if self.type__type() == Type::Int {
      self.type_().map(|u| Int::init_from_table(u))
    } else {
      None
    }
  }
```

Which will fail to build because the field is called `self.type_type()`, not `self.type__type()`.

* [Rust] Add crate-relative use statements for FBS includes.

At present if a flatbuffer description includes a reference to a type in
another file, the generated Rust code needs to be hand-modified to add
the appropriate `use` statements.

This assumes that the dependencies are built into the same crate, which
I think is a reasonable assumption?

* Revert "[Rust] Add crate-relative use statements for FBS includes."

This reverts commit d554d79fec.

* Add updated generated test files.

* Fixing Rust test harness to handle new includes.

Test binaries need to add references to generated code that's
transitively included.

This also has the knock-on in that this code (which is referenced by
include directives directly in the flatbuffer schema files) also needs
to be generated, hence the changes to generate_code.sh.

* Test harnesses expect test data to be checked in.

Put include_test2 files into the same directory as the include_test2
schema definition.

Update all code generation scripts (forgot the batch file from last
time).

Path updates in Rust test.

* Include updated generated code

* Address comments raised in PR

* Fix failing Rust tests.

* Previous merge clobbered this branch change.

* Add updated imports to benchmarks.

* Clarifying comment per PR request

* Update documentation comments per feedback

* Remove non-Rust generated files for include tests, per feedback from @rw/@aardappel

* Broken code generation batch file

* Fix typo

* Add TODO for tidying up use declaration traversal sometime in the future

* Update test files.
2020-01-19 14:47:28 -08:00

228 lines
7.4 KiB
Rust

/*
* Copyright 2018 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#[macro_use]
extern crate bencher;
use bencher::Bencher;
extern crate flatbuffers;
#[allow(dead_code, unused_imports)]
#[path = "../../include_test/include_test1_generated.rs"]
pub mod include_test1_generated;
#[allow(dead_code, unused_imports)]
#[path = "../../include_test/sub/include_test2_generated.rs"]
pub mod include_test2_generated;
#[allow(dead_code, unused_imports)]
#[path = "../../monster_test_generated.rs"]
mod monster_test_generated;
pub use monster_test_generated::my_game;
fn traverse_canonical_buffer(bench: &mut Bencher) {
let owned_data = {
let mut builder = &mut flatbuffers::FlatBufferBuilder::new();
create_serialized_example_with_generated_code(&mut builder, true);
builder.finished_data().to_vec()
};
let data = &owned_data[..];
let n = data.len() as u64;
bench.iter(|| {
traverse_serialized_example_with_generated_code(data);
});
bench.bytes = n;
}
fn create_canonical_buffer_then_reset(bench: &mut Bencher) {
let mut builder = &mut flatbuffers::FlatBufferBuilder::new();
// warmup
create_serialized_example_with_generated_code(&mut builder, true);
let n = builder.finished_data().len() as u64;
builder.reset();
bench.iter(|| {
let _ = create_serialized_example_with_generated_code(&mut builder, true);
builder.reset();
});
bench.bytes = n;
}
#[inline(always)]
fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder, finish: bool) -> usize{
let s0 = builder.create_string("test1");
let s1 = builder.create_string("test2");
let t0_name = builder.create_string("Barney");
let t1_name = builder.create_string("Fred");
let t2_name = builder.create_string("Wilma");
let t0 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
hp: 1000,
name: Some(t0_name),
..Default::default()
});
let t1 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
name: Some(t1_name),
..Default::default()
});
let t2 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
name: Some(t2_name),
..Default::default()
});
let mon = {
let name = builder.create_string("MyMonster");
let fred_name = builder.create_string("Fred");
let inventory = builder.create_vector_direct(&[0u8, 1, 2, 3, 4]);
let test4 = builder.create_vector_direct(&[my_game::example::Test::new(10, 20),
my_game::example::Test::new(30, 40)]);
let pos = my_game::example::Vec3::new(1.0, 2.0, 3.0, 3.0, my_game::example::Color::Green, &my_game::example::Test::new(5i16, 6i8));
let args = my_game::example::MonsterArgs{
hp: 80,
mana: 150,
name: Some(name),
pos: Some(&pos),
test_type: my_game::example::Any::Monster,
test: Some(my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
name: Some(fred_name),
..Default::default()
}).as_union_value()),
inventory: Some(inventory),
test4: Some(test4),
testarrayofstring: Some(builder.create_vector(&[s0, s1])),
testarrayoftables: Some(builder.create_vector(&[t0, t1, t2])),
..Default::default()
};
my_game::example::Monster::create(builder, &args)
};
if finish {
my_game::example::finish_monster_buffer(builder, mon);
}
builder.finished_data().len()
// make it do some work
// if builder.finished_data().len() == 0 { panic!("bad benchmark"); }
}
#[inline(always)]
fn blackbox<T>(t: T) -> T {
// encapsulate this in case we need to turn it into a noop
bencher::black_box(t)
}
#[inline(always)]
fn traverse_serialized_example_with_generated_code(bytes: &[u8]) {
let m = my_game::example::get_root_as_monster(bytes);
blackbox(m.hp());
blackbox(m.mana());
blackbox(m.name());
let pos = m.pos().unwrap();
blackbox(pos.x());
blackbox(pos.y());
blackbox(pos.z());
blackbox(pos.test1());
blackbox(pos.test2());
let pos_test3 = pos.test3();
blackbox(pos_test3.a());
blackbox(pos_test3.b());
blackbox(m.test_type());
let table2 = m.test().unwrap();
let monster2 = my_game::example::Monster::init_from_table(table2);
blackbox(monster2.name());
blackbox(m.inventory());
blackbox(m.test4());
let testarrayoftables = m.testarrayoftables().unwrap();
blackbox(testarrayoftables.get(0).hp());
blackbox(testarrayoftables.get(0).name());
blackbox(testarrayoftables.get(1).name());
blackbox(testarrayoftables.get(2).name());
let testarrayofstring = m.testarrayofstring().unwrap();
blackbox(testarrayofstring.get(0));
blackbox(testarrayofstring.get(1));
}
fn create_string_10(bench: &mut Bencher) {
let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
let mut i = 0;
bench.iter(|| {
builder.create_string("foobarbaz"); // zero-terminated -> 10 bytes
i += 1;
if i == 10000 {
builder.reset();
i = 0;
}
});
bench.bytes = 10;
}
fn create_string_100(bench: &mut Bencher) {
let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
let s_owned = (0..99).map(|_| "x").collect::<String>();
let s: &str = &s_owned;
let mut i = 0;
bench.iter(|| {
builder.create_string(s); // zero-terminated -> 100 bytes
i += 1;
if i == 1000 {
builder.reset();
i = 0;
}
});
bench.bytes = s.len() as u64;
}
fn create_byte_vector_100_naive(bench: &mut Bencher) {
let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>();
let v: &[u8] = &v_owned;
let mut i = 0;
bench.iter(|| {
builder.create_vector(v); // zero-terminated -> 100 bytes
i += 1;
if i == 10000 {
builder.reset();
i = 0;
}
});
bench.bytes = v.len() as u64;
}
fn create_byte_vector_100_optimal(bench: &mut Bencher) {
let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>();
let v: &[u8] = &v_owned;
let mut i = 0;
bench.iter(|| {
builder.create_vector_direct(v);
i += 1;
if i == 10000 {
builder.reset();
i = 0;
}
});
bench.bytes = v.len() as u64;
}
benchmark_group!(benches, create_byte_vector_100_naive, create_byte_vector_100_optimal, traverse_canonical_buffer, create_canonical_buffer_then_reset, create_string_10, create_string_100);
benchmark_main!(benches);