From 1adf25910060c509a32b60947e73f1ef177931d6 Mon Sep 17 00:00:00 2001 From: yanshay Date: Tue, 5 Nov 2024 01:00:19 +0200 Subject: [PATCH 1/3] Added support for ::{Vec, String} for map::{Key and Value} --- Cargo.toml | 5 +- src/alloc_impl.rs | 183 ++++++++++++++++++++++++++++++++++++++++ src/heapless_impl.rs | 193 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 + 4 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 src/alloc_impl.rs create mode 100644 src/heapless_impl.rs diff --git a/Cargo.toml b/Cargo.toml index cfb8dcf..7c704e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ defmt = { version = "0.3", optional = true } futures = { version = "0.3.30", features = ["executor"], optional = true } approx = { version = "0.5.1", optional = true } arrayvec = { version = "0.7.4", default-features = false, optional = true } +heapless = { version = "0.8.0", optional = true } [dev-dependencies] approx = "0.5.1" @@ -28,7 +29,9 @@ defmt-03 = ["dep:defmt"] std = [] # Enable the implementation of the map Key trait for ArrayVec and ArrayString arrayvec = ["dep:arrayvec"] -_test = ["dep:futures", "dep:approx", "std", "arrayvec"] +alloc = [] +heapless = ["dep:heapless"] +_test = ["dep:futures", "dep:approx", "std", "arrayvec", "alloc", "heapless"] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing_repro)'] } diff --git a/src/alloc_impl.rs b/src/alloc_impl.rs new file mode 100644 index 0000000..2cd5895 --- /dev/null +++ b/src/alloc_impl.rs @@ -0,0 +1,183 @@ +extern crate alloc; +use crate::map::{Key, SerializationError, Value}; +use alloc::{string::String, vec::Vec}; + +// alloc::Vec + +impl Key for Vec { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() + 2 { + return Err(SerializationError::BufferTooSmall); + } + + if self.len() > u16::MAX as usize { + return Err(SerializationError::InvalidData); + } + + buffer[..2].copy_from_slice(&(self.len() as u16).to_le_bytes()); + buffer[2..][..self.len()].copy_from_slice(self); + + Ok(self.len() + 2) + } + + fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> { + let total_len = Self::get_len(buffer)?; + + if buffer.len() < total_len { + return Err(SerializationError::BufferTooSmall); + } + + let data_len = total_len - 2; + + let output = Vec::from(&buffer[2..][..data_len]); + + Ok((output, total_len)) + } + + fn get_len(buffer: &[u8]) -> Result { + if buffer.len() < 2 { + return Err(SerializationError::BufferTooSmall); + } + + let len = u16::from_le_bytes(buffer[..2].try_into().unwrap()); + + Ok(len as usize + 2) + } +} + +impl<'a> Value<'a> for Vec { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() { + return Err(SerializationError::BufferTooSmall); + } + + buffer[..self.len()].copy_from_slice(self.as_slice()); + Ok(self.len()) + } + + fn deserialize_from(buffer: &'a [u8]) -> Result + where + Self: Sized, + { + Ok(Vec::from(buffer)) + } +} + +// alloc::String + +impl Key for String { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() + 2 { + return Err(SerializationError::BufferTooSmall); + } + + if self.len() > u16::MAX as usize { + return Err(SerializationError::InvalidData); + } + + buffer[..2].copy_from_slice(&(self.len() as u16).to_le_bytes()); + buffer[2..][..self.len()].copy_from_slice(self.as_bytes()); + + Ok(self.len() + 2) + } + + fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> { + let total_len = Self::get_len(buffer)?; + + if buffer.len() < total_len { + return Err(SerializationError::BufferTooSmall); + } + + let data_len = total_len - 2; + + let output = String::from( + core::str::from_utf8(&buffer[2..][..data_len]) + .map_err(|_| SerializationError::InvalidFormat)?, + ); + + Ok((output, total_len)) + } + + fn get_len(buffer: &[u8]) -> Result { + if buffer.len() < 2 { + return Err(SerializationError::BufferTooSmall); + } + + let len = u16::from_le_bytes(buffer[..2].try_into().unwrap()); + + Ok(len as usize + 2) + } +} + +impl<'a> Value<'a> for String { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() { + return Err(SerializationError::BufferTooSmall); + } + + buffer[..self.len()].copy_from_slice(self.as_bytes()); + Ok(self.len()) + } + + fn deserialize_from(buffer: &'a [u8]) -> Result + where + Self: Sized, + { + let output = String::from( + core::str::from_utf8(buffer).map_err(|_| SerializationError::InvalidFormat)?, + ); + + Ok(output) + } +} + +#[cfg(test)] +mod tests { + use core::str::FromStr; + + use super::*; + + #[test] + fn key_serde_alloc_vec() { + let mut buffer = [0; 128]; + + let val = Vec::from_iter([0xAAu8; 12]); + Key::serialize_into(&val, &mut buffer).unwrap(); + let new_val = as Key>::deserialize_from(&buffer).unwrap(); + + assert_eq!((val, 14), new_val); + } + + #[test] + fn key_serde_alloc_string() { + let mut buffer = [0; 128]; + + let val = String::from("Hello world!"); + Key::serialize_into(&val, &mut buffer).unwrap(); + let new_val = ::deserialize_from(&buffer).unwrap(); + + assert_eq!((val, 14), new_val); + } + + #[test] + fn value_serde_alloc_vec() { + let mut buffer = [0; 12]; + + let val = Vec::from_iter([0xAAu8; 12]); + Value::serialize_into(&val, &mut buffer).unwrap(); + let new_val = as Value>::deserialize_from(&buffer).unwrap(); + + assert_eq!(val, new_val); + } + + #[test] + fn value_serde_alloc_string() { + let mut buffer = [0; 12]; + + let val = String::from("Hello world!"); + Value::serialize_into(&val, &mut buffer).unwrap(); + let new_val = ::deserialize_from(&buffer).unwrap(); + + assert_eq!(val, new_val); + } +} diff --git a/src/heapless_impl.rs b/src/heapless_impl.rs new file mode 100644 index 0000000..eb0262b --- /dev/null +++ b/src/heapless_impl.rs @@ -0,0 +1,193 @@ +use core::str::FromStr; + +use heapless::{String, Vec}; + +use crate::map::{Key, SerializationError, Value}; + +// heapless:: Vec + +impl Key for Vec { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() + 2 { + return Err(SerializationError::BufferTooSmall); + } + + if self.len() > u16::MAX as usize { + return Err(SerializationError::InvalidData); + } + + buffer[..2].copy_from_slice(&(self.len() as u16).to_le_bytes()); + buffer[2..][..self.len()].copy_from_slice(self); + + Ok(self.len() + 2) + } + + fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> { + let total_len = Self::get_len(buffer)?; + + if buffer.len() < total_len { + return Err(SerializationError::BufferTooSmall); + } + + let data_len = total_len - 2; + + let mut output = Vec::new(); + output + .extend_from_slice(&buffer[2..][..data_len]) + .map_err(|_| SerializationError::InvalidFormat)?; + + Ok((output, total_len)) + } + + fn get_len(buffer: &[u8]) -> Result { + if buffer.len() < 2 { + return Err(SerializationError::BufferTooSmall); + } + + let len = u16::from_le_bytes(buffer[..2].try_into().unwrap()); + + Ok(len as usize + 2) + } +} + +impl<'a, const CAP: usize> Value<'a> for Vec { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() { + return Err(SerializationError::BufferTooSmall); + } + + buffer[..self.len()].copy_from_slice(self.as_slice()); + Ok(self.len()) + } + + fn deserialize_from(buffer: &'a [u8]) -> Result + where + Self: Sized, + { + Vec::try_from(buffer).map_err(|_| SerializationError::InvalidFormat) + } +} + +// heapless::String + +impl Key for String { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() + 2 { + return Err(SerializationError::InvalidFormat); + } + + if self.len() > u16::MAX as usize { + return Err(SerializationError::InvalidData); + } + + buffer[..2].copy_from_slice(&(self.len() as u16).to_le_bytes()); + buffer[2..][..self.len()].copy_from_slice(self.as_bytes()); + + Ok(self.len() + 2) + } + + fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> { + let total_len = Self::get_len(buffer)?; + + if buffer.len() < total_len { + return Err(SerializationError::BufferTooSmall); + } + + let data_len = total_len - 2; + + let mut output = String::new(); + output + .push_str( + core::str::from_utf8(&buffer[2..][..data_len]) + .map_err(|_| SerializationError::InvalidFormat)?, + ) + .map_err(|_| SerializationError::InvalidFormat)?; + + Ok((output, total_len)) + } + + fn get_len(buffer: &[u8]) -> Result { + if buffer.len() < 2 { + return Err(SerializationError::BufferTooSmall); + } + + let len = u16::from_le_bytes(buffer[..2].try_into().unwrap()); + + Ok(len as usize + 2) + } +} + +impl<'a, const CAP: usize> Value<'a> for String { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < self.len() { + return Err(SerializationError::BufferTooSmall); + } + + buffer[..self.len()].copy_from_slice(self.as_bytes()); + Ok(self.len()) + } + + fn deserialize_from(buffer: &'a [u8]) -> Result + where + Self: Sized, + { + let output = String::from_str( + core::str::from_utf8(buffer).map_err(|_| SerializationError::InvalidFormat)?, + ) + .map_err(|_| SerializationError::BufferTooSmall)?; + + Ok(output) + } +} + + +#[cfg(test)] +mod tests { + use core::str::FromStr; + + use super::*; + + #[test] + fn key_serde_heapless_vec() { + let mut buffer = [0; 128]; + + let val = Vec::::from_iter([0xAA; 12]); + Key::serialize_into(&val, &mut buffer).unwrap(); + let new_val = as Key>::deserialize_from(&buffer).unwrap(); + + assert_eq!((val, 14), new_val); + } + + #[test] + fn key_serde_heapless_string() { + let mut buffer = [0; 128]; + + let val = String::<45>::from_str("Hello world!").unwrap(); + Key::serialize_into(&val, &mut buffer).unwrap(); + let new_val = as Key>::deserialize_from(&buffer).unwrap(); + + assert_eq!((val, 14), new_val); + } + + #[test] + fn value_serde_heapless_vec() { + let mut buffer = [0; 12]; + + let val = Vec::::from_iter([0xAA; 12]); + Value::serialize_into(&val, &mut buffer).unwrap(); + let new_val = as Value>::deserialize_from(&buffer).unwrap(); + + assert_eq!(val, new_val); + } + + #[test] + fn value_serde_heapless_string() { + let mut buffer = [0; 12]; + + let val = String::<45>::from_str("Hello world!").unwrap(); + Value::serialize_into(&val, &mut buffer).unwrap(); + let new_val = as Value>::deserialize_from(&buffer).unwrap(); + + assert_eq!(val, new_val); + } +} diff --git a/src/lib.rs b/src/lib.rs index 567c4ab..1ecdc2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,10 @@ use map::SerializationError; #[cfg(feature = "arrayvec")] mod arrayvec_impl; +#[cfg(feature = "alloc")] +mod alloc_impl; +#[cfg(feature = "heapless")] +mod heapless_impl; pub mod cache; mod item; pub mod map; From 93d187b9f2b30506292e822ef5f4c6a465f68f00 Mon Sep 17 00:00:00 2001 From: yanshay Date: Tue, 5 Nov 2024 11:21:04 +0200 Subject: [PATCH 2/3] fix formatting --- src/heapless_impl.rs | 1 - src/lib.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/heapless_impl.rs b/src/heapless_impl.rs index eb0262b..b943d12 100644 --- a/src/heapless_impl.rs +++ b/src/heapless_impl.rs @@ -140,7 +140,6 @@ impl<'a, const CAP: usize> Value<'a> for String { } } - #[cfg(test)] mod tests { use core::str::FromStr; diff --git a/src/lib.rs b/src/lib.rs index 1ecdc2a..cd5f36e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,13 +15,13 @@ use core::{ use embedded_storage_async::nor_flash::NorFlash; use map::SerializationError; -#[cfg(feature = "arrayvec")] -mod arrayvec_impl; #[cfg(feature = "alloc")] mod alloc_impl; +#[cfg(feature = "arrayvec")] +mod arrayvec_impl; +pub mod cache; #[cfg(feature = "heapless")] mod heapless_impl; -pub mod cache; mod item; pub mod map; pub mod queue; From 9b39c9c69c76faa23ed56590297111fc9720f25e Mon Sep 17 00:00:00 2001 From: yanshay Date: Tue, 5 Nov 2024 11:22:33 +0200 Subject: [PATCH 3/3] Fixed a warning --- src/alloc_impl.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/alloc_impl.rs b/src/alloc_impl.rs index 2cd5895..85c56e6 100644 --- a/src/alloc_impl.rs +++ b/src/alloc_impl.rs @@ -133,8 +133,6 @@ impl<'a> Value<'a> for String { #[cfg(test)] mod tests { - use core::str::FromStr; - use super::*; #[test]