Skip to main content

sequential_storage/
map.rs

1//! Implementation of the map logic.
2
3use core::{marker::PhantomData, mem::size_of};
4use embedded_storage_async::nor_flash::MultiwriteNorFlash;
5
6#[cfg(feature = "postcard")]
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    cache::CacheImpl,
11    item::{Item, ItemHeader, ItemIter},
12};
13
14use self::item::{ItemHeaderIter, ItemUnborrowed};
15
16use super::{
17    Debug, Error, GenericStorage, MAX_WORD_SIZE, NorFlash, NorFlashExt, PageState, Range,
18    calculate_page_address, calculate_page_end_address, calculate_page_index, calculate_page_size,
19    item, run_with_auto_repair,
20};
21
22/// Configuration for a map
23pub struct MapConfig<S> {
24    flash_range: Range<u32>,
25    _phantom: PhantomData<S>,
26}
27
28impl<S: NorFlash> MapConfig<S> {
29    /// Create a new map configuration. Will panic if the data is invalid.
30    /// If you want a fallible version, use [`Self::try_new`].
31    #[must_use]
32    pub const fn new(flash_range: Range<u32>) -> Self {
33        match Self::try_new(flash_range) {
34            Ok(config) => config,
35            Err(_) => panic!("Map config must be correct"),
36        }
37    }
38
39    /// Create a new map configuration. Will return None if the data is invalid
40    pub const fn try_new(flash_range: Range<u32>) -> Result<Self, MapConfigError> {
41        if !flash_range.start.is_multiple_of(S::ERASE_SIZE as u32) {
42            return Err(MapConfigError::StartRangeNotAtPageBoundary);
43        }
44        if !flash_range.end.is_multiple_of(S::ERASE_SIZE as u32) {
45            return Err(MapConfigError::EndRangeNotAtPageBoundary);
46        }
47        // At least 2 pages are used
48        if flash_range.end - flash_range.start < S::ERASE_SIZE as u32 * 2 {
49            return Err(MapConfigError::RangeTooSmall);
50        }
51
52        // A page must be able to store the 2 page states and at least one item header and a word for item data
53        if S::ERASE_SIZE < S::WORD_SIZE * 3 + ItemHeader::data_address::<S>(0) as usize {
54            return Err(MapConfigError::PagesTooSmall);
55        }
56        if S::WORD_SIZE > MAX_WORD_SIZE {
57            return Err(MapConfigError::WordSizeTooLarge);
58        }
59
60        Ok(Self {
61            flash_range,
62            _phantom: PhantomData,
63        })
64    }
65}
66
67/// Error for [`MapConfig`] constructor
68#[derive(Debug, Clone, PartialEq, Eq)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum MapConfigError {
71    /// The start range address is not a multiple of the erase size
72    StartRangeNotAtPageBoundary,
73    /// The end range address is not a multiple of the erase size
74    EndRangeNotAtPageBoundary,
75    /// The map needs at least 2 pages to operate, but got less
76    RangeTooSmall,
77    /// The pages of the flash are too small to work with
78    PagesTooSmall,
79    /// The word size of the flash is bigger than [`MAX_WORD_SIZE`]
80    WordSizeTooLarge,
81}
82
83/// A map-like storage
84///
85/// When a key-value is stored, it overwrites the any old items with the same key.
86///
87/// ## Basic API
88///
89/// ```rust
90/// # use sequential_storage::cache::Cache;
91/// # use sequential_storage::map::{MapConfig, MapStorage};
92/// # use mock_flash::MockFlashBase;
93/// # use futures::executor::block_on;
94/// # type Flash = MockFlashBase<10, 1, 4096>;
95/// # mod mock_flash {
96/// #   include!("mock_flash.rs");
97/// # }
98/// # fn init_flash() -> Flash {
99/// #     Flash::new(mock_flash::WriteCountCheck::Twice, None, false)
100/// # }
101///
102/// # block_on(async {
103/// // Initialize the flash. This can be internal or external
104/// let mut flash = init_flash();
105///
106/// // Create the storage instance
107///
108/// // We provide the flash addresses in which it will operate.
109/// // The storage will not read, write or erase outside of this range.
110///
111/// // We also put the config in a const block so if the config is bad we'll get a compile time error
112///
113/// // With the generics we specify that this is a map with `u8` as the key
114/// let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, Cache::new_uncached());
115///
116/// // We need to give the crate a buffer to work with.
117/// // It must be big enough to serialize the biggest value of your storage type in,
118/// // rounded up to to word alignment of the flash. Some kinds of internal flash may require
119/// // this buffer to be aligned in RAM as well.
120/// let mut data_buffer = [0; 128];
121///
122/// // We can fetch an item from the flash. We're using `u8` as our key type and `u32` as our value type.
123/// // Nothing is stored in it yet, so it will return None.
124///
125/// assert_eq!(
126///     storage.fetch_item::<u32>(
127///         &mut data_buffer,
128///         &42,
129///     ).await.unwrap(),
130///     None
131/// );
132///
133/// // Now we store an item the flash with key 42.
134/// // Again we make sure we pass the correct key and value types, u8 and u32.
135/// // It is important to do this consistently.
136///
137/// storage.store_item(
138///     &mut data_buffer,
139///     &42u8,
140///     &104729u32,
141/// ).await.unwrap();
142///
143/// // When we ask for key 42, we now get back a Some with the correct value
144///
145/// assert_eq!(
146///     storage.fetch_item::<u32>(
147///         &mut data_buffer,
148///         &42,
149///     ).await.unwrap(),
150///     Some(104729)
151/// );
152/// # });
153/// ```
154///
155/// For your convenience there are premade implementations for the [Key] and [Value] traits.
156pub struct MapStorage<K: Key, S: NorFlash, C: CacheImpl<K>> {
157    inner: GenericStorage<S, C, K>,
158    _phantom: PhantomData<K>,
159}
160
161impl<S: NorFlash, C: CacheImpl<K>, K: Key> MapStorage<K, S, C> {
162    /// Create a new map instance
163    ///
164    /// The provided cache instance must be new or must be in the exact correct state for the current flash contents.
165    /// If the cache is bad, undesirable things will happen.
166    /// So, it's ok to reuse the cache gotten from the [`Self::destroy`] method when the flash hasn't changed since calling destroy.
167    pub const fn new(storage: S, config: MapConfig<S>, cache: C) -> Self {
168        Self {
169            inner: GenericStorage {
170                flash: storage,
171                flash_range: config.flash_range,
172                cache,
173                _phantom: PhantomData,
174            },
175            _phantom: PhantomData,
176        }
177    }
178
179    /// Get the last stored value from the flash that is associated with the given key.
180    /// If no value with the key is found, None is returned.
181    ///
182    /// You must make sure the used type as [Value] is correct for the key used.
183    /// If not, there can be wrong values or deserialization errors.
184    ///
185    /// The data buffer must be long enough to hold the longest serialized data of your [Key] + [Value] types combined,
186    /// rounded up to flash word alignment.
187    pub async fn fetch_item<'d, V: Value<'d>>(
188        &mut self,
189        data_buffer: &'d mut [u8],
190        search_key: &K,
191    ) -> Result<Option<V>, Error<S::Error>> {
192        let result = run_with_auto_repair!(
193            function = self.fetch_item_with_location(data_buffer, search_key).await,
194            repair = self.try_repair(data_buffer).await?
195        );
196
197        let Some((item, _, item_key_len)) = result? else {
198            return Ok(None);
199        };
200
201        let data_len = item.header.length as usize;
202        let item_key_len = match item_key_len {
203            Some(item_key_len) => item_key_len,
204            None => K::get_len(&data_buffer[..data_len])?,
205        };
206
207        let (value, _size) =
208            V::deserialize_from(&data_buffer[item_key_len..][..data_len - item_key_len])
209                .map_err(Error::SerializationError)?;
210        Ok(Some(value))
211    }
212
213    /// Fetch the item, but with the item unborrowed, the address of the item and the length of the key
214    #[allow(clippy::type_complexity)]
215    async fn fetch_item_with_location(
216        &mut self,
217        data_buffer: &mut [u8],
218        search_key: &K,
219    ) -> Result<Option<(ItemUnborrowed, u32, Option<usize>)>, Error<S::Error>> {
220        if self.inner.cache.is_dirty() {
221            self.inner.cache.invalidate_cache_state();
222        }
223
224        'cache: {
225            if let Some(cached_location) = self.inner.cache.key_location(search_key) {
226                let page_index = calculate_page_index::<S>(self.flash_range(), cached_location);
227                let page_data_end_address =
228                    calculate_page_end_address::<S>(self.flash_range(), page_index)
229                        - S::WORD_SIZE as u32;
230
231                let Some(header) = ItemHeader::read_new(
232                    &mut self.inner.flash,
233                    cached_location,
234                    page_data_end_address,
235                )
236                .await?
237                else {
238                    // The cache points to a non-existing item?
239                    #[expect(clippy::assertions_on_constants, reason = "Clippy is wrong here")]
240                    {
241                        assert!(
242                            !cfg!(feature = "_test"),
243                            "Wrong cache value. Addr: {cached_location}"
244                        );
245                    }
246                    self.inner.cache.invalidate_cache_state();
247                    break 'cache;
248                };
249
250                let item = header
251                    .read_item(
252                        &mut self.inner.flash,
253                        data_buffer,
254                        cached_location,
255                        page_data_end_address,
256                    )
257                    .await?;
258
259                match item {
260                    item::MaybeItem::Corrupted(_, _) | item::MaybeItem::Erased(_, _) => {
261                        #[expect(clippy::assertions_on_constants, reason = "Clippy is wrong here")]
262                        {
263                            assert!(
264                                !cfg!(feature = "_test"),
265                                "Wrong cache value. Addr: {cached_location}"
266                            );
267                        }
268
269                        // The cache points to a corrupted or erased item?
270                        self.inner.cache.invalidate_cache_state();
271                        break 'cache;
272                    }
273                    item::MaybeItem::Present(item) => {
274                        return Ok(Some((item.unborrow(), cached_location, None)));
275                    }
276                }
277            }
278        }
279
280        // We need to find the page we were last using. This should be the only partial open page.
281        let mut last_used_page = self
282            .inner
283            .find_first_page(0, PageState::PartialOpen)
284            .await?;
285
286        if last_used_page.is_none() {
287            // In the event that all pages are still open or the last used page was just closed, we search for the first open page.
288            // If the page one before that is closed, then that's the last used page.
289            if let Some(first_open_page) = self.inner.find_first_page(0, PageState::Open).await? {
290                let previous_page = self.inner.previous_page(first_open_page);
291                if self
292                    .inner
293                    .get_page_state_cached(previous_page)
294                    .await?
295                    .is_closed()
296                {
297                    last_used_page = Some(previous_page);
298                } else {
299                    // The page before the open page is not closed, so it must be open.
300                    // This means that all pages are open and that we don't have any items yet.
301                    self.inner.cache.unmark_dirty();
302                    return Ok(None);
303                }
304            } else {
305                // There are no open pages, so everything must be closed.
306                // Something is up and this should never happen.
307                // To recover, we will just erase all the flash.
308                return Err(Error::Corrupted {
309                    #[cfg(feature = "_test")]
310                    backtrace: std::backtrace::Backtrace::capture(),
311                });
312            }
313        }
314
315        // We must now find the most recent storage item with the key that was asked for.
316        // If we don't find it in the current page, then we check again in the previous page if that page is closed.
317
318        let mut current_page_to_check = last_used_page.unwrap();
319        let mut newest_found_item_data = None;
320
321        loop {
322            let page_data_start_address =
323                calculate_page_address::<S>(self.flash_range(), current_page_to_check)
324                    + S::WORD_SIZE as u32;
325            let page_data_end_address =
326                calculate_page_end_address::<S>(self.flash_range(), current_page_to_check)
327                    - S::WORD_SIZE as u32;
328
329            let mut it = ItemIter::new(page_data_start_address, page_data_end_address);
330            while let Some((item, address)) = it.next(&mut self.inner.flash, data_buffer).await? {
331                let (found_key, found_key_len) = K::deserialize_from(item.data())?;
332                if found_key == *search_key {
333                    newest_found_item_data = Some((address, found_key_len));
334                }
335            }
336
337            // We've found the item! We can stop searching
338            if let Some((newest_found_item_address, _)) = newest_found_item_data.as_ref() {
339                self.inner
340                    .cache
341                    .notice_key_location(search_key, *newest_found_item_address, false);
342
343                break;
344            }
345
346            // We have not found the item. We've got to look in the previous page, but only if that page is closed and contains data.
347            let previous_page = self.inner.previous_page(current_page_to_check);
348
349            if self.inner.get_page_state_cached(previous_page).await? != PageState::Closed {
350                // We've looked through all the pages with data and couldn't find the item
351                self.inner.cache.unmark_dirty();
352                return Ok(None);
353            }
354
355            current_page_to_check = previous_page;
356        }
357
358        self.inner.cache.unmark_dirty();
359
360        // We now need to reread the item because we lost all its data other than its address
361
362        if let Some((newest_found_item_address, newest_found_item_key_len)) = newest_found_item_data
363        {
364            let item =
365                ItemHeader::read_new(&mut self.inner.flash, newest_found_item_address, u32::MAX)
366                    .await?
367                    .ok_or_else(|| {
368                        // How come there's no item header here!? We just found it!
369                        Error::Corrupted {
370                            #[cfg(feature = "_test")]
371                            backtrace: std::backtrace::Backtrace::capture(),
372                        }
373                    })?
374                    .read_item(
375                        &mut self.inner.flash,
376                        data_buffer,
377                        newest_found_item_address,
378                        u32::MAX,
379                    )
380                    .await?;
381
382            Ok(Some((
383                item.unwrap()?.unborrow(),
384                newest_found_item_address,
385                Some(newest_found_item_key_len),
386            )))
387        } else {
388            Ok(None)
389        }
390    }
391
392    /// Store a key-value pair into flash memory.
393    /// It will (logically) overwrite the last value that has the same key.
394    ///
395    /// The data buffer must be long enough to hold the longest serialized data of your [Key] + [Value] types combined,
396    /// rounded up to flash word alignment.
397    pub async fn store_item<'d, V: Value<'d>>(
398        &mut self,
399        data_buffer: &mut [u8],
400        key: &K,
401        item: &V,
402    ) -> Result<(), Error<S::Error>> {
403        run_with_auto_repair!(
404            function = self
405                .store_item_inner::<dyn Value>(data_buffer, key, item)
406                .await,
407            repair = self.try_repair(data_buffer).await?
408        )
409    }
410
411    /// Same as [Self::store_item], except it doesn't turn the passed value generic into a trait object and passes it generically down the stack.
412    ///
413    /// Using a trait object is done by default to save on binary size while not impacting performance that much.
414    /// However, in some cases you might have weird [Sync], [Send] or other auto trait requirements where a trait object gets in the way.
415    /// So with this function you opt out of the trait object and you can pass your own values directly.
416    ///
417    /// You should keep using [Self::store_item] unless you really need this function.
418    pub async fn store_item_generic<'d, V: Value<'d> + ?Sized>(
419        &mut self,
420        data_buffer: &mut [u8],
421        key: &K,
422        item: &V,
423    ) -> Result<(), Error<S::Error>> {
424        run_with_auto_repair!(
425            function = self.store_item_inner::<V>(data_buffer, key, item).await,
426            repair = self.try_repair(data_buffer).await?
427        )
428    }
429
430    async fn store_item_inner<'d, V: Value<'d> + ?Sized>(
431        &mut self,
432        data_buffer: &mut [u8],
433        key: &K,
434        item: &V,
435    ) -> Result<(), Error<S::Error>> {
436        if self.inner.cache.is_dirty() {
437            self.inner.cache.invalidate_cache_state();
438        }
439
440        let mut recursion_level = 0;
441        loop {
442            // Check if we're in an infinite recursion which happens when we don't have enough space to store the new data
443            if recursion_level == self.inner.get_pages(0).count() {
444                self.inner.cache.unmark_dirty();
445                return Err(Error::FullStorage);
446            }
447
448            // If there is a partial open page, we try to write in that first if there is enough space
449            let next_page_to_use = if let Some(partial_open_page) = self
450                .inner
451                .find_first_page(0, PageState::PartialOpen)
452                .await?
453            {
454                // We found a partial open page, but at this point it's relatively cheap to do a consistency check
455                if !self
456                    .inner
457                    .get_page_state_cached(self.inner.next_page(partial_open_page))
458                    .await?
459                    .is_open()
460                {
461                    // Oh oh, the next page which serves as the buffer page is not open. We're corrupt.
462                    // This likely happened because of an unexpected shutdown during data migration from the
463                    // then new buffer page to the new partial open page.
464                    // The repair function should be able to repair this.
465                    return Err(Error::Corrupted {
466                        #[cfg(feature = "_test")]
467                        backtrace: std::backtrace::Backtrace::capture(),
468                    });
469                }
470
471                // We've got to search where the free space is since the page starts with items present already
472
473                let page_data_start_address =
474                    calculate_page_address::<S>(self.flash_range(), partial_open_page)
475                        + S::WORD_SIZE as u32;
476                let page_data_end_address =
477                    calculate_page_end_address::<S>(self.flash_range(), partial_open_page)
478                        - S::WORD_SIZE as u32;
479
480                let key_len = key.serialize_into(data_buffer)?;
481                let item_data_length = key_len
482                    + item
483                        .serialize_into(&mut data_buffer[key_len..])
484                        .map_err(Error::SerializationError)?;
485
486                if item_data_length > u16::MAX as usize
487                    || item_data_length
488                        > calculate_page_size::<S>()
489                            .saturating_sub(ItemHeader::data_address::<S>(0) as usize)
490                {
491                    self.inner.cache.unmark_dirty();
492                    return Err(Error::ItemTooBig);
493                }
494
495                let free_spot_address = self
496                    .inner
497                    .find_next_free_item_spot(
498                        page_data_start_address,
499                        page_data_end_address,
500                        item_data_length as u32,
501                    )
502                    .await?;
503
504                if let Some(free_spot_address) = free_spot_address {
505                    self.inner
506                        .cache
507                        .notice_key_location(key, free_spot_address, true);
508                    Item::write_new(
509                        &mut self.inner.flash,
510                        self.inner.flash_range.clone(),
511                        &mut self.inner.cache,
512                        free_spot_address,
513                        &data_buffer[..item_data_length],
514                    )
515                    .await?;
516
517                    self.inner.cache.unmark_dirty();
518                    return Ok(());
519                }
520
521                // The item doesn't fit here, so we need to close this page and move to the next
522                self.inner.close_page(partial_open_page).await?;
523                Some(self.inner.next_page(partial_open_page))
524            } else {
525                None
526            };
527
528            // If we get here, there was no partial page found or the partial page has now been closed because the item didn't fit.
529            // If there was a partial page, then we need to look at the next page. It's supposed to be open since it was the previous empty buffer page.
530            // The new buffer page has to be emptied if it was closed.
531            // If there was no partial page, we just use the first open page.
532
533            if let Some(next_page_to_use) = next_page_to_use {
534                let next_page_state = self.inner.get_page_state_cached(next_page_to_use).await?;
535
536                if !next_page_state.is_open() {
537                    // What was the previous buffer page was not open...
538                    return Err(Error::Corrupted {
539                        #[cfg(feature = "_test")]
540                        backtrace: std::backtrace::Backtrace::capture(),
541                    });
542                }
543
544                // Since we're gonna write data here, let's already partially close the page
545                // This could be done after moving the data, but this is more robust in the
546                // face of shutdowns and cancellations
547                self.inner.partial_close_page(next_page_to_use).await?;
548
549                let next_buffer_page = self.inner.next_page(next_page_to_use);
550                let next_buffer_page_state =
551                    self.inner.get_page_state_cached(next_buffer_page).await?;
552
553                if !next_buffer_page_state.is_open() {
554                    self.migrate_items(data_buffer, next_buffer_page, next_page_to_use)
555                        .await?;
556                }
557            } else {
558                // There's no partial open page, so we just gotta turn the first open page into a partial open one
559                let Some(first_open_page) = self.inner.find_first_page(0, PageState::Open).await?
560                else {
561                    // Uh oh, no open pages.
562                    // Something has gone wrong.
563                    // We should never get here.
564                    return Err(Error::Corrupted {
565                        #[cfg(feature = "_test")]
566                        backtrace: std::backtrace::Backtrace::capture(),
567                    });
568                };
569
570                self.inner.partial_close_page(first_open_page).await?;
571            }
572
573            // If we get here, we just freshly partially closed a new page, so the next loop iteration should succeed.
574            recursion_level += 1;
575        }
576    }
577
578    /// Fully remove an item. Additional calls to fetch with the same key will return None until
579    /// a new one is stored again.
580    ///
581    /// <div class="warning">
582    /// This is really slow!
583    ///
584    /// All items in flash have to be read and deserialized to find the items with the key.
585    /// This is unlikely to be cached well.
586    ///
587    /// Alternatively, e.g. when you don't have a [`MultiwriteNorFlash`] flash, you could store your value inside an Option
588    /// and store the value `None` to mark it as erased.
589    /// </div>
590    pub async fn remove_item(
591        &mut self,
592        data_buffer: &mut [u8],
593        search_key: &K,
594    ) -> Result<(), Error<S::Error>>
595    where
596        S: MultiwriteNorFlash,
597    {
598        run_with_auto_repair!(
599            function = self.remove_item_inner(data_buffer, Some(search_key)).await,
600            repair = self.try_repair(data_buffer).await?
601        )
602    }
603
604    /// Fully remove all stored items. Additional calls to fetch with any key will return None until
605    /// new items are stored again.
606    ///
607    /// <div class="warning">
608    /// This might be really slow! This doesn't simply erase flash, but goes through all items and marks them as deleted.
609    /// This is better for flash endurance.
610    ///
611    /// You might want to simply erase the flash range, e.g. if your flash does not implement [`MultiwriteNorFlash`].
612    /// Consider using the helper method for that: [`Self::erase_all`].
613    /// </div>
614    pub async fn remove_all_items(&mut self, data_buffer: &mut [u8]) -> Result<(), Error<S::Error>>
615    where
616        S: MultiwriteNorFlash,
617    {
618        run_with_auto_repair!(
619            function = self.remove_item_inner(data_buffer, None).await,
620            repair = self.try_repair(data_buffer).await?
621        )
622    }
623
624    /// If `search_key` is None, then all items will be removed
625    async fn remove_item_inner(
626        &mut self,
627        data_buffer: &mut [u8],
628        search_key: Option<&K>,
629    ) -> Result<(), Error<S::Error>>
630    where
631        S: MultiwriteNorFlash,
632    {
633        if let Some(key) = &search_key {
634            self.inner.cache.notice_key_erased(key);
635        } else {
636            self.inner.cache.invalidate_cache_state();
637        }
638
639        // Search for the last used page. We're gonna erase from the one after this first.
640        // If we get an early shutoff or cancellation, this will make it so that we don't return
641        // an old version of the key on the next fetch.
642        let last_used_page = self
643            .inner
644            .find_first_page(0, PageState::PartialOpen)
645            .await?
646            .unwrap_or_default();
647
648        // Go through all the pages
649        for page_index in self.inner.get_pages(self.inner.next_page(last_used_page)) {
650            if self
651                .inner
652                .get_page_state_cached(page_index)
653                .await?
654                .is_open()
655            {
656                // This page is open, we don't have to check it
657                continue;
658            }
659
660            let page_data_start_address =
661                calculate_page_address::<S>(self.flash_range(), page_index) + S::WORD_SIZE as u32;
662            let page_data_end_address =
663                calculate_page_end_address::<S>(self.flash_range(), page_index)
664                    - S::WORD_SIZE as u32;
665
666            // Go through all items on the page
667            let mut item_headers =
668                ItemHeaderIter::new(page_data_start_address, page_data_end_address);
669
670            while let (Some(item_header), item_address) =
671                item_headers.next(&mut self.inner.flash).await?
672            {
673                let item = item_header
674                    .read_item(
675                        &mut self.inner.flash,
676                        data_buffer,
677                        item_address,
678                        page_data_end_address,
679                    )
680                    .await?;
681
682                match item {
683                    item::MaybeItem::Corrupted(_, _) | item::MaybeItem::Erased(_, _) => continue,
684                    item::MaybeItem::Present(item) => {
685                        let item_match = match search_key {
686                            Some(search_key) => K::deserialize_from(item.data())?.0 == *search_key,
687                            _ => true,
688                        };
689                        // If this item has the same key as the key we're trying to erase, then erase the item.
690                        // But keep going! We need to erase everything.
691                        if item_match {
692                            item.header
693                                .erase_data(
694                                    &mut self.inner.flash,
695                                    self.inner.flash_range.clone(),
696                                    &mut self.inner.cache,
697                                    item_address,
698                                )
699                                .await?;
700                        }
701                    }
702                }
703            }
704        }
705
706        // We're done, we now know the cache is in a good state
707        self.inner.cache.unmark_dirty();
708
709        Ok(())
710    }
711
712    /// Get an iterator that iterates over all non-erased & non-corrupted items in the map.
713    ///
714    /// <div class="warning">
715    /// You should be very careful when using the map item iterator:
716    /// <ul>
717    /// <li>
718    /// Because map doesn't erase the items when you insert a new one with the same key,
719    /// so it's expected that the iterator returns items with the same key multiple times.
720    /// Only the last returned one is the `active` one.
721    /// </li>
722    /// <li>
723    /// The iterator requires ALL items in the storage have the SAME Value type.
724    /// If you have different types of items in your map, the iterator might return incorrect data or error.
725    /// </li>
726    /// </ul>
727    /// </div>
728    ///
729    /// The following is a simple example of how to use the iterator:
730    /// ```rust
731    /// # use sequential_storage::cache::Cache;
732    /// # use sequential_storage::map::{MapConfig, MapStorage};
733    /// # use mock_flash::MockFlashBase;
734    /// # use futures::executor::block_on;
735    /// # use std::collections::HashMap;
736    /// # type Flash = MockFlashBase<10, 1, 4096>;
737    /// # mod mock_flash {
738    /// #   include!("mock_flash.rs");
739    /// # }
740    /// # fn init_flash() -> Flash {
741    /// #     Flash::new(mock_flash::WriteCountCheck::Twice, None, false)
742    /// # }
743    ///
744    /// # block_on(async {
745    /// let mut flash = init_flash();
746    ///
747    /// let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, Cache::new_uncached());
748    /// let mut data_buffer = [0; 128];
749    ///
750    /// // Create the iterator of map items
751    /// let mut iterator = storage.fetch_all_items(
752    ///     &mut data_buffer
753    /// )
754    /// .await
755    /// .unwrap();
756    ///
757    /// let mut all_items = HashMap::new();
758    ///
759    /// // Iterate through all items, suppose the Key and Value types are u8, u32
760    /// while let Some((key, value)) = iterator
761    ///     .next::<u32>(&mut data_buffer)
762    ///     .await
763    ///     .unwrap()
764    /// {
765    ///     // Do something with the item.
766    ///     // Please note that for the same key there might be multiple items returned,
767    ///     // the last one is the current active one.
768    ///     all_items.insert(key, value);
769    /// }
770    /// # })
771    /// ```
772    pub async fn fetch_all_items(
773        &mut self,
774        data_buffer: &mut [u8],
775    ) -> Result<MapItemIter<'_, K, S, C>, Error<S::Error>> {
776        // Get the first page index.
777        // The first page used by the map is the next page of the `PartialOpen` page or the last `Closed` page
778        let first_page = run_with_auto_repair!(
779            function = {
780                match self
781                    .inner
782                    .find_first_page(0, PageState::PartialOpen)
783                    .await?
784                {
785                    Some(last_used_page) => {
786                        // The next page of the `PartialOpen` page is the first page
787                        Ok(self.inner.next_page(last_used_page))
788                    }
789                    None => {
790                        // In the event that all pages are still open or the last used page was just closed, we search for the first open page.
791                        // If the page one before that is closed, then that's the last used page.
792                        if let Some(first_open_page) =
793                            self.inner.find_first_page(0, PageState::Open).await?
794                        {
795                            let previous_page = self.inner.previous_page(first_open_page);
796                            if self
797                                .inner
798                                .get_page_state_cached(previous_page)
799                                .await?
800                                .is_closed()
801                            {
802                                // The previous page is closed, so the first_open_page is what we want
803                                Ok(first_open_page)
804                            } else {
805                                // The page before the open page is not closed, so it must be open.
806                                // This means that all pages are open and that we don't have any items yet.
807                                self.inner.cache.unmark_dirty();
808                                Ok(0)
809                            }
810                        } else {
811                            // There are no open pages, so everything must be closed.
812                            // Something is up and this should never happen.
813                            // To recover, we will just erase all the flash.
814                            Err(Error::Corrupted {
815                                #[cfg(feature = "_test")]
816                                backtrace: std::backtrace::Backtrace::capture(),
817                            })
818                        }
819                    }
820                }
821            },
822            repair = self.try_repair(data_buffer).await?
823        )?;
824
825        let start_address =
826            calculate_page_address::<S>(self.flash_range(), first_page) + S::WORD_SIZE as u32;
827        let end_address =
828            calculate_page_end_address::<S>(self.flash_range(), first_page) - S::WORD_SIZE as u32;
829
830        Ok(MapItemIter {
831            storage: self,
832            first_page,
833            current_page_index: first_page,
834            current_iter: ItemIter::new(start_address, end_address),
835            _key: PhantomData,
836        })
837    }
838
839    async fn migrate_items(
840        &mut self,
841        data_buffer: &mut [u8],
842        source_page: usize,
843        target_page: usize,
844    ) -> Result<(), Error<S::Error>> {
845        // We need to move the data from the next buffer page to the next_page_to_use, but only if that data
846        // doesn't have a newer value somewhere else.
847
848        let mut next_page_write_address =
849            calculate_page_address::<S>(self.flash_range(), target_page) + S::WORD_SIZE as u32;
850
851        let mut it = ItemIter::new(
852            calculate_page_address::<S>(self.flash_range(), source_page) + S::WORD_SIZE as u32,
853            calculate_page_end_address::<S>(self.flash_range(), source_page) - S::WORD_SIZE as u32,
854        );
855        while let Some((item, item_address)) = it.next(&mut self.inner.flash, data_buffer).await? {
856            let (key, _) = K::deserialize_from(item.data())?;
857
858            // We're in a decent state here
859            self.inner.cache.unmark_dirty();
860
861            // Search for the newest item with the key we found
862            let Some((found_item, found_address, _)) =
863                self.fetch_item_with_location(data_buffer, &key).await?
864            else {
865                // We couldn't even find our own item?
866                return Err(Error::Corrupted {
867                    #[cfg(feature = "_test")]
868                    backtrace: std::backtrace::Backtrace::capture(),
869                });
870            };
871
872            let found_item = found_item
873                .reborrow(data_buffer)
874                .ok_or_else(|| Error::LogicBug {
875                    #[cfg(feature = "_test")]
876                    backtrace: std::backtrace::Backtrace::capture(),
877                })?;
878
879            if found_address == item_address {
880                self.inner
881                    .cache
882                    .notice_key_location(&key, next_page_write_address, true);
883                found_item
884                    .write(
885                        &mut self.inner.flash,
886                        self.inner.flash_range.clone(),
887                        &mut self.inner.cache,
888                        next_page_write_address,
889                    )
890                    .await?;
891                next_page_write_address = found_item
892                    .header
893                    .next_item_address::<S>(next_page_write_address);
894            }
895        }
896
897        self.inner.open_page(source_page).await?;
898
899        Ok(())
900    }
901
902    /// Try to repair the state of the flash to hopefull get back everything in working order.
903    /// Care is taken that no data is lost, but this depends on correctly repairing the state and
904    /// so is only best effort.
905    ///
906    /// This function might be called after a different function returned the [`Error::Corrupted`] error.
907    /// There's no guarantee it will work.
908    ///
909    /// If this function or the function call after this crate returns [`Error::Corrupted`], then it's unlikely
910    /// that the state can be recovered. To at least make everything function again at the cost of losing the data,
911    /// erase the flash range.
912    async fn try_repair(&mut self, data_buffer: &mut [u8]) -> Result<(), Error<S::Error>> {
913        self.inner.cache.invalidate_cache_state();
914
915        self.inner.try_general_repair().await?;
916
917        // Let's check if we corrupted in the middle of a migration
918        if let Some(partial_open_page) = self
919            .inner
920            .find_first_page(0, PageState::PartialOpen)
921            .await?
922        {
923            let buffer_page = self.inner.next_page(partial_open_page);
924            if !self
925                .inner
926                .get_page_state_cached(buffer_page)
927                .await?
928                .is_open()
929            {
930                // Yes, the migration got interrupted. Let's redo it.
931                // To do that, we erase the partial open page first because it contains incomplete data.
932                self.inner.open_page(partial_open_page).await?;
933
934                // Then partially close it again
935                self.inner.partial_close_page(partial_open_page).await?;
936
937                self.migrate_items(data_buffer, buffer_page, partial_open_page)
938                    .await?;
939            }
940        }
941
942        Ok(())
943    }
944
945    /// Resets the flash in the entire given flash range.
946    ///
947    /// This is just a thin helper function as it just calls the flash's erase function.
948    pub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>> {
949        self.inner.erase_all()
950    }
951
952    /// Get the minimal overhead size per stored item for the given flash type.
953    ///
954    /// The associated data of each item is additionally padded to a full flash word size, but that's not part of this number.\
955    /// This means the full item length is `returned number + (data length).next_multiple_of(S::WORD_SIZE)`.
956    #[must_use]
957    pub const fn item_overhead_size() -> u32 {
958        GenericStorage::<S, C, K>::item_overhead_size()
959    }
960
961    /// Destroy the instance to get back the flash and the cache.
962    ///
963    /// The cache can be passed to a new storage instance, but only for the same flash region and if nothing has changed in flash.
964    pub fn destroy(self) -> (S, C) {
965        self.inner.destroy()
966    }
967
968    /// Get a reference to the flash. Mutating the memory is at your own risk.
969    pub const fn flash(&mut self) -> &mut S {
970        self.inner.flash()
971    }
972
973    /// Get the flash range being used
974    pub const fn flash_range(&self) -> Range<u32> {
975        self.inner.flash_range()
976    }
977
978    /// Get a reference to the cache
979    #[cfg(any(test, fuzzing))]
980    pub const fn cache(&mut self) -> &mut C {
981        &mut self.inner.cache
982    }
983
984    #[cfg(any(test, feature = "std", fuzzing))]
985    /// Print all items in flash to the returned string
986    ///
987    /// This is meant as a debugging utility. The string format is not stable.
988    pub fn print_items(&mut self) -> impl Future<Output = String> {
989        self.inner.print_items()
990    }
991}
992
993/// Iterator which iterates all non-erased & non-corrupted items in the map.
994///
995/// The iterator will return the (Key, Value) tuple when calling `next()`.
996/// If the iterator ends, it will return `Ok(None)`.
997///
998/// The following is a simple example of how to use the iterator:
999/// ```rust
1000/// # use sequential_storage::cache::Cache;
1001/// # use sequential_storage::map::{MapConfig, MapStorage};
1002/// # use mock_flash::MockFlashBase;
1003/// # use futures::executor::block_on;
1004/// # use std::collections::HashMap;
1005/// # type Flash = MockFlashBase<10, 1, 4096>;
1006/// # mod mock_flash {
1007/// #   include!("mock_flash.rs");
1008/// # }
1009/// # fn init_flash() -> Flash {
1010/// #     Flash::new(mock_flash::WriteCountCheck::Twice, None, false)
1011/// # }
1012///
1013/// # block_on(async {
1014/// let mut flash = init_flash();
1015///
1016/// let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, Cache::new_uncached());
1017/// let mut data_buffer = [0; 128];
1018///
1019/// // Create the iterator of map items
1020/// let mut iterator = storage.fetch_all_items(
1021///     &mut data_buffer
1022/// )
1023/// .await
1024/// .unwrap();
1025///
1026/// let mut all_items = HashMap::new();
1027///
1028/// // Iterate through all items, suppose the Key and Value types are u8, u32
1029/// while let Some((key, value)) = iterator
1030///     .next::<u32>(&mut data_buffer)
1031///     .await
1032///     .unwrap()
1033/// {
1034///     // Do something with the item.
1035///     // Please note that for the same key there might be multiple items returned,
1036///     // the last one is the current active one.
1037///     all_items.insert(key, value);
1038/// }
1039/// # })
1040/// ```
1041pub struct MapItemIter<'s, K: Key, S: NorFlash, C: CacheImpl<K>> {
1042    storage: &'s mut MapStorage<K, S, C>,
1043    first_page: usize,
1044    current_page_index: usize,
1045    pub(crate) current_iter: ItemIter,
1046    _key: PhantomData<K>,
1047}
1048
1049impl<K: Key, S: NorFlash, C: CacheImpl<K>> MapItemIter<'_, K, S, C> {
1050    /// Get the next item in the iterator. Be careful that the given `data_buffer` should large enough to contain the serialized key and value.
1051    pub async fn next<'a, V: Value<'a>>(
1052        &mut self,
1053        data_buffer: &'a mut [u8],
1054    ) -> Result<Option<(K, V)>, Error<S::Error>> {
1055        // Find the next item
1056        let item = loop {
1057            if let Some((item, _address)) = self
1058                .current_iter
1059                .next(&mut self.storage.inner.flash, data_buffer)
1060                .await?
1061            {
1062                // We've found the next item, quit the loop
1063                break item;
1064            }
1065
1066            // The current page is done, we need to find the next page
1067            // Find next page which is not open, update `self.current_iter`
1068            loop {
1069                self.current_page_index = self.storage.inner.next_page(self.current_page_index);
1070
1071                // We've looped back to the first page, which means all pages are checked, there's nothing left so we return None
1072                if self.current_page_index == self.first_page {
1073                    return Ok(None);
1074                }
1075
1076                match self
1077                    .storage
1078                    .inner
1079                    .get_page_state_cached(self.current_page_index)
1080                    .await
1081                {
1082                    Ok(PageState::Closed | PageState::PartialOpen) => {
1083                        self.current_iter = ItemIter::new(
1084                            calculate_page_address::<S>(
1085                                self.storage.inner.flash_range.clone(),
1086                                self.current_page_index,
1087                            ) + S::WORD_SIZE as u32,
1088                            calculate_page_end_address::<S>(
1089                                self.storage.inner.flash_range.clone(),
1090                                self.current_page_index,
1091                            ) - S::WORD_SIZE as u32,
1092                        );
1093                        break;
1094                    }
1095                    _ => continue,
1096                }
1097            }
1098        };
1099
1100        let data_len = item.header.length as usize;
1101        let (key, key_len) = K::deserialize_from(item.data())?;
1102        let (value, _value_len) = V::deserialize_from(&data_buffer[..data_len][key_len..])
1103            .map_err(Error::SerializationError)?;
1104
1105        Ok(Some((key, value)))
1106    }
1107}
1108
1109/// Anything implementing this trait can be used as a key in the map functions.
1110///
1111/// It provides a way to serialize and deserialize the key.
1112///
1113/// The `Eq` bound is used because we need to be able to compare keys and the
1114/// `Clone` bound helps us pass the key around.
1115///
1116/// The key cannot have a lifetime like the [Value]
1117pub trait Key: Eq + Clone + Sized + Debug {
1118    /// Serialize the key into the given buffer.
1119    /// The serialized size is returned.
1120    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError>;
1121    /// Deserialize the key from the given buffer.
1122    /// The key is returned together with the serialized length.
1123    fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError>;
1124    /// Get the length of the key from the buffer.
1125    /// This is an optimized version of [`Self::deserialize_from`] that doesn't have to deserialize everything.
1126    fn get_len(buffer: &[u8]) -> Result<usize, SerializationError> {
1127        Self::deserialize_from(buffer).map(|(_, len)| len)
1128    }
1129}
1130
1131macro_rules! impl_key_num {
1132    ($int:ty) => {
1133        impl Key for $int {
1134            fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1135                let self_bytes = self.to_le_bytes();
1136
1137                match buffer.get_mut(..self_bytes.len()) {
1138                    Some(buffer) => {
1139                        buffer.copy_from_slice(&self_bytes);
1140                        Ok(buffer.len())
1141                    }
1142                    None => Err(SerializationError::BufferTooSmall),
1143                }
1144            }
1145
1146            fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1147                let value = Self::from_le_bytes(
1148                    buffer
1149                        .get(..size_of::<Self>())
1150                        .ok_or(SerializationError::BufferTooSmall)?
1151                        .try_into()
1152                        .unwrap(),
1153                );
1154                Ok((value, size_of::<Self>()))
1155            }
1156
1157            fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
1158                Ok(size_of::<Self>())
1159            }
1160        }
1161    };
1162}
1163
1164impl_key_num!(u8);
1165impl_key_num!(u16);
1166impl_key_num!(u32);
1167impl_key_num!(u64);
1168impl_key_num!(u128);
1169impl_key_num!(i8);
1170impl_key_num!(i16);
1171impl_key_num!(i32);
1172impl_key_num!(i64);
1173impl_key_num!(i128);
1174
1175impl<const N: usize> Key for [u8; N] {
1176    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1177        buffer
1178            .get_mut(..N)
1179            .ok_or(SerializationError::BufferTooSmall)?
1180            .copy_from_slice(self);
1181        Ok(N)
1182    }
1183
1184    fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1185        Ok((
1186            buffer
1187                .get(..N)
1188                .ok_or(SerializationError::BufferTooSmall)?
1189                .try_into()
1190                .unwrap(),
1191            N,
1192        ))
1193    }
1194
1195    fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
1196        Ok(N)
1197    }
1198}
1199
1200impl Key for () {
1201    fn serialize_into(&self, _buffer: &mut [u8]) -> Result<usize, SerializationError> {
1202        Ok(0)
1203    }
1204
1205    fn deserialize_from(_buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1206        Ok(((), 0))
1207    }
1208}
1209
1210/// The trait that defines how map values are serialized and deserialized.
1211///
1212/// It also carries a lifetime so that zero-copy deserialization is supported.
1213/// Zero-copy serialization is not supported due to technical restrictions.
1214pub trait Value<'a> {
1215    /// Serialize the value into the given buffer. If everything went ok, this function returns the length
1216    /// of the used part of the buffer.
1217    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError>;
1218    /// Deserialize the value from the buffer. Because of the added lifetime, the implementation can borrow from the
1219    /// buffer which opens up some zero-copy possibilities.
1220    ///
1221    /// The buffer will be the same length as the serialize function returned for this value. Though note that the length
1222    /// is written from flash, so bitflips can affect that (though the length is separately crc-protected) and the key deserialization might
1223    /// return a wrong length.
1224    ///
1225    /// Returns the decoded value and the amount of bytes used from the buffer.
1226    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1227    where
1228        Self: Sized;
1229}
1230
1231impl<'a> Value<'a> for bool {
1232    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1233        <u8 as Value>::serialize_into(&u8::from(*self), buffer)
1234    }
1235
1236    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1237    where
1238        Self: Sized,
1239    {
1240        let (value, size) = <u8 as Value>::deserialize_from(buffer)?;
1241        Ok((value != 0, size))
1242    }
1243}
1244
1245impl<'a, T: Value<'a>> Value<'a> for Option<T> {
1246    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1247        if let Some(val) = self {
1248            let mut size = 0;
1249            size += <bool as Value>::serialize_into(&true, buffer)?;
1250            size += <T as Value>::serialize_into(
1251                val,
1252                buffer
1253                    .get_mut(size..)
1254                    .ok_or(SerializationError::BufferTooSmall)?,
1255            )?;
1256            Ok(size)
1257        } else {
1258            <bool as Value>::serialize_into(&false, buffer)
1259        }
1260    }
1261
1262    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1263    where
1264        Self: Sized,
1265    {
1266        let (is_some, tag_size) = <bool as Value>::deserialize_from(buffer)?;
1267        if is_some {
1268            let (value, value_size) = <T as Value>::deserialize_from(
1269                buffer
1270                    .get(tag_size..)
1271                    .ok_or(SerializationError::BufferTooSmall)?,
1272            )?;
1273            Ok((Some(value), tag_size + value_size))
1274        } else {
1275            Ok((None, tag_size))
1276        }
1277    }
1278}
1279
1280impl<'a> Value<'a> for &'a [u8] {
1281    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1282        buffer
1283            .get_mut(..self.len())
1284            .ok_or(SerializationError::BufferTooSmall)?
1285            .copy_from_slice(self);
1286        Ok(self.len())
1287    }
1288
1289    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1290    where
1291        Self: Sized,
1292    {
1293        Ok((buffer, buffer.len()))
1294    }
1295}
1296
1297#[cfg(feature = "postcard")]
1298/// Marker trait for types that will be serialized using [postcard].
1299///
1300/// Implement this trait on a type to enable automatically using postcard to serialize and
1301/// deserialize it.
1302///
1303/// [postcard]: https://crates.io/crates/postcard
1304pub trait PostcardValue<'a>: Serialize + Deserialize<'a> {}
1305
1306#[cfg(feature = "postcard")]
1307impl<'a, T> Value<'a> for T
1308where
1309    T: PostcardValue<'a>,
1310{
1311    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1312        Ok(postcard::to_slice(self, buffer).map(|s| s.len())?)
1313    }
1314
1315    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1316    where
1317        Self: Sized,
1318    {
1319        Ok((postcard::from_bytes(buffer)?, buffer.len()))
1320    }
1321}
1322
1323#[cfg(feature = "postcard")]
1324impl From<postcard::Error> for SerializationError {
1325    fn from(error: postcard::Error) -> SerializationError {
1326        use postcard::Error::*;
1327        match error {
1328            SerializeBufferFull => SerializationError::BufferTooSmall,
1329            SerializeSeqLengthUnknown => SerializationError::InvalidData,
1330            DeserializeUnexpectedEnd
1331            | DeserializeBadVarint
1332            | DeserializeBadBool
1333            | DeserializeBadChar
1334            | DeserializeBadUtf8
1335            | DeserializeBadOption
1336            | DeserializeBadEnum
1337            | DeserializeBadEncoding
1338            | DeserializeBadCrc => SerializationError::InvalidFormat,
1339            _ => SerializationError::Custom(error as i32),
1340        }
1341    }
1342}
1343
1344macro_rules! impl_map_item_num {
1345    ($num:ty) => {
1346        impl<'a> Value<'a> for $num {
1347            fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1348                let self_bytes = self.to_le_bytes();
1349
1350                match buffer.get_mut(..self_bytes.len()) {
1351                    Some(buffer) => {
1352                        buffer.copy_from_slice(&self_bytes);
1353                        Ok(buffer.len())
1354                    }
1355                    None => Err(SerializationError::BufferTooSmall),
1356                }
1357            }
1358
1359            fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1360                let value = Self::from_le_bytes(
1361                    buffer
1362                        .get(..size_of::<Self>())
1363                        .ok_or(SerializationError::BufferTooSmall)?
1364                        .try_into()
1365                        .unwrap(),
1366                );
1367                Ok((value, size_of::<Self>()))
1368            }
1369        }
1370
1371        // Also implement `Value` for arrays of numbers.
1372        impl<'a, const N: usize> Value<'a> for [$num; N] {
1373            fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1374                let elem_size = size_of::<$num>();
1375
1376                let buffer = buffer
1377                    .get_mut(0..elem_size * N)
1378                    .ok_or(SerializationError::BufferTooSmall)?;
1379
1380                for (chunk, number) in buffer.chunks_exact_mut(elem_size).zip(self.iter()) {
1381                    chunk.copy_from_slice(&number.to_le_bytes())
1382                }
1383                Ok(elem_size * N)
1384            }
1385
1386            fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1387                let elem_size = size_of::<$num>();
1388                if buffer.len() < elem_size * N {
1389                    return Err(SerializationError::BufferTooSmall);
1390                }
1391
1392                let mut array = [0 as $num; N];
1393                for (chunk, number) in buffer.chunks_exact(elem_size).zip(array.iter_mut()) {
1394                    *number = <$num>::from_le_bytes(chunk.try_into().unwrap());
1395                }
1396                Ok((array, elem_size * N))
1397            }
1398        }
1399    };
1400}
1401
1402impl_map_item_num!(u8);
1403impl_map_item_num!(u16);
1404impl_map_item_num!(u32);
1405impl_map_item_num!(u64);
1406impl_map_item_num!(u128);
1407impl_map_item_num!(i8);
1408impl_map_item_num!(i16);
1409impl_map_item_num!(i32);
1410impl_map_item_num!(i64);
1411impl_map_item_num!(i128);
1412impl_map_item_num!(f32);
1413impl_map_item_num!(f64);
1414
1415/// Error for map value (de)serialization.
1416///
1417/// This error type is predefined (in contrast to using generics) to save many kilobytes of binary size.
1418#[non_exhaustive]
1419#[derive(Debug, PartialEq, Eq, Clone)]
1420#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1421pub enum SerializationError {
1422    /// The provided buffer was too small.
1423    BufferTooSmall,
1424    /// The serialization could not succeed because the data was not in order. (e.g. too big to fit)
1425    InvalidData,
1426    /// The deserialization could not succeed because the bytes are in an invalid format.
1427    InvalidFormat,
1428    /// An implementation defined error that might contain more information than the other predefined
1429    /// error variants.
1430    Custom(i32),
1431}
1432
1433impl core::fmt::Display for SerializationError {
1434    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1435        match self {
1436            SerializationError::BufferTooSmall => write!(f, "Buffer too small"),
1437            SerializationError::InvalidData => write!(f, "Invalid data"),
1438            SerializationError::InvalidFormat => write!(f, "Invalid format"),
1439            SerializationError::Custom(val) => write!(f, "Custom error: {val}"),
1440        }
1441    }
1442}
1443
1444#[cfg(test)]
1445mod tests {
1446    use crate::{AlignedBuf, cache::Cache, mock_flash};
1447
1448    use super::*;
1449    use futures_test::test;
1450
1451    type MockFlashBig = mock_flash::MockFlashBase<4, 4, 256>;
1452    type MockFlashTiny = mock_flash::MockFlashBase<2, 1, 32>;
1453
1454    #[test]
1455    async fn store_and_fetch() {
1456        let mut storage = MapStorage::<u8, _, _>::new(
1457            MockFlashBig::default(),
1458            MapConfig::new(0x000..0x1000),
1459            Cache::new_uncached(),
1460        );
1461
1462        let mut data_buffer = AlignedBuf([0; 128]);
1463
1464        let start_snapshot = storage.flash().stats_snapshot();
1465
1466        let item = storage
1467            .fetch_item::<&[u8]>(&mut data_buffer, &0)
1468            .await
1469            .unwrap();
1470        assert_eq!(item, None);
1471
1472        let item = storage
1473            .fetch_item::<&[u8]>(&mut data_buffer, &60)
1474            .await
1475            .unwrap();
1476        assert_eq!(item, None);
1477
1478        let item = storage
1479            .fetch_item::<&[u8]>(&mut data_buffer, &0xFF)
1480            .await
1481            .unwrap();
1482        assert_eq!(item, None);
1483
1484        storage
1485            .store_item(&mut data_buffer, &0u8, &[5u8])
1486            .await
1487            .unwrap();
1488        storage
1489            .store_item(&mut data_buffer, &0u8, &[5u8, 6])
1490            .await
1491            .unwrap();
1492
1493        let item = storage
1494            .fetch_item::<&[u8]>(&mut data_buffer, &0)
1495            .await
1496            .unwrap()
1497            .unwrap();
1498        assert_eq!(item, &[5, 6]);
1499
1500        storage
1501            .store_item(&mut data_buffer, &1u8, &[2u8, 2, 2, 2, 2, 2])
1502            .await
1503            .unwrap();
1504
1505        let item = storage
1506            .fetch_item::<&[u8]>(&mut data_buffer, &0)
1507            .await
1508            .unwrap()
1509            .unwrap();
1510        assert_eq!(item, &[5, 6]);
1511
1512        let item = storage
1513            .fetch_item::<&[u8]>(&mut data_buffer, &1)
1514            .await
1515            .unwrap()
1516            .unwrap();
1517        assert_eq!(item, &[2, 2, 2, 2, 2, 2]);
1518
1519        for index in 0..4000 {
1520            storage
1521                .store_item(
1522                    &mut data_buffer,
1523                    &((index % 10) as u8),
1524                    &vec![(index % 10) as u8 * 2; index % 10].as_slice(),
1525                )
1526                .await
1527                .unwrap();
1528        }
1529
1530        for i in 0..10 {
1531            let item = storage
1532                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1533                .await
1534                .unwrap()
1535                .unwrap();
1536            assert_eq!(item, &vec![(i % 10) * 2; (i % 10) as usize]);
1537        }
1538
1539        for _ in 0..4000 {
1540            storage
1541                .store_item(&mut data_buffer, &11u8, &[0; 10])
1542                .await
1543                .unwrap();
1544        }
1545
1546        for i in 0..10 {
1547            let item = storage
1548                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1549                .await
1550                .unwrap()
1551                .unwrap();
1552            assert_eq!(item, &vec![(i % 10) * 2; (i % 10) as usize]);
1553        }
1554
1555        println!(
1556            "{:?}",
1557            start_snapshot.compare_to(storage.flash().stats_snapshot()),
1558        );
1559    }
1560
1561    #[test]
1562    async fn store_too_many_items() {
1563        const UPPER_BOUND: u8 = 3;
1564
1565        let mut storage = MapStorage::new(
1566            MockFlashTiny::default(),
1567            const { MapConfig::new(0x00..0x40) },
1568            Cache::new_uncached(),
1569        );
1570        let mut data_buffer = AlignedBuf([0; 128]);
1571
1572        for i in 0..UPPER_BOUND {
1573            println!("Storing {i:?}");
1574
1575            storage
1576                .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1577                .await
1578                .unwrap();
1579        }
1580
1581        assert_eq!(
1582            storage
1583                .store_item(
1584                    &mut data_buffer,
1585                    &UPPER_BOUND,
1586                    &vec![0; UPPER_BOUND as usize].as_slice(),
1587                )
1588                .await,
1589            Err(Error::FullStorage)
1590        );
1591
1592        for i in 0..UPPER_BOUND {
1593            let item = storage
1594                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1595                .await
1596                .unwrap()
1597                .unwrap();
1598
1599            println!("Fetched {item:?}");
1600
1601            assert_eq!(item, vec![i; i as usize]);
1602        }
1603    }
1604
1605    #[test]
1606    async fn store_too_many_items_big() {
1607        const UPPER_BOUND: u8 = 68;
1608
1609        let mut storage = MapStorage::new(
1610            MockFlashBig::default(),
1611            const { MapConfig::new(0x0000..0x1000) },
1612            Cache::new_uncached(),
1613        );
1614        let mut data_buffer = AlignedBuf([0; 128]);
1615
1616        for i in 0..UPPER_BOUND {
1617            println!("Storing {i:?}");
1618
1619            storage
1620                .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1621                .await
1622                .unwrap();
1623        }
1624
1625        assert_eq!(
1626            storage
1627                .store_item(
1628                    &mut data_buffer,
1629                    &UPPER_BOUND,
1630                    &vec![0; UPPER_BOUND as usize].as_slice(),
1631                )
1632                .await,
1633            Err(Error::FullStorage)
1634        );
1635
1636        for i in 0..UPPER_BOUND {
1637            let item = storage
1638                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1639                .await
1640                .unwrap()
1641                .unwrap();
1642
1643            println!("Fetched {item:?}");
1644
1645            assert_eq!(item, vec![i; i as usize]);
1646        }
1647    }
1648
1649    #[test]
1650    async fn store_many_items_big() {
1651        let mut storage = MapStorage::new(
1652            mock_flash::MockFlashBase::<4, 1, 4096>::default(),
1653            const { MapConfig::new(0x0000..0x4000) },
1654            Cache::new_uncached(),
1655        );
1656        let mut data_buffer = AlignedBuf([0; 128]);
1657
1658        const LENGHT_PER_KEY: [usize; 24] = [
1659            11, 13, 6, 13, 13, 10, 2, 3, 5, 36, 1, 65, 4, 6, 1, 15, 10, 7, 3, 15, 9, 3, 4, 5,
1660        ];
1661
1662        for _ in 0..100 {
1663            #[allow(clippy::needless_range_loop)]
1664            for i in 0..24 {
1665                storage
1666                    .store_item(
1667                        &mut data_buffer,
1668                        &(i as u16),
1669                        &vec![i as u8; LENGHT_PER_KEY[i]].as_slice(),
1670                    )
1671                    .await
1672                    .unwrap();
1673            }
1674        }
1675
1676        #[allow(clippy::needless_range_loop)]
1677        for i in 0..24 {
1678            let item = storage
1679                .fetch_item::<&[u8]>(&mut data_buffer, &(i as u16))
1680                .await
1681                .unwrap()
1682                .unwrap();
1683
1684            println!("Fetched {item:?}");
1685
1686            assert_eq!(item, vec![i as u8; LENGHT_PER_KEY[i]]);
1687        }
1688    }
1689
1690    #[test]
1691    async fn remove_items() {
1692        let mut storage = MapStorage::new(
1693            mock_flash::MockFlashBase::<4, 1, 4096>::new(
1694                mock_flash::WriteCountCheck::Twice,
1695                None,
1696                true,
1697            ),
1698            const { MapConfig::new(0x0000..0x4000) },
1699            Cache::new_uncached(),
1700        );
1701        let mut data_buffer = AlignedBuf([0; 128]);
1702
1703        // Add some data to flash
1704        for j in 0..10 {
1705            for i in 0..24 {
1706                storage
1707                    .store_item(
1708                        &mut data_buffer,
1709                        &(i as u8),
1710                        &vec![i as u8; j + 2].as_slice(),
1711                    )
1712                    .await
1713                    .unwrap();
1714            }
1715        }
1716
1717        for j in (0..24).rev() {
1718            // Are all things still in flash that we expect?
1719            for i in 0..=j {
1720                assert!(
1721                    storage
1722                        .fetch_item::<&[u8]>(&mut data_buffer, &i)
1723                        .await
1724                        .unwrap()
1725                        .is_some()
1726                );
1727            }
1728
1729            // Remove the item
1730            storage.remove_item(&mut data_buffer, &j).await.unwrap();
1731
1732            // Are all things still in flash that we expect?
1733            for i in 0..j {
1734                assert!(
1735                    storage
1736                        .fetch_item::<&[u8]>(&mut data_buffer, &i)
1737                        .await
1738                        .unwrap()
1739                        .is_some()
1740                );
1741            }
1742
1743            assert!(
1744                storage
1745                    .fetch_item::<&[u8]>(&mut data_buffer, &j)
1746                    .await
1747                    .unwrap()
1748                    .is_none()
1749            );
1750        }
1751    }
1752
1753    #[test]
1754    async fn remove_all() {
1755        let mut storage = MapStorage::new(
1756            mock_flash::MockFlashBase::<4, 1, 4096>::new(
1757                mock_flash::WriteCountCheck::Twice,
1758                None,
1759                true,
1760            ),
1761            const { MapConfig::new(0x0000..0x4000) },
1762            Cache::new_uncached(),
1763        );
1764        let mut data_buffer = AlignedBuf([0; 128]);
1765
1766        // Add some data to flash
1767        for value in 0..10 {
1768            for key in 0..24u8 {
1769                storage
1770                    .store_item(&mut data_buffer, &key, &vec![key; value + 2].as_slice())
1771                    .await
1772                    .unwrap();
1773            }
1774        }
1775
1776        // Sanity check that we can find all the keys we just added.
1777        for key in 0..24u8 {
1778            assert!(
1779                storage
1780                    .fetch_item::<&[u8]>(&mut data_buffer, &key)
1781                    .await
1782                    .unwrap()
1783                    .is_some()
1784            );
1785        }
1786
1787        // Remove all the items
1788        storage.remove_all_items(&mut data_buffer).await.unwrap();
1789
1790        // Verify that none of the keys are present in flash.
1791        for key in 0..24 {
1792            assert!(
1793                storage
1794                    .fetch_item::<&[u8]>(&mut data_buffer, &key)
1795                    .await
1796                    .unwrap()
1797                    .is_none()
1798            );
1799        }
1800    }
1801
1802    #[test]
1803    async fn store_too_big_item() {
1804        let mut storage = MapStorage::new(
1805            MockFlashBig::new(mock_flash::WriteCountCheck::Twice, None, true),
1806            const { MapConfig::new(0x000..0x1000) },
1807            Cache::new_uncached(),
1808        );
1809
1810        storage
1811            .store_item(&mut [0; 1024], &0u8, &[0u8; 1024 - 4 * 2 - 8 - 1])
1812            .await
1813            .unwrap();
1814
1815        assert_eq!(
1816            storage
1817                .store_item(&mut [0; 1024], &0u8, &[0u8; 1024 - 4 * 2 - 8 - 1 + 1],)
1818                .await,
1819            Err(Error::ItemTooBig)
1820        );
1821    }
1822
1823    #[test]
1824    async fn item_iterator() {
1825        const UPPER_BOUND: u8 = 64;
1826        let mut storage = MapStorage::new(
1827            MockFlashBig::default(),
1828            const { MapConfig::new(0x000..0x1000) },
1829            Cache::new_uncached(),
1830        );
1831
1832        let mut data_buffer = AlignedBuf([0; 128]);
1833
1834        for i in 0..UPPER_BOUND {
1835            storage
1836                .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1837                .await
1838                .unwrap();
1839        }
1840
1841        // Save 10 times for key 1
1842        for i in 0..10 {
1843            storage
1844                .store_item(&mut data_buffer, &1u8, &vec![i; i as usize].as_slice())
1845                .await
1846                .unwrap();
1847        }
1848
1849        let mut map_iter = storage.fetch_all_items(&mut data_buffer).await.unwrap();
1850
1851        let mut count = 0;
1852        let mut last_value_buffer = [0u8; 64];
1853        let mut last_value_length = 0;
1854        while let Ok(Some((key, value))) = map_iter.next::<&[u8]>(&mut data_buffer).await {
1855            if key == 1 {
1856                // This is the key we stored multiple times, record the last value
1857                last_value_length = value.len();
1858                last_value_buffer[..value.len()].copy_from_slice(value);
1859            } else {
1860                assert_eq!(value, vec![key; key as usize]);
1861                count += 1;
1862            }
1863        }
1864
1865        assert_eq!(last_value_length, 9);
1866        assert_eq!(
1867            &last_value_buffer[..last_value_length],
1868            vec![9u8; 9].as_slice()
1869        );
1870
1871        // Check total number of fetched items, +1 since we didn't count key 1
1872        assert_eq!(count + 1, UPPER_BOUND);
1873    }
1874
1875    #[test]
1876    async fn store_unit_key() {
1877        let mut storage = MapStorage::new(
1878            MockFlashBig::default(),
1879            const { MapConfig::new(0x000..0x1000) },
1880            Cache::new_uncached(),
1881        );
1882
1883        let mut data_buffer = AlignedBuf([0; 128]);
1884
1885        let item = storage
1886            .fetch_item::<&[u8]>(&mut data_buffer, &())
1887            .await
1888            .unwrap();
1889        assert_eq!(item, None);
1890
1891        storage
1892            .store_item(&mut data_buffer, &(), &[5u8])
1893            .await
1894            .unwrap();
1895        storage
1896            .store_item(&mut data_buffer, &(), &[5u8, 6])
1897            .await
1898            .unwrap();
1899
1900        let item = storage
1901            .fetch_item::<&[u8]>(&mut data_buffer, &())
1902            .await
1903            .unwrap()
1904            .unwrap();
1905        assert_eq!(item, &[5, 6]);
1906    }
1907
1908    #[test]
1909    async fn option_value() {
1910        let mut buffer = [0; 2];
1911
1912        assert_eq!(Some(42u8).serialize_into(&mut buffer), Ok(2));
1913        assert_eq!(Option::<u8>::deserialize_from(&buffer), Ok((Some(42u8), 2)));
1914        assert_eq!(buffer, [1, 42]);
1915
1916        let mut buffer = [0; 1];
1917
1918        assert_eq!(Option::<u8>::None.serialize_into(&mut buffer), Ok(1));
1919        assert_eq!(Option::<u8>::deserialize_from(&buffer), Ok((None, 1)));
1920        assert_eq!(buffer, [0]);
1921    }
1922
1923    #[test]
1924    async fn array_value() {
1925        let mut buffer = [0; 3];
1926        assert_eq!(Value::serialize_into(&[1u8, 2, 3], &mut buffer), Ok(3));
1927        assert_eq!(buffer, [1, 2, 3]);
1928        assert_eq!(
1929            <[u8; 3] as Value>::deserialize_from(&buffer),
1930            Ok(([1, 2, 3], 3))
1931        );
1932
1933        let mut buffer = [0; 4];
1934        assert_eq!(
1935            Value::serialize_into(&[0x1234u16, 0x5678], &mut buffer),
1936            Ok(4)
1937        );
1938        assert_eq!(buffer, [0x34, 0x12, 0x78, 0x56]);
1939        assert_eq!(
1940            <[u16; 2]>::deserialize_from(&buffer),
1941            Ok(([0x1234, 0x5678], 4))
1942        );
1943    }
1944
1945    #[test]
1946    async fn send_sync() {
1947        fn assert_sync<T: Sync + Send>(_: T) {}
1948
1949        let mut storage = MapStorage::new(
1950            MockFlashBig::default(),
1951            const { MapConfig::new(0x000..0x1000) },
1952            Cache::new_uncached(),
1953        );
1954
1955        let mut buffer = [0; 16];
1956
1957        // The normal store doesn't work because of the value trait object
1958        assert_sync(storage.store_item_generic(&mut buffer, &0u8, &0u8));
1959        // Trait objects can still be used, but it must be with extra bounds
1960        assert_sync(storage.store_item_generic::<dyn Value + Sync>(&mut buffer, &0u8, &0u8));
1961        assert_sync(storage.fetch_item::<u8>(&mut buffer, &0u8));
1962    }
1963
1964    #[cfg(feature = "postcard")]
1965    #[test]
1966    async fn postcard_value() {
1967        #[derive(PartialEq, Debug, serde::Serialize, serde::Deserialize)]
1968        struct Foo(u32);
1969        impl crate::map::PostcardValue<'_> for Foo {}
1970        let mut buffer = [0; 8];
1971        assert_eq!(Value::serialize_into(&Foo(123), &mut buffer), Ok(1));
1972        assert_eq!(
1973            <Foo as Value>::deserialize_from(&buffer[..1]),
1974            Ok((Foo(123), 1))
1975        );
1976    }
1977}