From f0bd266ac1d57fd3ea1e044a6d93de81519cdd04 Mon Sep 17 00:00:00 2001 From: tedmund Date: Sat, 21 Oct 2023 08:50:40 +0800 Subject: [PATCH] quicklog(serialize): modify `Serialize` impl for DSTs --- quicklog/benches/logger_benchmark.rs | 28 +++++++++++------- quicklog/src/serialize/mod.rs | 44 ++++++++++++++++------------ quicklog/tests/common/mod.rs | 38 +++++++++++++----------- 3 files changed, 64 insertions(+), 46 deletions(-) diff --git a/quicklog/benches/logger_benchmark.rs b/quicklog/benches/logger_benchmark.rs index 42ff3ec..9537680 100644 --- a/quicklog/benches/logger_benchmark.rs +++ b/quicklog/benches/logger_benchmark.rs @@ -26,30 +26,36 @@ struct Nested { impl Serialize for BigStruct { fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> { - let (mut _head, mut tail) = write_buf.split_at_mut(0); - for i in 0..100 { - (_head, tail) = tail.split_at_mut(4); + let (chunk, _) = write_buf.split_at_mut(self.buffer_size_required()); + + let elm_size = std::mem::size_of::(); + let (vec_chunk, str_chunk) = chunk.split_at_mut(self.vec.len() * elm_size); + let (mut _head, mut _tail) = vec_chunk.split_at_mut(0); + for i in 0..self.vec.len() { + (_head, _tail) = _tail.split_at_mut(elm_size); _head.copy_from_slice(&self.vec[i].to_le_bytes()) } - tail.copy_from_slice(self.some.as_bytes()); + _ = self.some.encode(str_chunk); - Store::new(Self::decode, write_buf) + Store::new(Self::decode, chunk) } fn decode(buf: &[u8]) -> (String, &[u8]) { let (mut _head, mut tail) = buf.split_at(0); - let mut vec = vec![]; - for _ in 0..100 { - (_head, tail) = tail.split_at(4); - vec.push(i32::from_le_bytes(_head.try_into().unwrap())); + let mut arr = [0; 100]; + let elm_size = std::mem::size_of::(); + for i in &mut arr { + (_head, tail) = tail.split_at(elm_size); + *i = i32::from_le_bytes(_head.try_into().unwrap()); } let (s, rest) = <&str as Serialize>::decode(tail); - (format!("vec: {:?}, str: {}", vec, s), rest) + + (format!("vec: {:?}, str: {}", arr, s), rest) } fn buffer_size_required(&self) -> usize { - std::mem::size_of::() * 100 + self.some.len() + std::mem::size_of::() * 100 + self.some.buffer_size_required() } } diff --git a/quicklog/src/serialize/mod.rs b/quicklog/src/serialize/mod.rs index a2adfa2..9ecdd6b 100644 --- a/quicklog/src/serialize/mod.rs +++ b/quicklog/src/serialize/mod.rs @@ -14,6 +14,9 @@ pub trait Serialize { /// Function pointer which decodes a byte buffer back into `String` representation pub type DecodeFn = fn(&[u8]) -> (String, &[u8]); +/// Number of bytes it takes to store the size of a type. +pub const SIZE_LENGTH: usize = std::mem::size_of::(); + /// Contains the decode function required to decode `buffer` back into a `String` /// representation. #[derive(Clone)] @@ -76,36 +79,42 @@ gen_serialize!(usize); impl Serialize for &str { fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> { - assert!(self.len() == write_buf.len()); - write_buf.copy_from_slice(self.as_bytes()); - Store::new(Self::decode, write_buf) + let str_len = self.len(); + let (chunk, _) = write_buf.split_at_mut(str_len + SIZE_LENGTH); + let (len_chunk, str_chunk) = chunk.split_at_mut(SIZE_LENGTH); + + len_chunk.copy_from_slice(&str_len.to_le_bytes()); + str_chunk.copy_from_slice(self.as_bytes()); + + Store::new(Self::decode, chunk) } fn decode(read_buf: &[u8]) -> (String, &[u8]) { - let x = from_utf8(read_buf).unwrap(); - (x.to_string(), &[]) + let (len_chunk, chunk) = read_buf.split_at(SIZE_LENGTH); + let str_len = usize::from_le_bytes(len_chunk.try_into().unwrap()); + + let (str_chunk, rest) = chunk.split_at(str_len); + let s = from_utf8(str_chunk).unwrap(); + + (s.to_string(), rest) } fn buffer_size_required(&self) -> usize { - self.len() + SIZE_LENGTH + self.len() } } /// Eager evaluation into a String for debug structs pub fn encode_debug(val: T, write_buf: &mut [u8]) -> Store { let val_string = format!("{:?}", val); - // TODO: change back to strict equality when Serialize implemented, to use - // `buffer_size_required` - assert!(val_string.len() <= write_buf.len()); + let str_len = val_string.len(); - fn decode(read_buf: &[u8]) -> (String, &[u8]) { - let x = from_utf8(read_buf).unwrap(); - (x.to_string(), &[]) - } + let (chunk, _) = write_buf.split_at_mut(str_len + SIZE_LENGTH); + let (len_chunk, str_chunk) = chunk.split_at_mut(SIZE_LENGTH); + len_chunk.copy_from_slice(&str_len.to_le_bytes()); + str_chunk.copy_from_slice(val_string.as_bytes()); - let (chunk, _) = write_buf.split_at_mut(val_string.len()); - chunk.copy_from_slice(val_string.as_bytes()); - Store::new(decode, chunk) + Store::new(<&str as Serialize>::decode, chunk) } #[cfg(test)] @@ -162,8 +171,7 @@ mod tests { fn serialize_str() { let mut buf = [0; 128]; let s = "hello world"; - let (s_chunk, _) = buf.split_at_mut(s.buffer_size_required()); - let store = s.encode(s_chunk); + let store = s.encode(&mut buf); assert_eq!(s, format!("{}", store).as_str()) } diff --git a/quicklog/tests/common/mod.rs b/quicklog/tests/common/mod.rs index 1f7dcf4..3e710b3 100644 --- a/quicklog/tests/common/mod.rs +++ b/quicklog/tests/common/mod.rs @@ -106,17 +106,15 @@ pub(crate) struct SerializeStruct { impl Serialize for SerializeStruct { fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> { - write_buf.copy_from_slice(self.symbol.as_bytes()); - Store::new(Self::decode, write_buf) + self.symbol.as_str().encode(write_buf) } fn decode(read_buf: &[u8]) -> (String, &[u8]) { - let x = std::str::from_utf8(read_buf).unwrap(); - (x.to_string(), &[]) + <&str as Serialize>::decode(read_buf) } fn buffer_size_required(&self) -> usize { - self.symbol.len() + self.symbol.as_str().buffer_size_required() } } @@ -128,30 +126,36 @@ pub(crate) struct BigStruct { impl Serialize for BigStruct { fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> { - let (mut _head, mut tail) = write_buf.split_at_mut(0); - for i in 0..100 { - (_head, tail) = tail.split_at_mut(4); + let (chunk, _) = write_buf.split_at_mut(self.buffer_size_required()); + + let elm_size = std::mem::size_of::(); + let (vec_chunk, str_chunk) = chunk.split_at_mut(self.vec.len() * elm_size); + let (mut _head, mut _tail) = vec_chunk.split_at_mut(0); + for i in 0..self.vec.len() { + (_head, _tail) = _tail.split_at_mut(elm_size); _head.copy_from_slice(&self.vec[i].to_le_bytes()) } - tail.copy_from_slice(self.some.as_bytes()); + _ = self.some.encode(str_chunk); - Store::new(Self::decode, write_buf) + Store::new(Self::decode, chunk) } fn decode(buf: &[u8]) -> (String, &[u8]) { let (mut _head, mut tail) = buf.split_at(0); - let mut vec = vec![]; - for _ in 0..100 { - (_head, tail) = tail.split_at(4); - vec.push(i32::from_le_bytes(_head.try_into().unwrap())); + let mut arr = [0; 100]; + let elm_size = std::mem::size_of::(); + for i in 0..100 { + (_head, tail) = tail.split_at(elm_size); + arr[i] = i32::from_le_bytes(_head.try_into().unwrap()); } - let s = std::str::from_utf8(tail).unwrap(); - (format!("vec: {:?}, str: {}", vec, s), &[]) + let (s, rest) = <&str as Serialize>::decode(tail); + + (format!("vec: {:?}, str: {}", arr, s), rest) } fn buffer_size_required(&self) -> usize { - std::mem::size_of::() * 100 + self.some.len() + std::mem::size_of::() * 100 + self.some.buffer_size_required() } }