...

Text file src/github.com/google/flatbuffers/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs

Documentation: github.com/google/flatbuffers/tests/rust_usage_test/bin

     1// define a passthrough allocator that tracks alloc calls.
     2// (note that we can't drop this in to the usual test suite, because it's a big
     3// global variable).
     4use std::alloc::{GlobalAlloc, Layout, System};
     5
     6
     7static mut N_ALLOCS: usize = 0;
     8
     9struct TrackingAllocator;
    10
    11impl TrackingAllocator {
    12    fn n_allocs(&self) -> usize {
    13        unsafe { N_ALLOCS }
    14    }
    15}
    16
    17unsafe impl GlobalAlloc for TrackingAllocator {
    18    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
    19        N_ALLOCS += 1;
    20        System.alloc(layout)
    21    }
    22    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
    23        System.dealloc(ptr, layout)
    24    }
    25}
    26
    27// use the tracking allocator:
    28#[global_allocator]
    29static A: TrackingAllocator = TrackingAllocator;
    30
    31// import the flatbuffers generated code:
    32extern crate flatbuffers;
    33
    34#[allow(dead_code, unused_imports, clippy::all)]
    35#[path = "../../include_test1/mod.rs"]
    36pub mod include_test1_generated;
    37
    38#[allow(dead_code, unused_imports, clippy::all)]
    39#[path = "../../include_test2/mod.rs"]
    40pub mod include_test2_generated;
    41
    42#[allow(dead_code, unused_imports, clippy::all)]
    43#[path = "../../monster_test/mod.rs"]
    44mod monster_test_generated;
    45
    46pub use monster_test_generated::my_game;
    47
    48// verbatim from the test suite:
    49fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder) {
    50    let mon = {
    51        let strings = [
    52            builder.create_string("these"),
    53            builder.create_string("unused"),
    54            builder.create_string("strings"),
    55            builder.create_string("check"),
    56            builder.create_string("the"),
    57            builder.create_string("create_vector_of_strings"),
    58            builder.create_string("function")
    59        ];
    60        let _ = builder.create_vector(&strings);
    61
    62        let s0 = builder.create_string("test1");
    63        let s1 = builder.create_string("test2");
    64        let fred_name = builder.create_string("Fred");
    65
    66        // can't inline creation of this Vec3 because we refer to it by reference, so it must live
    67        // long enough to be used by MonsterArgs.
    68        let pos = my_game::example::Vec3::new(
    69            1.0,
    70            2.0,
    71            3.0,
    72            3.0,
    73            my_game::example::Color::Green,
    74            &my_game::example::Test::new(5i16, 6i8),
    75        );
    76
    77        let args = my_game::example::MonsterArgs {
    78            hp: 80,
    79            mana: 150,
    80            name: Some(builder.create_string("MyMonster")),
    81            pos: Some(&pos),
    82            test_type: my_game::example::Any::Monster,
    83            test: Some(
    84                my_game::example::Monster::create(
    85                    builder,
    86                    &my_game::example::MonsterArgs {
    87                        name: Some(fred_name),
    88                        ..Default::default()
    89                    },
    90                )
    91                    .as_union_value(),
    92            ),
    93            inventory: Some(builder.create_vector(&[0u8, 1, 2, 3, 4])),
    94            test4: Some(builder.create_vector(&[
    95                my_game::example::Test::new(10, 20),
    96                my_game::example::Test::new(30, 40),
    97            ])),
    98            testarrayofstring: Some(builder.create_vector(&[s0, s1])),
    99            ..Default::default()
   100        };
   101        my_game::example::Monster::create(builder, &args)
   102    };
   103    my_game::example::finish_monster_buffer(builder, mon);
   104}
   105
   106#[cfg(not(miri))]  // slow.
   107fn main() {
   108    // test the allocation tracking:
   109    {
   110        let before = A.n_allocs();
   111        let _x: Vec<u8> = vec![0u8; 1];
   112        let after = A.n_allocs();
   113        assert_eq!(before + 1, after);
   114    }
   115
   116    let builder = &mut flatbuffers::FlatBufferBuilder::new();
   117    {
   118        // warm up the builder (it can make small allocs internally, such as for storing vtables):
   119        create_serialized_example_with_generated_code(builder);
   120    }
   121
   122    // reset the builder, clearing its heap-allocated memory:
   123    builder.reset();
   124
   125    {
   126        let before = A.n_allocs();
   127        create_serialized_example_with_generated_code(builder);
   128        let after = A.n_allocs();
   129        assert_eq!(before, after, "KO: Heap allocs occurred in Rust write path");
   130    }
   131
   132    let buf = builder.finished_data();
   133
   134    // use the allocation tracking on the read path:
   135    {
   136        let before = A.n_allocs();
   137
   138        // do many reads, forcing them to execute by using assert_eq:
   139        {
   140            let m = unsafe { my_game::example::root_as_monster_unchecked(buf) };
   141            assert_eq!(80, m.hp());
   142            assert_eq!(150, m.mana());
   143            assert_eq!("MyMonster", m.name());
   144
   145            let pos = m.pos().unwrap();
   146            // We know the bits should be exactly equal here but compilers may
   147            // optimize floats in subtle ways so we're playing it safe and using
   148            // epsilon comparison
   149            assert!((pos.x() - 1.0f32).abs() < std::f32::EPSILON);
   150            assert!((pos.y() - 2.0f32).abs() < std::f32::EPSILON);
   151            assert!((pos.z() - 3.0f32).abs() < std::f32::EPSILON);
   152            assert!((pos.test1() - 3.0f64).abs() < std::f64::EPSILON);
   153            assert_eq!(pos.test2(), my_game::example::Color::Green);
   154            let pos_test3 = pos.test3();
   155            assert_eq!(pos_test3.a(), 5i16);
   156            assert_eq!(pos_test3.b(), 6i8);
   157            assert_eq!(m.test_type(), my_game::example::Any::Monster);
   158            let table2 = m.test().unwrap();
   159            let m2 = unsafe { my_game::example::Monster::init_from_table(table2) };
   160
   161            assert_eq!(m2.name(), "Fred");
   162
   163            let inv = m.inventory().unwrap();
   164            assert_eq!(inv.len(), 5);
   165            assert_eq!(inv.iter().sum::<u8>(), 10u8);
   166
   167            let test4 = m.test4().unwrap();
   168            assert_eq!(test4.len(), 2);
   169            assert_eq!(
   170                i32::from(test4.get(0).a())
   171                    + i32::from(test4.get(1).a())
   172                    + i32::from(test4.get(0).b())
   173                    + i32::from(test4.get(1).b()),
   174                100
   175            );
   176
   177            let testarrayofstring = m.testarrayofstring().unwrap();
   178            assert_eq!(testarrayofstring.len(), 2);
   179            assert_eq!(testarrayofstring.get(0), "test1");
   180            assert_eq!(testarrayofstring.get(1), "test2");
   181        }
   182
   183        // assert that no allocs occurred:
   184        let after = A.n_allocs();
   185        assert_eq!(before, after, "KO: Heap allocs occurred in Rust read path");
   186    }
   187    println!("Rust: Heap alloc checks completed successfully");
   188}

View as plain text