Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map iterator #69

Merged
merged 9 commits into from
Dec 19, 2024
108 changes: 108 additions & 0 deletions src/map.rs
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@

use core::mem::{size_of, MaybeUninit};

use cache::NoCache;
use embedded_storage_async::nor_flash::MultiwriteNorFlash;

use crate::item::{find_next_free_item_spot, Item, ItemHeader, ItemIter};
Expand All @@ -110,6 +111,113 @@ use self::{

use super::*;

/// Iterator which iterates all non-erased & non-corrupted items in the map.
///
/// The iterator will return the (Key, Value) tuple when calling `next()`.
/// If the iterator ends, it will return `None`.
///
/// The following is a simple example of how to use the iterator:
/// ```rust
/// // Create the iterator
/// let mut iterator = get_item_iter(&mut flash, flash_range.clone());
///
/// // Iterate through all items
/// loop {
/// // Suppose the Key and Value types are u8, u32
/// if let Ok(Some(item)) = iterator.next::<u8, u32>(&mut buffer).await {
/// // Do something with the item
/// } else {
/// // Iterator ends
/// break;
/// }
/// }
/// ```
pub struct MapItemIter<'d, S: NorFlash> {
flash: &'d mut S,
flash_range: Range<u32>,
current_page_index: usize,
current_iter: ItemIter,
}

impl<'d, S: NorFlash> MapItemIter<'d, S> {
/// Get the next item in the iterator. Be careful that the given `data_buffer` should large enough to contain the serialized key and value.
pub async fn next<'a, K: Key, V: Value<'a>>(
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
data_buffer: &'a mut [u8],
) -> Result<Option<(K, V)>, Error<S::Error>> {
// Find the next item
let item = loop {
if let Some((item, _address)) = self.current_iter.next(self.flash, data_buffer).await? {
// We've found the next item, quit the loop
break item;
}

// The current page is done, we need to find the next page
// Find next page which is not open, update `self.current_iter`
loop {
self.current_page_index =
next_page::<S>(self.flash_range.clone(), self.current_page_index);

// All pages are checked, there's nothing left so we return None
if self.current_page_index >= self.flash_range.len() / S::ERASE_SIZE
|| self.current_page_index == 0
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
{
return Ok(None);
}

match get_page_state::<S>(
self.flash,
self.flash_range.clone(),
&mut NoCache::new(),
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
self.current_page_index,
)
.await
{
Ok(PageState::Closed) | Ok(PageState::PartialOpen) => {
self.current_iter = ItemIter::new(
calculate_page_address::<S>(
self.flash_range.clone(),
self.current_page_index,
),
calculate_page_end_address::<S>(
self.flash_range.clone(),
self.current_page_index,
),
);
break;
}
_ => continue,
}
}
};

let data_len = item.header.length as usize;
let (key, key_len) = K::deserialize_from(item.data())?;

Ok(Some((
key,
V::deserialize_from(&data_buffer[key_len..][..data_len - key_len])
.map_err(Error::SerializationError)?,
)))
}
}

/// Get an iterator that iterates over all non-erased & non-corrupted items in the map.
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
pub fn get_item_iter<'d, S: NorFlash>(
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
flash: &'d mut S,
flash_range: Range<u32>,
) -> MapItemIter<'d, S> {
MapItemIter {
flash,
flash_range: flash_range.clone(),
current_page_index: 0,
current_iter: ItemIter::new(
calculate_page_address::<S>(flash_range.clone(), 0),
calculate_page_end_address::<S>(flash_range.clone(), 0),
),
HaoboGu marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Get the last stored value from the flash that is associated with the given key.
/// If no value with the key is found, None is returned.
///
Expand Down