Skip to content

Commit

Permalink
Merge pull request #64 from korken89/more-map-value-impls
Browse files Browse the repository at this point in the history
Add `map::Value` imps for `bool` and `Option<T>`
  • Loading branch information
diondokter authored Aug 5, 2024
2 parents d3cdf72 + 37519cc commit b53ea61
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

## Unreleased

- Added `Value` impls for `bool`, `Option<T: Value>`, and `[T: Value; N]`

## 3.0.1 25-07-24

- Add `defmt` attributes to cache types.
Expand Down
94 changes: 76 additions & 18 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -693,7 +695,7 @@ macro_rules! impl_key_num {
($int:ty) => {
impl Key for $int {
fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
let len = core::mem::size_of::<Self>();
let len = size_of::<Self>();
if buffer.len() < len {
return Err(SerializationError::BufferTooSmall);
}
Expand All @@ -702,19 +704,19 @@ macro_rules! impl_key_num {
}

fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
let len = core::mem::size_of::<Self>();
let len = size_of::<Self>();
if buffer.len() < len {
return Err(SerializationError::BufferTooSmall);
}

Ok((
Self::from_le_bytes(buffer[..len].try_into().unwrap()),
core::mem::size_of::<Self>(),
size_of::<Self>(),
))
}

fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
Ok(core::mem::size_of::<Self>())
Ok(size_of::<Self>())
}
}
};
Expand Down Expand Up @@ -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<usize, SerializationError> {
if buffer.len() < self.len() {
<u8 as Value>::serialize_into(&(*self as u8), buffer)
}

fn deserialize_from(buffer: &'a [u8]) -> Result<Self, SerializationError>
where
Self: Sized,
{
Ok(<u8 as Value>::deserialize_from(buffer)? != 0)
}
}

impl<'a, T: Value<'a>> Value<'a> for Option<T> {
fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
if let Some(val) = self {
<bool as Value>::serialize_into(&true, buffer)?;
<T as Value>::serialize_into(val, buffer)
} else {
<bool as Value>::serialize_into(&false, buffer)
}
}

fn deserialize_from(buffer: &'a [u8]) -> Result<Self, SerializationError>
where
Self: Sized,
{
if <bool as Value>::deserialize_from(buffer)? {
Ok(Some(<T as Value>::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<usize, SerializationError> {
if buffer.len() < size_of::<T>() * N {
return Err(SerializationError::BufferTooSmall);
}

buffer[..self.len()].copy_from_slice(self);
Ok(self.len())
let mut size = 0;
for v in self {
size += <T as Value>::serialize_into(v, &mut buffer[size..])?;
}

Ok(size)
}

fn deserialize_from(buffer: &'a [u8]) -> Result<Self, SerializationError>
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) = <T as Value>::deserialize_from(&buffer[i * size_of::<T>()..])?;
}

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<usize, SerializationError> {
if buffer.len() < self.len() {
return Err(SerializationError::BufferTooSmall);
Expand All @@ -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)
}
}

Expand Down Expand Up @@ -1033,7 +1091,7 @@ mod tests {
&mut cache::NoCache::new(),
&mut data_buffer,
&0u8,
&[5],
&[5u8],
)
.await
.unwrap();
Expand All @@ -1043,7 +1101,7 @@ mod tests {
&mut cache::NoCache::new(),
&mut data_buffer,
&0u8,
&[5, 6],
&[5u8, 6],
)
.await
.unwrap();
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -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)
Expand Down

0 comments on commit b53ea61

Please sign in to comment.