// 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 _ = builder.create_vector_of_strings(&["these", "unused", "strings", "check", "the", "create_vector_of_strings", "function"]); 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-allocated 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"); }