diff --git a/CHANGELOG.md b/CHANGELOG.md index 1625e0e..5ec5082 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ## Unreleased +- Added `Value` impls for `bool`, `Option`, and `[T: Value; N]` + ## 3.0.1 25-07-24 - Add `defmt` attributes to cache types. diff --git a/src/map.rs b/src/map.rs index 4881db7..bf0c751 100644 --- a/src/map.rs +++ b/src/map.rs @@ -97,6 +97,8 @@ //! For your convenience there are premade implementations for the [Key] and [Value] traits. //! +use core::mem::{size_of, MaybeUninit}; + use embedded_storage_async::nor_flash::MultiwriteNorFlash; use crate::item::{find_next_free_item_spot, Item, ItemHeader, ItemIter}; @@ -693,7 +695,7 @@ macro_rules! impl_key_num { ($int:ty) => { impl Key for $int { fn serialize_into(&self, buffer: &mut [u8]) -> Result { - let len = core::mem::size_of::(); + let len = size_of::(); if buffer.len() < len { return Err(SerializationError::BufferTooSmall); } @@ -702,19 +704,19 @@ macro_rules! impl_key_num { } fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> { - let len = core::mem::size_of::(); + let len = size_of::(); if buffer.len() < len { return Err(SerializationError::BufferTooSmall); } Ok(( Self::from_le_bytes(buffer[..len].try_into().unwrap()), - core::mem::size_of::(), + size_of::(), )) } fn get_len(_buffer: &[u8]) -> Result { - Ok(core::mem::size_of::()) + Ok(size_of::()) } } }; @@ -772,25 +774,83 @@ pub trait Value<'a> { Self: Sized; } -impl<'a> Value<'a> for &'a [u8] { +impl<'a> Value<'a> for bool { fn serialize_into(&self, buffer: &mut [u8]) -> Result { - if buffer.len() < self.len() { + ::serialize_into(&(*self as u8), buffer) + } + + fn deserialize_from(buffer: &'a [u8]) -> Result + where + Self: Sized, + { + Ok(::deserialize_from(buffer)? != 0) + } +} + +impl<'a, T: Value<'a>> Value<'a> for Option { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if let Some(val) = self { + ::serialize_into(&true, buffer)?; + ::serialize_into(val, buffer) + } else { + ::serialize_into(&false, buffer) + } + } + + fn deserialize_from(buffer: &'a [u8]) -> Result + where + Self: Sized, + { + if ::deserialize_from(buffer)? { + Ok(Some(::deserialize_from(buffer)?)) + } else { + Ok(None) + } + } +} + +impl<'a, T: Value<'a>, const N: usize> Value<'a> for [T; N] { + fn serialize_into(&self, buffer: &mut [u8]) -> Result { + if buffer.len() < size_of::() * N { return Err(SerializationError::BufferTooSmall); } - buffer[..self.len()].copy_from_slice(self); - Ok(self.len()) + let mut size = 0; + for v in self { + size += ::serialize_into(v, &mut buffer[size..])?; + } + + Ok(size) } fn deserialize_from(buffer: &'a [u8]) -> Result where Self: Sized, { - Ok(buffer) + let mut array = MaybeUninit::<[T; N]>::uninit(); + + if N == 0 { + // SAFETY: This type is of zero size. + return Ok(unsafe { array.assume_init() }); + } + + let ptr = array.as_mut_ptr() as *mut T; + + // SAFETY: + // 1. The pointers are all inside the array via knowing `N`. + // 2. `ptr.add(1)` does never point outside the array. + // 3. `MaybeUninit::assume_init` is upheld with all values being filled. + unsafe { + for i in 0..N { + *ptr.add(i) = ::deserialize_from(&buffer[i * size_of::()..])?; + } + + Ok(array.assume_init()) + } } } -impl<'a, const N: usize> Value<'a> for [u8; N] { +impl<'a> Value<'a> for &'a [u8] { fn serialize_into(&self, buffer: &mut [u8]) -> Result { if buffer.len() < self.len() { return Err(SerializationError::BufferTooSmall); @@ -804,9 +864,7 @@ impl<'a, const N: usize> Value<'a> for [u8; N] { where Self: Sized, { - buffer - .try_into() - .map_err(|_| SerializationError::BufferTooSmall) + Ok(buffer) } } @@ -1033,7 +1091,7 @@ mod tests { &mut cache::NoCache::new(), &mut data_buffer, &0u8, - &[5], + &[5u8], ) .await .unwrap(); @@ -1043,7 +1101,7 @@ mod tests { &mut cache::NoCache::new(), &mut data_buffer, &0u8, - &[5, 6], + &[5u8, 6], ) .await .unwrap(); @@ -1066,7 +1124,7 @@ mod tests { &mut cache::NoCache::new(), &mut data_buffer, &1u8, - &[2, 2, 2, 2, 2, 2], + &[2u8, 2, 2, 2, 2, 2], ) .await .unwrap(); @@ -1455,7 +1513,7 @@ mod tests { &mut cache::NoCache::new(), &mut [0; 1024], &0u8, - &[0; 1024 - 4 * 2 - 8 - 1], + &[0u8; 1024 - 4 * 2 - 8 - 1], ) .await .unwrap(); @@ -1467,7 +1525,7 @@ mod tests { &mut cache::NoCache::new(), &mut [0; 1024], &0u8, - &[0; 1024 - 4 * 2 - 8 - 1 + 1], + &[0u8; 1024 - 4 * 2 - 8 - 1 + 1], ) .await, Err(Error::ItemTooBig)