--- /dev/null
+// define a passthrough allocator that tracks alloc calls.
+// (note that we can't drop this in to the usual test suite, because it's a big
+// global variable).
+use std::alloc::{GlobalAlloc, Layout, System};
+
+static mut N_ALLOCS: usize = 0;
+
+struct TrackingAllocator;
+
+impl TrackingAllocator {
+ fn n_allocs(&self) -> usize {
+ unsafe { N_ALLOCS }
+ }
+}
+unsafe impl GlobalAlloc for TrackingAllocator {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ N_ALLOCS += 1;
+ System.alloc(layout)
+ }
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ System.dealloc(ptr, layout)
+ }
+}
+
+// use the tracking allocator:
+#[global_allocator]
+static A: TrackingAllocator = TrackingAllocator;
+
+// import the flatbuffers generated code:
+extern crate flatbuffers;
+#[path = "../../monster_test_generated.rs"]
+mod monster_test_generated;
+pub use monster_test_generated::my_game;
+
+// verbatim from the test suite:
+fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder) {
+ let mon = {
+ let s0 = builder.create_string("test1");
+ let s1 = builder.create_string("test2");
+ let fred_name = builder.create_string("Fred");
+
+ // can't inline creation of this Vec3 because we refer to it by reference, so it must live
+ // long enough to be used by MonsterArgs.
+ 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(builder.create_string("MyMonster")),
+ 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(builder.create_vector_direct(&[0u8, 1, 2, 3, 4][..])),
+ test4: Some(builder.create_vector_direct(&[my_game::example::Test::new(10, 20),
+ my_game::example::Test::new(30, 40)])),
+ testarrayofstring: Some(builder.create_vector(&[s0, s1])),
+ ..Default::default()
+ };
+ my_game::example::Monster::create(builder, &args)
+ };
+ my_game::example::finish_monster_buffer(builder, mon);
+}
+
+fn main() {
+ // test the allocation tracking:
+ {
+ let before = A.n_allocs();
+ let _x: Vec<u8> = vec![0u8; 1];
+ let after = A.n_allocs();
+ assert_eq!(before + 1, after);
+ }
+
+ let builder = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ // warm up the builder (it can make small allocs internally, such as for storing vtables):
+ create_serialized_example_with_generated_code(builder);
+ }
+
+ // reset the builder, clearing its heap-allocted memory:
+ builder.reset();
+
+ {
+ let before = A.n_allocs();
+ create_serialized_example_with_generated_code(builder);
+ let after = A.n_allocs();
+ assert_eq!(before, after, "KO: Heap allocs occurred in Rust write path");
+ }
+
+ let buf = builder.finished_data();
+
+ // use the allocation tracking on the read path:
+ {
+ let before = A.n_allocs();
+
+ // do many reads, forcing them to execute by using assert_eq:
+ {
+ let m = my_game::example::get_root_as_monster(buf);
+ assert_eq!(80, m.hp());
+ assert_eq!(150, m.mana());
+ assert_eq!("MyMonster", m.name());
+
+ let pos = m.pos().unwrap();
+ assert_eq!(pos.x(), 1.0f32);
+ assert_eq!(pos.y(), 2.0f32);
+ assert_eq!(pos.z(), 3.0f32);
+ assert_eq!(pos.test1(), 3.0f64);
+ assert_eq!(pos.test2(), my_game::example::Color::Green);
+ let pos_test3 = pos.test3();
+ assert_eq!(pos_test3.a(), 5i16);
+ assert_eq!(pos_test3.b(), 6i8);
+ assert_eq!(m.test_type(), my_game::example::Any::Monster);
+ let table2 = m.test().unwrap();
+ let m2 = my_game::example::Monster::init_from_table(table2);
+
+ assert_eq!(m2.name(), "Fred");
+
+ let inv = m.inventory().unwrap();
+ assert_eq!(inv.len(), 5);
+ assert_eq!(inv.iter().sum::<u8>(), 10u8);
+
+ let test4 = m.test4().unwrap();
+ assert_eq!(test4.len(), 2);
+ assert_eq!(test4[0].a() as i32 + test4[0].b() as i32 +
+ test4[1].a() as i32 + test4[1].b() as i32, 100);
+
+ let testarrayofstring = m.testarrayofstring().unwrap();
+ assert_eq!(testarrayofstring.len(), 2);
+ assert_eq!(testarrayofstring.get(0), "test1");
+ assert_eq!(testarrayofstring.get(1), "test2");
+ }
+
+ // assert that no allocs occurred:
+ let after = A.n_allocs();
+ assert_eq!(before, after, "KO: Heap allocs occurred in Rust read path");
+ }
+ println!("Rust: Heap alloc checks completed successfully");
+}