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 = match self
643            .inner
644            .find_first_page(0, PageState::PartialOpen)
645            .await?
646        {
647            Some(last_used_page) => last_used_page,
648            None => {
649                // Oh dear, there's no active partial open page. Seems like some operation was cancelled or didn't make it through.
650                // Instead, we're gonna have to find what should be the partial open page, which is the first open page after the closed pages.
651                // If there's no closed pages, we only have open pages,
652                // so we can fall back to just the 0 index after which the rest of the logic should work fine.
653                self.inner
654                    .find_last_page(0, PageState::Closed)
655                    .await?
656                    .unwrap_or_default()
657            }
658        };
659
660        // Go through all the pages
661        for page_index in self.inner.get_pages(self.inner.next_page(last_used_page)) {
662            if self
663                .inner
664                .get_page_state_cached(page_index)
665                .await?
666                .is_open()
667            {
668                // This page is open, we don't have to check it
669                continue;
670            }
671
672            let page_data_start_address =
673                calculate_page_address::<S>(self.flash_range(), page_index) + S::WORD_SIZE as u32;
674            let page_data_end_address =
675                calculate_page_end_address::<S>(self.flash_range(), page_index)
676                    - S::WORD_SIZE as u32;
677
678            // Go through all items on the page
679            let mut item_headers =
680                ItemHeaderIter::new(page_data_start_address, page_data_end_address);
681
682            while let (Some(item_header), item_address) =
683                item_headers.next(&mut self.inner.flash).await?
684            {
685                let item = item_header
686                    .read_item(
687                        &mut self.inner.flash,
688                        data_buffer,
689                        item_address,
690                        page_data_end_address,
691                    )
692                    .await?;
693
694                match item {
695                    item::MaybeItem::Corrupted(_, _) | item::MaybeItem::Erased(_, _) => continue,
696                    item::MaybeItem::Present(item) => {
697                        let item_match = match search_key {
698                            Some(search_key) => K::deserialize_from(item.data())?.0 == *search_key,
699                            _ => true,
700                        };
701                        // If this item has the same key as the key we're trying to erase, then erase the item.
702                        // But keep going! We need to erase everything.
703                        if item_match {
704                            item.header
705                                .erase_data(
706                                    &mut self.inner.flash,
707                                    self.inner.flash_range.clone(),
708                                    &mut self.inner.cache,
709                                    item_address,
710                                )
711                                .await?;
712                        }
713                    }
714                }
715            }
716        }
717
718        // We're done, we now know the cache is in a good state
719        self.inner.cache.unmark_dirty();
720
721        Ok(())
722    }
723
724    /// Get an iterator that iterates over all non-erased & non-corrupted items in the map.
725    ///
726    /// <div class="warning">
727    /// You should be very careful when using the map item iterator:
728    /// <ul>
729    /// <li>
730    /// Because map doesn't erase the items when you insert a new one with the same key,
731    /// so it's expected that the iterator returns items with the same key multiple times.
732    /// Only the last returned one is the `active` one.
733    /// </li>
734    /// <li>
735    /// The iterator requires ALL items in the storage have the SAME Value type.
736    /// If you have different types of items in your map, the iterator might return incorrect data or error.
737    /// </li>
738    /// </ul>
739    /// </div>
740    ///
741    /// The following is a simple example of how to use the iterator:
742    /// ```rust
743    /// # use sequential_storage::cache::Cache;
744    /// # use sequential_storage::map::{MapConfig, MapStorage};
745    /// # use mock_flash::MockFlashBase;
746    /// # use futures::executor::block_on;
747    /// # use std::collections::HashMap;
748    /// # type Flash = MockFlashBase<10, 1, 4096>;
749    /// # mod mock_flash {
750    /// #   include!("mock_flash.rs");
751    /// # }
752    /// # fn init_flash() -> Flash {
753    /// #     Flash::new(mock_flash::WriteCountCheck::Twice, None, false)
754    /// # }
755    ///
756    /// # block_on(async {
757    /// let mut flash = init_flash();
758    ///
759    /// let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, Cache::new_uncached());
760    /// let mut data_buffer = [0; 128];
761    ///
762    /// // Create the iterator of map items
763    /// let mut iterator = storage.fetch_all_items(
764    ///     &mut data_buffer
765    /// )
766    /// .await
767    /// .unwrap();
768    ///
769    /// let mut all_items = HashMap::new();
770    ///
771    /// // Iterate through all items, suppose the Key and Value types are u8, u32
772    /// while let Some((key, value)) = iterator
773    ///     .next::<u32>(&mut data_buffer)
774    ///     .await
775    ///     .unwrap()
776    /// {
777    ///     // Do something with the item.
778    ///     // Please note that for the same key there might be multiple items returned,
779    ///     // the last one is the current active one.
780    ///     all_items.insert(key, value);
781    /// }
782    /// # })
783    /// ```
784    pub async fn fetch_all_items(
785        &mut self,
786        data_buffer: &mut [u8],
787    ) -> Result<MapItemIter<'_, K, S, C>, Error<S::Error>> {
788        // Get the first page index.
789        // The first page used by the map is the next page of the `PartialOpen` page or the last `Closed` page
790        let first_page = run_with_auto_repair!(
791            function = {
792                match self
793                    .inner
794                    .find_first_page(0, PageState::PartialOpen)
795                    .await?
796                {
797                    Some(last_used_page) => {
798                        // The next page of the `PartialOpen` page is the first page
799                        Ok(self.inner.next_page(last_used_page))
800                    }
801                    None => {
802                        // In the event that all pages are still open or the last used page was just closed, we search for the first open page.
803                        // If the page one before that is closed, then that's the last used page.
804                        if let Some(first_open_page) =
805                            self.inner.find_first_page(0, PageState::Open).await?
806                        {
807                            let previous_page = self.inner.previous_page(first_open_page);
808                            if self
809                                .inner
810                                .get_page_state_cached(previous_page)
811                                .await?
812                                .is_closed()
813                            {
814                                // The previous page is closed, so the first_open_page is what we want
815                                Ok(first_open_page)
816                            } else {
817                                // The page before the open page is not closed, so it must be open.
818                                // This means that all pages are open and that we don't have any items yet.
819                                self.inner.cache.unmark_dirty();
820                                Ok(0)
821                            }
822                        } else {
823                            // There are no open pages, so everything must be closed.
824                            // Something is up and this should never happen.
825                            // To recover, we will just erase all the flash.
826                            Err(Error::Corrupted {
827                                #[cfg(feature = "_test")]
828                                backtrace: std::backtrace::Backtrace::capture(),
829                            })
830                        }
831                    }
832                }
833            },
834            repair = self.try_repair(data_buffer).await?
835        )?;
836
837        let start_address =
838            calculate_page_address::<S>(self.flash_range(), first_page) + S::WORD_SIZE as u32;
839        let end_address =
840            calculate_page_end_address::<S>(self.flash_range(), first_page) - S::WORD_SIZE as u32;
841
842        Ok(MapItemIter {
843            storage: self,
844            first_page,
845            current_page_index: first_page,
846            current_iter: ItemIter::new(start_address, end_address),
847            _key: PhantomData,
848        })
849    }
850
851    async fn migrate_items(
852        &mut self,
853        data_buffer: &mut [u8],
854        source_page: usize,
855        target_page: usize,
856    ) -> Result<(), Error<S::Error>> {
857        // We need to move the data from the next buffer page to the next_page_to_use, but only if that data
858        // doesn't have a newer value somewhere else.
859
860        let mut next_page_write_address =
861            calculate_page_address::<S>(self.flash_range(), target_page) + S::WORD_SIZE as u32;
862
863        let mut it = ItemIter::new(
864            calculate_page_address::<S>(self.flash_range(), source_page) + S::WORD_SIZE as u32,
865            calculate_page_end_address::<S>(self.flash_range(), source_page) - S::WORD_SIZE as u32,
866        );
867        while let Some((item, item_address)) = it.next(&mut self.inner.flash, data_buffer).await? {
868            let (key, _) = K::deserialize_from(item.data())?;
869
870            // We're in a decent state here
871            self.inner.cache.unmark_dirty();
872
873            // Search for the newest item with the key we found
874            let Some((found_item, found_address, _)) =
875                self.fetch_item_with_location(data_buffer, &key).await?
876            else {
877                // We couldn't even find our own item?
878                return Err(Error::Corrupted {
879                    #[cfg(feature = "_test")]
880                    backtrace: std::backtrace::Backtrace::capture(),
881                });
882            };
883
884            let found_item = found_item
885                .reborrow(data_buffer)
886                .ok_or_else(|| Error::LogicBug {
887                    #[cfg(feature = "_test")]
888                    backtrace: std::backtrace::Backtrace::capture(),
889                })?;
890
891            if found_address == item_address {
892                self.inner
893                    .cache
894                    .notice_key_location(&key, next_page_write_address, true);
895                found_item
896                    .write(
897                        &mut self.inner.flash,
898                        self.inner.flash_range.clone(),
899                        &mut self.inner.cache,
900                        next_page_write_address,
901                    )
902                    .await?;
903                next_page_write_address = found_item
904                    .header
905                    .next_item_address::<S>(next_page_write_address);
906            }
907        }
908
909        self.inner.open_page(source_page).await?;
910
911        Ok(())
912    }
913
914    /// Try to repair the state of the flash to hopefull get back everything in working order.
915    /// Care is taken that no data is lost, but this depends on correctly repairing the state and
916    /// so is only best effort.
917    ///
918    /// This function might be called after a different function returned the [`Error::Corrupted`] error.
919    /// There's no guarantee it will work.
920    ///
921    /// If this function or the function call after this crate returns [`Error::Corrupted`], then it's unlikely
922    /// that the state can be recovered. To at least make everything function again at the cost of losing the data,
923    /// erase the flash range.
924    async fn try_repair(&mut self, data_buffer: &mut [u8]) -> Result<(), Error<S::Error>> {
925        self.inner.cache.invalidate_cache_state();
926
927        self.inner.try_general_repair().await?;
928
929        // Let's check if we corrupted in the middle of a migration
930        if let Some(partial_open_page) = self
931            .inner
932            .find_first_page(0, PageState::PartialOpen)
933            .await?
934        {
935            let buffer_page = self.inner.next_page(partial_open_page);
936            if !self
937                .inner
938                .get_page_state_cached(buffer_page)
939                .await?
940                .is_open()
941            {
942                // Yes, the migration got interrupted. Let's redo it.
943                // To do that, we erase the partial open page first because it contains incomplete data.
944                self.inner.open_page(partial_open_page).await?;
945
946                // Then partially close it again
947                self.inner.partial_close_page(partial_open_page).await?;
948
949                self.migrate_items(data_buffer, buffer_page, partial_open_page)
950                    .await?;
951            }
952        }
953
954        Ok(())
955    }
956
957    /// Resets the flash in the entire given flash range.
958    ///
959    /// This is just a thin helper function as it just calls the flash's erase function.
960    pub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>> {
961        self.inner.erase_all()
962    }
963
964    /// Get the minimal overhead size per stored item for the given flash type.
965    ///
966    /// The associated data of each item is additionally padded to a full flash word size, but that's not part of this number.\
967    /// This means the full item length is `returned number + (data length).next_multiple_of(S::WORD_SIZE)`.
968    #[must_use]
969    pub const fn item_overhead_size() -> u32 {
970        GenericStorage::<S, C, K>::item_overhead_size()
971    }
972
973    /// Destroy the instance to get back the flash and the cache.
974    ///
975    /// The cache can be passed to a new storage instance, but only for the same flash region and if nothing has changed in flash.
976    pub fn destroy(self) -> (S, C) {
977        self.inner.destroy()
978    }
979
980    /// Get a reference to the flash. Mutating the memory is at your own risk.
981    pub const fn flash(&mut self) -> &mut S {
982        self.inner.flash()
983    }
984
985    /// Get the flash range being used
986    pub const fn flash_range(&self) -> Range<u32> {
987        self.inner.flash_range()
988    }
989
990    /// Get a reference to the cache
991    #[cfg(any(test, fuzzing))]
992    pub const fn cache(&mut self) -> &mut C {
993        &mut self.inner.cache
994    }
995
996    #[cfg(any(test, feature = "std", fuzzing))]
997    /// Print all items in flash to the returned string
998    ///
999    /// This is meant as a debugging utility. The string format is not stable.
1000    pub fn print_items(&mut self) -> impl Future<Output = String> {
1001        self.inner.print_items()
1002    }
1003
1004    #[cfg(test)]
1005    fn inner_mut(&mut self) -> &mut GenericStorage<S, C, K> {
1006        &mut self.inner
1007    }
1008}
1009
1010/// Iterator which iterates all non-erased & non-corrupted items in the map.
1011///
1012/// The iterator will return the (Key, Value) tuple when calling `next()`.
1013/// If the iterator ends, it will return `Ok(None)`.
1014///
1015/// The following is a simple example of how to use the iterator:
1016/// ```rust
1017/// # use sequential_storage::cache::Cache;
1018/// # use sequential_storage::map::{MapConfig, MapStorage};
1019/// # use mock_flash::MockFlashBase;
1020/// # use futures::executor::block_on;
1021/// # use std::collections::HashMap;
1022/// # type Flash = MockFlashBase<10, 1, 4096>;
1023/// # mod mock_flash {
1024/// #   include!("mock_flash.rs");
1025/// # }
1026/// # fn init_flash() -> Flash {
1027/// #     Flash::new(mock_flash::WriteCountCheck::Twice, None, false)
1028/// # }
1029///
1030/// # block_on(async {
1031/// let mut flash = init_flash();
1032///
1033/// let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, Cache::new_uncached());
1034/// let mut data_buffer = [0; 128];
1035///
1036/// // Create the iterator of map items
1037/// let mut iterator = storage.fetch_all_items(
1038///     &mut data_buffer
1039/// )
1040/// .await
1041/// .unwrap();
1042///
1043/// let mut all_items = HashMap::new();
1044///
1045/// // Iterate through all items, suppose the Key and Value types are u8, u32
1046/// while let Some((key, value)) = iterator
1047///     .next::<u32>(&mut data_buffer)
1048///     .await
1049///     .unwrap()
1050/// {
1051///     // Do something with the item.
1052///     // Please note that for the same key there might be multiple items returned,
1053///     // the last one is the current active one.
1054///     all_items.insert(key, value);
1055/// }
1056/// # })
1057/// ```
1058pub struct MapItemIter<'s, K: Key, S: NorFlash, C: CacheImpl<K>> {
1059    storage: &'s mut MapStorage<K, S, C>,
1060    first_page: usize,
1061    current_page_index: usize,
1062    pub(crate) current_iter: ItemIter,
1063    _key: PhantomData<K>,
1064}
1065
1066impl<K: Key, S: NorFlash, C: CacheImpl<K>> MapItemIter<'_, K, S, C> {
1067    /// Get the next item in the iterator. Be careful that the given `data_buffer` should large enough to contain the serialized key and value.
1068    pub async fn next<'a, V: Value<'a>>(
1069        &mut self,
1070        data_buffer: &'a mut [u8],
1071    ) -> Result<Option<(K, V)>, Error<S::Error>> {
1072        // Find the next item
1073        let item = loop {
1074            if let Some((item, _address)) = self
1075                .current_iter
1076                .next(&mut self.storage.inner.flash, data_buffer)
1077                .await?
1078            {
1079                // We've found the next item, quit the loop
1080                break item;
1081            }
1082
1083            // The current page is done, we need to find the next page
1084            // Find next page which is not open, update `self.current_iter`
1085            loop {
1086                self.current_page_index = self.storage.inner.next_page(self.current_page_index);
1087
1088                // We've looped back to the first page, which means all pages are checked, there's nothing left so we return None
1089                if self.current_page_index == self.first_page {
1090                    return Ok(None);
1091                }
1092
1093                match self
1094                    .storage
1095                    .inner
1096                    .get_page_state_cached(self.current_page_index)
1097                    .await
1098                {
1099                    Ok(PageState::Closed | PageState::PartialOpen) => {
1100                        self.current_iter = ItemIter::new(
1101                            calculate_page_address::<S>(
1102                                self.storage.inner.flash_range.clone(),
1103                                self.current_page_index,
1104                            ) + S::WORD_SIZE as u32,
1105                            calculate_page_end_address::<S>(
1106                                self.storage.inner.flash_range.clone(),
1107                                self.current_page_index,
1108                            ) - S::WORD_SIZE as u32,
1109                        );
1110                        break;
1111                    }
1112                    _ => continue,
1113                }
1114            }
1115        };
1116
1117        let data_len = item.header.length as usize;
1118        let (key, key_len) = K::deserialize_from(item.data())?;
1119        let (value, _value_len) = V::deserialize_from(&data_buffer[..data_len][key_len..])
1120            .map_err(Error::SerializationError)?;
1121
1122        Ok(Some((key, value)))
1123    }
1124}
1125
1126/// Anything implementing this trait can be used as a key in the map functions.
1127///
1128/// It provides a way to serialize and deserialize the key.
1129///
1130/// The `Eq` bound is used because we need to be able to compare keys and the
1131/// `Clone` bound helps us pass the key around.
1132///
1133/// The key cannot have a lifetime like the [Value]
1134pub trait Key: Eq + Clone + Sized + Debug {
1135    /// Serialize the key into the given buffer.
1136    /// The serialized size is returned.
1137    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError>;
1138    /// Deserialize the key from the given buffer.
1139    /// The key is returned together with the serialized length.
1140    fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError>;
1141    /// Get the length of the key from the buffer.
1142    /// This is an optimized version of [`Self::deserialize_from`] that doesn't have to deserialize everything.
1143    fn get_len(buffer: &[u8]) -> Result<usize, SerializationError> {
1144        Self::deserialize_from(buffer).map(|(_, len)| len)
1145    }
1146}
1147
1148macro_rules! impl_key_num {
1149    ($int:ty) => {
1150        impl Key for $int {
1151            fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1152                let self_bytes = self.to_le_bytes();
1153
1154                match buffer.get_mut(..self_bytes.len()) {
1155                    Some(buffer) => {
1156                        buffer.copy_from_slice(&self_bytes);
1157                        Ok(buffer.len())
1158                    }
1159                    None => Err(SerializationError::BufferTooSmall),
1160                }
1161            }
1162
1163            fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1164                let value = Self::from_le_bytes(
1165                    buffer
1166                        .get(..size_of::<Self>())
1167                        .ok_or(SerializationError::BufferTooSmall)?
1168                        .try_into()
1169                        .unwrap(),
1170                );
1171                Ok((value, size_of::<Self>()))
1172            }
1173
1174            fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
1175                Ok(size_of::<Self>())
1176            }
1177        }
1178    };
1179}
1180
1181impl_key_num!(u8);
1182impl_key_num!(u16);
1183impl_key_num!(u32);
1184impl_key_num!(u64);
1185impl_key_num!(u128);
1186impl_key_num!(i8);
1187impl_key_num!(i16);
1188impl_key_num!(i32);
1189impl_key_num!(i64);
1190impl_key_num!(i128);
1191
1192impl<const N: usize> Key for [u8; N] {
1193    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1194        buffer
1195            .get_mut(..N)
1196            .ok_or(SerializationError::BufferTooSmall)?
1197            .copy_from_slice(self);
1198        Ok(N)
1199    }
1200
1201    fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1202        Ok((
1203            buffer
1204                .get(..N)
1205                .ok_or(SerializationError::BufferTooSmall)?
1206                .try_into()
1207                .unwrap(),
1208            N,
1209        ))
1210    }
1211
1212    fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
1213        Ok(N)
1214    }
1215}
1216
1217impl Key for () {
1218    fn serialize_into(&self, _buffer: &mut [u8]) -> Result<usize, SerializationError> {
1219        Ok(0)
1220    }
1221
1222    fn deserialize_from(_buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1223        Ok(((), 0))
1224    }
1225}
1226
1227/// The trait that defines how map values are serialized and deserialized.
1228///
1229/// It also carries a lifetime so that zero-copy deserialization is supported.
1230/// Zero-copy serialization is not supported due to technical restrictions.
1231pub trait Value<'a> {
1232    /// Serialize the value into the given buffer. If everything went ok, this function returns the length
1233    /// of the used part of the buffer.
1234    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError>;
1235    /// Deserialize the value from the buffer. Because of the added lifetime, the implementation can borrow from the
1236    /// buffer which opens up some zero-copy possibilities.
1237    ///
1238    /// The buffer will be the same length as the serialize function returned for this value. Though note that the length
1239    /// is written from flash, so bitflips can affect that (though the length is separately crc-protected) and the key deserialization might
1240    /// return a wrong length.
1241    ///
1242    /// Returns the decoded value and the amount of bytes used from the buffer.
1243    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1244    where
1245        Self: Sized;
1246}
1247
1248impl<'a> Value<'a> for bool {
1249    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1250        <u8 as Value>::serialize_into(&u8::from(*self), buffer)
1251    }
1252
1253    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1254    where
1255        Self: Sized,
1256    {
1257        let (value, size) = <u8 as Value>::deserialize_from(buffer)?;
1258        Ok((value != 0, size))
1259    }
1260}
1261
1262impl<'a, T: Value<'a>> Value<'a> for Option<T> {
1263    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1264        if let Some(val) = self {
1265            let mut size = 0;
1266            size += <bool as Value>::serialize_into(&true, buffer)?;
1267            size += <T as Value>::serialize_into(
1268                val,
1269                buffer
1270                    .get_mut(size..)
1271                    .ok_or(SerializationError::BufferTooSmall)?,
1272            )?;
1273            Ok(size)
1274        } else {
1275            <bool as Value>::serialize_into(&false, buffer)
1276        }
1277    }
1278
1279    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1280    where
1281        Self: Sized,
1282    {
1283        let (is_some, tag_size) = <bool as Value>::deserialize_from(buffer)?;
1284        if is_some {
1285            let (value, value_size) = <T as Value>::deserialize_from(
1286                buffer
1287                    .get(tag_size..)
1288                    .ok_or(SerializationError::BufferTooSmall)?,
1289            )?;
1290            Ok((Some(value), tag_size + value_size))
1291        } else {
1292            Ok((None, tag_size))
1293        }
1294    }
1295}
1296
1297impl<'a> Value<'a> for &'a [u8] {
1298    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1299        buffer
1300            .get_mut(..self.len())
1301            .ok_or(SerializationError::BufferTooSmall)?
1302            .copy_from_slice(self);
1303        Ok(self.len())
1304    }
1305
1306    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1307    where
1308        Self: Sized,
1309    {
1310        Ok((buffer, buffer.len()))
1311    }
1312}
1313
1314#[cfg(feature = "postcard")]
1315/// Marker trait for types that will be serialized using [postcard].
1316///
1317/// Implement this trait on a type to enable automatically using postcard to serialize and
1318/// deserialize it.
1319///
1320/// [postcard]: https://crates.io/crates/postcard
1321pub trait PostcardValue<'a>: Serialize + Deserialize<'a> {}
1322
1323#[cfg(feature = "postcard")]
1324impl<'a, T> Value<'a> for T
1325where
1326    T: PostcardValue<'a>,
1327{
1328    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1329        Ok(postcard::to_slice(self, buffer).map(|s| s.len())?)
1330    }
1331
1332    fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1333    where
1334        Self: Sized,
1335    {
1336        Ok((postcard::from_bytes(buffer)?, buffer.len()))
1337    }
1338}
1339
1340#[cfg(feature = "postcard")]
1341impl From<postcard::Error> for SerializationError {
1342    fn from(error: postcard::Error) -> SerializationError {
1343        use postcard::Error::*;
1344        match error {
1345            SerializeBufferFull => SerializationError::BufferTooSmall,
1346            SerializeSeqLengthUnknown => SerializationError::InvalidData,
1347            DeserializeUnexpectedEnd
1348            | DeserializeBadVarint
1349            | DeserializeBadBool
1350            | DeserializeBadChar
1351            | DeserializeBadUtf8
1352            | DeserializeBadOption
1353            | DeserializeBadEnum
1354            | DeserializeBadEncoding
1355            | DeserializeBadCrc => SerializationError::InvalidFormat,
1356            _ => SerializationError::Custom(error as i32),
1357        }
1358    }
1359}
1360
1361macro_rules! impl_map_item_num {
1362    ($num:ty) => {
1363        impl<'a> Value<'a> for $num {
1364            fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1365                let self_bytes = self.to_le_bytes();
1366
1367                match buffer.get_mut(..self_bytes.len()) {
1368                    Some(buffer) => {
1369                        buffer.copy_from_slice(&self_bytes);
1370                        Ok(buffer.len())
1371                    }
1372                    None => Err(SerializationError::BufferTooSmall),
1373                }
1374            }
1375
1376            fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1377                let value = Self::from_le_bytes(
1378                    buffer
1379                        .get(..size_of::<Self>())
1380                        .ok_or(SerializationError::BufferTooSmall)?
1381                        .try_into()
1382                        .unwrap(),
1383                );
1384                Ok((value, size_of::<Self>()))
1385            }
1386        }
1387
1388        // Also implement `Value` for arrays of numbers.
1389        impl<'a, const N: usize> Value<'a> for [$num; N] {
1390            fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1391                let elem_size = size_of::<$num>();
1392
1393                let buffer = buffer
1394                    .get_mut(0..elem_size * N)
1395                    .ok_or(SerializationError::BufferTooSmall)?;
1396
1397                for (chunk, number) in buffer.chunks_exact_mut(elem_size).zip(self.iter()) {
1398                    chunk.copy_from_slice(&number.to_le_bytes())
1399                }
1400                Ok(elem_size * N)
1401            }
1402
1403            fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1404                let elem_size = size_of::<$num>();
1405                if buffer.len() < elem_size * N {
1406                    return Err(SerializationError::BufferTooSmall);
1407                }
1408
1409                let mut array = [0 as $num; N];
1410                for (chunk, number) in buffer.chunks_exact(elem_size).zip(array.iter_mut()) {
1411                    *number = <$num>::from_le_bytes(chunk.try_into().unwrap());
1412                }
1413                Ok((array, elem_size * N))
1414            }
1415        }
1416    };
1417}
1418
1419impl_map_item_num!(u8);
1420impl_map_item_num!(u16);
1421impl_map_item_num!(u32);
1422impl_map_item_num!(u64);
1423impl_map_item_num!(u128);
1424impl_map_item_num!(i8);
1425impl_map_item_num!(i16);
1426impl_map_item_num!(i32);
1427impl_map_item_num!(i64);
1428impl_map_item_num!(i128);
1429impl_map_item_num!(f32);
1430impl_map_item_num!(f64);
1431
1432/// Error for map value (de)serialization.
1433///
1434/// This error type is predefined (in contrast to using generics) to save many kilobytes of binary size.
1435#[non_exhaustive]
1436#[derive(Debug, PartialEq, Eq, Clone)]
1437#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1438pub enum SerializationError {
1439    /// The provided buffer was too small.
1440    BufferTooSmall,
1441    /// The serialization could not succeed because the data was not in order. (e.g. too big to fit)
1442    InvalidData,
1443    /// The deserialization could not succeed because the bytes are in an invalid format.
1444    InvalidFormat,
1445    /// An implementation defined error that might contain more information than the other predefined
1446    /// error variants.
1447    Custom(i32),
1448}
1449
1450impl core::fmt::Display for SerializationError {
1451    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1452        match self {
1453            SerializationError::BufferTooSmall => write!(f, "Buffer too small"),
1454            SerializationError::InvalidData => write!(f, "Invalid data"),
1455            SerializationError::InvalidFormat => write!(f, "Invalid format"),
1456            SerializationError::Custom(val) => write!(f, "Custom error: {val}"),
1457        }
1458    }
1459}
1460
1461#[cfg(test)]
1462mod tests {
1463    use crate::{AlignedBuf, cache::Cache, mock_flash};
1464
1465    use super::*;
1466    use futures_test::test;
1467
1468    type MockFlashBig = mock_flash::MockFlashBase<4, 4, 256>;
1469    type MockFlashTiny = mock_flash::MockFlashBase<2, 1, 32>;
1470
1471    #[test]
1472    async fn store_and_fetch() {
1473        let mut storage = MapStorage::<u8, _, _>::new(
1474            MockFlashBig::default(),
1475            MapConfig::new(0x000..0x1000),
1476            Cache::new_uncached(),
1477        );
1478
1479        let mut data_buffer = AlignedBuf([0; 128]);
1480
1481        let start_snapshot = storage.flash().stats_snapshot();
1482
1483        let item = storage
1484            .fetch_item::<&[u8]>(&mut data_buffer, &0)
1485            .await
1486            .unwrap();
1487        assert_eq!(item, None);
1488
1489        let item = storage
1490            .fetch_item::<&[u8]>(&mut data_buffer, &60)
1491            .await
1492            .unwrap();
1493        assert_eq!(item, None);
1494
1495        let item = storage
1496            .fetch_item::<&[u8]>(&mut data_buffer, &0xFF)
1497            .await
1498            .unwrap();
1499        assert_eq!(item, None);
1500
1501        storage
1502            .store_item(&mut data_buffer, &0u8, &[5u8])
1503            .await
1504            .unwrap();
1505        storage
1506            .store_item(&mut data_buffer, &0u8, &[5u8, 6])
1507            .await
1508            .unwrap();
1509
1510        let item = storage
1511            .fetch_item::<&[u8]>(&mut data_buffer, &0)
1512            .await
1513            .unwrap()
1514            .unwrap();
1515        assert_eq!(item, &[5, 6]);
1516
1517        storage
1518            .store_item(&mut data_buffer, &1u8, &[2u8, 2, 2, 2, 2, 2])
1519            .await
1520            .unwrap();
1521
1522        let item = storage
1523            .fetch_item::<&[u8]>(&mut data_buffer, &0)
1524            .await
1525            .unwrap()
1526            .unwrap();
1527        assert_eq!(item, &[5, 6]);
1528
1529        let item = storage
1530            .fetch_item::<&[u8]>(&mut data_buffer, &1)
1531            .await
1532            .unwrap()
1533            .unwrap();
1534        assert_eq!(item, &[2, 2, 2, 2, 2, 2]);
1535
1536        for index in 0..4000 {
1537            storage
1538                .store_item(
1539                    &mut data_buffer,
1540                    &((index % 10) as u8),
1541                    &vec![(index % 10) as u8 * 2; index % 10].as_slice(),
1542                )
1543                .await
1544                .unwrap();
1545        }
1546
1547        for i in 0..10 {
1548            let item = storage
1549                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1550                .await
1551                .unwrap()
1552                .unwrap();
1553            assert_eq!(item, &vec![(i % 10) * 2; (i % 10) as usize]);
1554        }
1555
1556        for _ in 0..4000 {
1557            storage
1558                .store_item(&mut data_buffer, &11u8, &[0; 10])
1559                .await
1560                .unwrap();
1561        }
1562
1563        for i in 0..10 {
1564            let item = storage
1565                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1566                .await
1567                .unwrap()
1568                .unwrap();
1569            assert_eq!(item, &vec![(i % 10) * 2; (i % 10) as usize]);
1570        }
1571
1572        println!(
1573            "{:?}",
1574            start_snapshot.compare_to(storage.flash().stats_snapshot()),
1575        );
1576    }
1577
1578    #[test]
1579    async fn store_too_many_items() {
1580        const UPPER_BOUND: u8 = 3;
1581
1582        let mut storage = MapStorage::new(
1583            MockFlashTiny::default(),
1584            const { MapConfig::new(0x00..0x40) },
1585            Cache::new_uncached(),
1586        );
1587        let mut data_buffer = AlignedBuf([0; 128]);
1588
1589        for i in 0..UPPER_BOUND {
1590            println!("Storing {i:?}");
1591
1592            storage
1593                .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1594                .await
1595                .unwrap();
1596        }
1597
1598        assert_eq!(
1599            storage
1600                .store_item(
1601                    &mut data_buffer,
1602                    &UPPER_BOUND,
1603                    &vec![0; UPPER_BOUND as usize].as_slice(),
1604                )
1605                .await,
1606            Err(Error::FullStorage)
1607        );
1608
1609        for i in 0..UPPER_BOUND {
1610            let item = storage
1611                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1612                .await
1613                .unwrap()
1614                .unwrap();
1615
1616            println!("Fetched {item:?}");
1617
1618            assert_eq!(item, vec![i; i as usize]);
1619        }
1620    }
1621
1622    #[test]
1623    async fn store_too_many_items_big() {
1624        const UPPER_BOUND: u8 = 68;
1625
1626        let mut storage = MapStorage::new(
1627            MockFlashBig::default(),
1628            const { MapConfig::new(0x0000..0x1000) },
1629            Cache::new_uncached(),
1630        );
1631        let mut data_buffer = AlignedBuf([0; 128]);
1632
1633        for i in 0..UPPER_BOUND {
1634            println!("Storing {i:?}");
1635
1636            storage
1637                .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1638                .await
1639                .unwrap();
1640        }
1641
1642        assert_eq!(
1643            storage
1644                .store_item(
1645                    &mut data_buffer,
1646                    &UPPER_BOUND,
1647                    &vec![0; UPPER_BOUND as usize].as_slice(),
1648                )
1649                .await,
1650            Err(Error::FullStorage)
1651        );
1652
1653        for i in 0..UPPER_BOUND {
1654            let item = storage
1655                .fetch_item::<&[u8]>(&mut data_buffer, &i)
1656                .await
1657                .unwrap()
1658                .unwrap();
1659
1660            println!("Fetched {item:?}");
1661
1662            assert_eq!(item, vec![i; i as usize]);
1663        }
1664    }
1665
1666    #[test]
1667    async fn store_many_items_big() {
1668        let mut storage = MapStorage::new(
1669            mock_flash::MockFlashBase::<4, 1, 4096>::default(),
1670            const { MapConfig::new(0x0000..0x4000) },
1671            Cache::new_uncached(),
1672        );
1673        let mut data_buffer = AlignedBuf([0; 128]);
1674
1675        const LENGHT_PER_KEY: [usize; 24] = [
1676            11, 13, 6, 13, 13, 10, 2, 3, 5, 36, 1, 65, 4, 6, 1, 15, 10, 7, 3, 15, 9, 3, 4, 5,
1677        ];
1678
1679        for _ in 0..100 {
1680            #[allow(clippy::needless_range_loop)]
1681            for i in 0..24 {
1682                storage
1683                    .store_item(
1684                        &mut data_buffer,
1685                        &(i as u16),
1686                        &vec![i as u8; LENGHT_PER_KEY[i]].as_slice(),
1687                    )
1688                    .await
1689                    .unwrap();
1690            }
1691        }
1692
1693        #[allow(clippy::needless_range_loop)]
1694        for i in 0..24 {
1695            let item = storage
1696                .fetch_item::<&[u8]>(&mut data_buffer, &(i as u16))
1697                .await
1698                .unwrap()
1699                .unwrap();
1700
1701            println!("Fetched {item:?}");
1702
1703            assert_eq!(item, vec![i as u8; LENGHT_PER_KEY[i]]);
1704        }
1705    }
1706
1707    #[test]
1708    async fn remove_items() {
1709        let mut storage = MapStorage::new(
1710            mock_flash::MockFlashBase::<4, 1, 4096>::new(
1711                mock_flash::WriteCountCheck::Twice,
1712                None,
1713                true,
1714            ),
1715            const { MapConfig::new(0x0000..0x4000) },
1716            Cache::new_uncached(),
1717        );
1718        let mut data_buffer = AlignedBuf([0; 128]);
1719
1720        // Add some data to flash
1721        for j in 0..10 {
1722            for i in 0..24 {
1723                storage
1724                    .store_item(
1725                        &mut data_buffer,
1726                        &(i as u8),
1727                        &vec![i as u8; j + 2].as_slice(),
1728                    )
1729                    .await
1730                    .unwrap();
1731            }
1732        }
1733
1734        for j in (0..24).rev() {
1735            // Are all things still in flash that we expect?
1736            for i in 0..=j {
1737                assert!(
1738                    storage
1739                        .fetch_item::<&[u8]>(&mut data_buffer, &i)
1740                        .await
1741                        .unwrap()
1742                        .is_some()
1743                );
1744            }
1745
1746            // Remove the item
1747            storage.remove_item(&mut data_buffer, &j).await.unwrap();
1748
1749            // Are all things still in flash that we expect?
1750            for i in 0..j {
1751                assert!(
1752                    storage
1753                        .fetch_item::<&[u8]>(&mut data_buffer, &i)
1754                        .await
1755                        .unwrap()
1756                        .is_some()
1757                );
1758            }
1759
1760            assert!(
1761                storage
1762                    .fetch_item::<&[u8]>(&mut data_buffer, &j)
1763                    .await
1764                    .unwrap()
1765                    .is_none()
1766            );
1767        }
1768    }
1769
1770    #[test]
1771    async fn remove_all() {
1772        let mut storage = MapStorage::new(
1773            mock_flash::MockFlashBase::<4, 1, 4096>::new(
1774                mock_flash::WriteCountCheck::Twice,
1775                None,
1776                true,
1777            ),
1778            const { MapConfig::new(0x0000..0x4000) },
1779            Cache::new_uncached(),
1780        );
1781        let mut data_buffer = AlignedBuf([0; 128]);
1782
1783        // Add some data to flash
1784        for value in 0..10 {
1785            for key in 0..24u8 {
1786                storage
1787                    .store_item(&mut data_buffer, &key, &vec![key; value + 2].as_slice())
1788                    .await
1789                    .unwrap();
1790            }
1791        }
1792
1793        // Sanity check that we can find all the keys we just added.
1794        for key in 0..24u8 {
1795            assert!(
1796                storage
1797                    .fetch_item::<&[u8]>(&mut data_buffer, &key)
1798                    .await
1799                    .unwrap()
1800                    .is_some()
1801            );
1802        }
1803
1804        // Remove all the items
1805        storage.remove_all_items(&mut data_buffer).await.unwrap();
1806
1807        // Verify that none of the keys are present in flash.
1808        for key in 0..24 {
1809            assert!(
1810                storage
1811                    .fetch_item::<&[u8]>(&mut data_buffer, &key)
1812                    .await
1813                    .unwrap()
1814                    .is_none()
1815            );
1816        }
1817    }
1818
1819    #[test]
1820    async fn store_too_big_item() {
1821        let mut storage = MapStorage::new(
1822            MockFlashBig::new(mock_flash::WriteCountCheck::Twice, None, true),
1823            const { MapConfig::new(0x000..0x1000) },
1824            Cache::new_uncached(),
1825        );
1826
1827        storage
1828            .store_item(&mut [0; 1024], &0u8, &[0u8; 1024 - 4 * 2 - 8 - 1])
1829            .await
1830            .unwrap();
1831
1832        assert_eq!(
1833            storage
1834                .store_item(&mut [0; 1024], &0u8, &[0u8; 1024 - 4 * 2 - 8 - 1 + 1],)
1835                .await,
1836            Err(Error::ItemTooBig)
1837        );
1838    }
1839
1840    #[test]
1841    async fn item_iterator() {
1842        const UPPER_BOUND: u8 = 64;
1843        let mut storage = MapStorage::new(
1844            MockFlashBig::default(),
1845            const { MapConfig::new(0x000..0x1000) },
1846            Cache::new_uncached(),
1847        );
1848
1849        let mut data_buffer = AlignedBuf([0; 128]);
1850
1851        for i in 0..UPPER_BOUND {
1852            storage
1853                .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1854                .await
1855                .unwrap();
1856        }
1857
1858        // Save 10 times for key 1
1859        for i in 0..10 {
1860            storage
1861                .store_item(&mut data_buffer, &1u8, &vec![i; i as usize].as_slice())
1862                .await
1863                .unwrap();
1864        }
1865
1866        let mut map_iter = storage.fetch_all_items(&mut data_buffer).await.unwrap();
1867
1868        let mut count = 0;
1869        let mut last_value_buffer = [0u8; 64];
1870        let mut last_value_length = 0;
1871        while let Ok(Some((key, value))) = map_iter.next::<&[u8]>(&mut data_buffer).await {
1872            if key == 1 {
1873                // This is the key we stored multiple times, record the last value
1874                last_value_length = value.len();
1875                last_value_buffer[..value.len()].copy_from_slice(value);
1876            } else {
1877                assert_eq!(value, vec![key; key as usize]);
1878                count += 1;
1879            }
1880        }
1881
1882        assert_eq!(last_value_length, 9);
1883        assert_eq!(
1884            &last_value_buffer[..last_value_length],
1885            vec![9u8; 9].as_slice()
1886        );
1887
1888        // Check total number of fetched items, +1 since we didn't count key 1
1889        assert_eq!(count + 1, UPPER_BOUND);
1890    }
1891
1892    #[test]
1893    async fn issue_132() {
1894        // https://github.com/tweedegolf/sequential-storage/issues/132
1895
1896        // Get the storage in a state where we have a closed page and then an open page.
1897        // This can only happen with a cancelled future/shutoff at the exact right moment.
1898        let mut storage = MapStorage::new(
1899            MockFlashBig::new(mock_flash::WriteCountCheck::Disabled, Some(9168), false),
1900            const { MapConfig::new(0x000..0x1000) },
1901            Cache::new_uncached(),
1902        );
1903        let mut buf = [0; 32];
1904        for i in 0..=378u64 {
1905            let _ = storage.store_item(&mut buf, &(), &i).await;
1906        }
1907
1908        println!("{}", storage.print_items().await);
1909
1910        // Check we're in the state we want to reproduce the error
1911        assert_eq!(
1912            storage.inner_mut().get_page_state(0).await.unwrap(),
1913            PageState::Closed
1914        );
1915        assert_eq!(
1916            storage.inner_mut().get_page_state(1).await.unwrap(),
1917            PageState::Closed
1918        );
1919        assert_eq!(
1920            storage.inner_mut().get_page_state(2).await.unwrap(),
1921            PageState::Open
1922        );
1923        assert_eq!(
1924            storage.inner_mut().get_page_state(3).await.unwrap(),
1925            PageState::Closed
1926        );
1927
1928        // The last store would've failed, so we read the previous value
1929        assert_eq!(
1930            storage.fetch_item::<u64>(&mut buf, &()).await.unwrap(),
1931            Some(377)
1932        );
1933
1934        // Now we remove an item. It should start by removing the oldest items.
1935        // The bug is that with no partial open page, it will start with page 0, which is the page containing the newest items.
1936        // If the remove task is also interrupted, we will then read back an old value.
1937
1938        storage.flash().bytes_until_shutoff = Some(1000);
1939
1940        std::assert_matches!(
1941            storage.remove_item(&mut buf, &()).await,
1942            Err(Error::Storage {
1943                value: mock_flash::MockFlashError::EarlyShutoff(_, mock_flash::Operation::Write)
1944            })
1945        );
1946
1947        println!("{}", storage.print_items().await);
1948
1949        // If the bug is fixed, the fetch should return either the most recent value or None
1950        std::assert_matches!(
1951            storage.fetch_item::<u64>(&mut buf, &()).await.unwrap(),
1952            Some(377) | None
1953        );
1954    }
1955
1956    #[test]
1957    async fn store_unit_key() {
1958        let mut storage = MapStorage::new(
1959            MockFlashBig::default(),
1960            const { MapConfig::new(0x000..0x1000) },
1961            Cache::new_uncached(),
1962        );
1963
1964        let mut data_buffer = AlignedBuf([0; 128]);
1965
1966        let item = storage
1967            .fetch_item::<&[u8]>(&mut data_buffer, &())
1968            .await
1969            .unwrap();
1970        assert_eq!(item, None);
1971
1972        storage
1973            .store_item(&mut data_buffer, &(), &[5u8])
1974            .await
1975            .unwrap();
1976        storage
1977            .store_item(&mut data_buffer, &(), &[5u8, 6])
1978            .await
1979            .unwrap();
1980
1981        let item = storage
1982            .fetch_item::<&[u8]>(&mut data_buffer, &())
1983            .await
1984            .unwrap()
1985            .unwrap();
1986        assert_eq!(item, &[5, 6]);
1987    }
1988
1989    #[test]
1990    async fn option_value() {
1991        let mut buffer = [0; 2];
1992
1993        assert_eq!(Some(42u8).serialize_into(&mut buffer), Ok(2));
1994        assert_eq!(Option::<u8>::deserialize_from(&buffer), Ok((Some(42u8), 2)));
1995        assert_eq!(buffer, [1, 42]);
1996
1997        let mut buffer = [0; 1];
1998
1999        assert_eq!(Option::<u8>::None.serialize_into(&mut buffer), Ok(1));
2000        assert_eq!(Option::<u8>::deserialize_from(&buffer), Ok((None, 1)));
2001        assert_eq!(buffer, [0]);
2002    }
2003
2004    #[test]
2005    async fn array_value() {
2006        let mut buffer = [0; 3];
2007        assert_eq!(Value::serialize_into(&[1u8, 2, 3], &mut buffer), Ok(3));
2008        assert_eq!(buffer, [1, 2, 3]);
2009        assert_eq!(
2010            <[u8; 3] as Value>::deserialize_from(&buffer),
2011            Ok(([1, 2, 3], 3))
2012        );
2013
2014        let mut buffer = [0; 4];
2015        assert_eq!(
2016            Value::serialize_into(&[0x1234u16, 0x5678], &mut buffer),
2017            Ok(4)
2018        );
2019        assert_eq!(buffer, [0x34, 0x12, 0x78, 0x56]);
2020        assert_eq!(
2021            <[u16; 2]>::deserialize_from(&buffer),
2022            Ok(([0x1234, 0x5678], 4))
2023        );
2024    }
2025
2026    #[test]
2027    async fn send_sync() {
2028        fn assert_sync<T: Sync + Send>(_: T) {}
2029
2030        let mut storage = MapStorage::new(
2031            MockFlashBig::default(),
2032            const { MapConfig::new(0x000..0x1000) },
2033            Cache::new_uncached(),
2034        );
2035
2036        let mut buffer = [0; 16];
2037
2038        // The normal store doesn't work because of the value trait object
2039        assert_sync(storage.store_item_generic(&mut buffer, &0u8, &0u8));
2040        // Trait objects can still be used, but it must be with extra bounds
2041        assert_sync(storage.store_item_generic::<dyn Value + Sync>(&mut buffer, &0u8, &0u8));
2042        assert_sync(storage.fetch_item::<u8>(&mut buffer, &0u8));
2043    }
2044
2045    #[cfg(feature = "postcard")]
2046    #[test]
2047    async fn postcard_value() {
2048        #[derive(PartialEq, Debug, serde::Serialize, serde::Deserialize)]
2049        struct Foo(u32);
2050        impl crate::map::PostcardValue<'_> for Foo {}
2051        let mut buffer = [0; 8];
2052        assert_eq!(Value::serialize_into(&Foo(123), &mut buffer), Ok(1));
2053        assert_eq!(
2054            <Foo as Value>::deserialize_from(&buffer[..1]),
2055            Ok((Foo(123), 1))
2056        );
2057    }
2058}