min_align: usize,
force_defaults: bool,
+ strings_pool: Vec<WIPOffset<&'fbb str>>,
_phantom: PhantomData<&'fbb ()>,
}
min_align: 0,
force_defaults: false,
+ strings_pool: Vec::new(),
_phantom: PhantomData,
}
self.finished = false;
self.min_align = 0;
+ self.strings_pool.clear();
}
/// Destroy the FlatBufferBuilder, returning its internal byte vector
WIPOffset::new(o.value())
}
+ #[inline]
+ pub fn create_shared_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
+ self.assert_not_nested(
+ "create_shared_string can not be called when a table or vector is under construction",
+ );
+
+ // Saves a ref to owned_buf since rust doesnt like us refrencing it
+ // in the binary_search_by code.
+ let buf = &self.owned_buf;
+
+ let found = self.strings_pool.binary_search_by(|offset| {
+ let ptr = offset.value() as usize;
+ // Gets The pointer to the size of the string
+ let str_memory = &buf[buf.len() - ptr..];
+ // Gets the size of the written string from buffer
+ let size = u32::from_le_bytes([
+ str_memory[0],
+ str_memory[1],
+ str_memory[2],
+ str_memory[3],
+ ]) as usize;
+ // Size of the string size
+ let string_size: usize = 4;
+ // Fetches actual string bytes from index of string after string size
+ // to the size of string plus string size
+ let iter = str_memory[string_size..size + string_size].iter();
+ // Compares bytes of fetched string and current writable string
+ iter.cloned().cmp(s.bytes())
+ });
+
+ match found {
+ Ok(index) => self.strings_pool[index],
+ Err(index) => {
+ let address = WIPOffset::new(self.create_byte_string(s.as_bytes()).value());
+ self.strings_pool.insert(index, address);
+ address
+ }
+ }
+ }
+
/// Create a utf8 string.
///
/// The wire format represents this as a zero-terminated byte vector.
f.read_to_end(&mut buf)?;
Ok(buf)
}
+
+#[test]
+fn test_shared_strings() {
+ let mut builder = flatbuffers::FlatBufferBuilder::new();
+ let offset1 = builder.create_shared_string("welcome to flatbuffers!!");
+ let offset2 = builder.create_shared_string("welcome");
+ let offset3 = builder.create_shared_string("welcome to flatbuffers!!");
+ assert_ne!(offset2.value(), offset3.value());
+ assert_eq!(offset1.value(), offset3.value());
+ builder.reset();
+ let offset4 = builder.create_shared_string("welcome");
+ let offset5 = builder.create_shared_string("welcome to flatbuffers!!");
+ assert_ne!(offset2.value(), offset4.value());
+ assert_ne!(offset5.value(), offset1.value());
+ builder.reset();
+
+ // Checks if the shared string function would always work with
+ // an object in between the writes
+ let name = builder.create_shared_string("foo");
+ let enemy = my_game::example::Monster::create(&mut builder, &my_game::example::MonsterArgs {
+ name: Some(name),
+ ..Default::default()
+ });
+ let secondary_name = builder.create_shared_string("foo");
+ assert_eq!(name.value(), secondary_name.value());
+
+ // Builds a new monster object and embeds enemy into it so we can verify
+ // that shared strings are working.
+ let args = my_game::example::MonsterArgs {
+ name: Some(secondary_name),
+ enemy: Some(enemy),
+ testarrayofstring: Some(builder.create_vector(&[name, secondary_name])),
+ ..Default::default()
+ };
+ // Building secondary monster
+ let main_monster = my_game::example::Monster::create(&mut builder, &args);
+ builder.finish(main_monster, None);
+ let monster = my_game::example::root_as_monster(builder.finished_data()).unwrap();
+
+ // Checks if the embedded object (Enemy) name is foo
+ assert_eq!(monster.enemy().unwrap().name(), "foo");
+ let string_vector = monster.testarrayofstring().unwrap();
+ // Check if the vector will have the same string
+ assert_eq!(string_vector.get(0), "foo");
+ assert_eq!(string_vector.get(1), "foo");
+}
+
}