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;