From: mustiikhalil Date: Mon, 4 Jan 2021 14:18:35 +0000 (+0300) Subject: [Rust] Shared String (#6367) X-Git-Tag: v2.0.0~128 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=57f68e28964c050190bc9d0242d76be56d898c78;p=platform%2Fupstream%2Fflatbuffers.git [Rust] Shared String (#6367) * Adds shared strings and tests for shared strings * Adds resets on string_map * Moved shared strings to use vector instead of hashmap * Addresses all the issues * Resolves some comments --- diff --git a/rust/flatbuffers/src/builder.rs b/rust/flatbuffers/src/builder.rs index f3bfcf2..2db363b 100644 --- a/rust/flatbuffers/src/builder.rs +++ b/rust/flatbuffers/src/builder.rs @@ -54,6 +54,7 @@ pub struct FlatBufferBuilder<'fbb> { min_align: usize, force_defaults: bool, + strings_pool: Vec>, _phantom: PhantomData<&'fbb ()>, } @@ -88,6 +89,7 @@ impl<'fbb> FlatBufferBuilder<'fbb> { min_align: 0, force_defaults: false, + strings_pool: Vec::new(), _phantom: PhantomData, } @@ -121,6 +123,7 @@ impl<'fbb> FlatBufferBuilder<'fbb> { self.finished = false; self.min_align = 0; + self.strings_pool.clear(); } /// Destroy the FlatBufferBuilder, returning its internal byte vector @@ -235,6 +238,46 @@ impl<'fbb> FlatBufferBuilder<'fbb> { 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. diff --git a/rust/flatbuffers/src/primitives.rs b/rust/flatbuffers/src/primitives.rs index 350e984..3d9d4c8 100644 --- a/rust/flatbuffers/src/primitives.rs +++ b/rust/flatbuffers/src/primitives.rs @@ -93,6 +93,8 @@ impl Clone for WIPOffset { } } +impl Eq for WIPOffset {} + impl PartialEq for WIPOffset { fn eq(&self, o: &WIPOffset) -> bool { self.value() == o.value() diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index 4f04760..e219624 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -3051,4 +3051,51 @@ fn load_file(filename: &str) -> Result, std::io::Error> { 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"); +} + }