Skip to main content

sequential_storage/queue/
mod.rs

1//! Implementation of the queue logic.
2
3pub mod buffered;
4
5use crate::item::{Item, ItemHeader, ItemHeaderIter};
6
7use self::{cache::CacheImpl, item::ItemUnborrowed};
8
9use super::{
10    Debug, Deref, DerefMut, Error, GenericStorage, MAX_WORD_SIZE, NorFlash, NorFlashExt, PageState,
11    PhantomData, Range, cache, calculate_page_address, calculate_page_end_address,
12    calculate_page_index, calculate_page_size, item, run_with_auto_repair,
13};
14use embedded_storage_async::nor_flash::MultiwriteNorFlash;
15
16/// Configuration for a queue
17pub struct QueueConfig<S> {
18    flash_range: Range<u32>,
19    _phantom: PhantomData<S>,
20}
21
22impl<S: NorFlash> QueueConfig<S> {
23    /// Create a new queue configuration. Will panic if the data is invalid.
24    /// If you want a fallible version, use [`Self::try_new`].
25    #[must_use]
26    pub const fn new(flash_range: Range<u32>) -> Self {
27        match Self::try_new(flash_range) {
28            Ok(config) => config,
29            Err(_) => panic!("Queue config must be correct"),
30        }
31    }
32
33    /// Create a new queue configuration. Will return None if the data is invalid
34    pub const fn try_new(flash_range: Range<u32>) -> Result<Self, QueueConfigError> {
35        if !flash_range.start.is_multiple_of(S::ERASE_SIZE as u32) {
36            return Err(QueueConfigError::StartRangeNotAtPageBoundary);
37        }
38        if !flash_range.end.is_multiple_of(S::ERASE_SIZE as u32) {
39            return Err(QueueConfigError::EndRangeNotAtPageBoundary);
40        }
41        // At least 1 page is used
42        if flash_range.end - flash_range.start < (S::ERASE_SIZE as u32) {
43            return Err(QueueConfigError::RangeTooSmall);
44        }
45
46        // A page must be able to store the 2 page states and at least one item header and a word for item data
47        if S::ERASE_SIZE < S::WORD_SIZE * 3 + ItemHeader::data_address::<S>(0) as usize {
48            return Err(QueueConfigError::PagesTooSmall);
49        }
50        if S::WORD_SIZE > MAX_WORD_SIZE {
51            return Err(QueueConfigError::WordSizeTooLarge);
52        }
53
54        Ok(Self {
55            flash_range,
56            _phantom: PhantomData,
57        })
58    }
59}
60
61/// Error for [`QueueConfig`] constructor
62#[derive(Debug, Clone, PartialEq, Eq)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub enum QueueConfigError {
65    /// The start range address is not a multiple of the erase size
66    StartRangeNotAtPageBoundary,
67    /// The end range address is not a multiple of the erase size
68    EndRangeNotAtPageBoundary,
69    /// The queue needs at least 1 page to operate, but got less
70    RangeTooSmall,
71    /// The pages of the flash are too small to work with
72    PagesTooSmall,
73    /// The word size of the flash is bigger than [`MAX_WORD_SIZE`]
74    WordSizeTooLarge,
75}
76
77/// A fifo queue storage
78///
79/// Use [`Self::push`] to add data to the fifo and use [`Self::peek`] and [`Self::pop`] to get the data back.
80///
81/// ## Basic API
82///
83/// ```rust
84/// # use sequential_storage::cache::Cache;
85/// # use sequential_storage::queue::{QueueConfig, QueueStorage};
86/// # use mock_flash::MockFlashBase;
87/// # use futures::executor::block_on;
88/// # type Flash = MockFlashBase<10, 1, 4096>;
89/// # mod mock_flash {
90/// #   include!("../mock_flash.rs");
91/// # }
92/// #
93/// # fn init_flash() -> Flash {
94/// #     Flash::new(mock_flash::WriteCountCheck::Twice, None, false)
95/// # }
96/// #
97/// # block_on(async {
98///
99/// // Initialize the flash. This can be internal or external
100/// let mut flash = init_flash();
101///
102/// let mut storage = QueueStorage::new(flash, const { QueueConfig::new(0x1000..0x3000) }, Cache::new_uncached());
103/// // We need to give the crate a buffer to work with.
104/// // It must be big enough to serialize the biggest value of your storage type in.
105/// let mut data_buffer = [0; 128];
106///
107/// let my_data = [10, 47, 29];
108///
109/// // We can push some data to the queue
110/// storage.push(&my_data, false).await.unwrap();
111///
112/// // We can peek at the oldest data
113///
114/// assert_eq!(
115///     &storage.peek(&mut data_buffer).await.unwrap().unwrap()[..],
116///     &my_data[..]
117/// );
118///
119/// // With popping we get back the oldest data, but that data is now also removed
120///
121/// assert_eq!(
122///     &storage.pop(&mut data_buffer).await.unwrap().unwrap()[..],
123///     &my_data[..]
124/// );
125///
126/// // If we pop again, we find there's no data anymore
127///
128/// assert_eq!(
129///     storage.pop(&mut data_buffer).await,
130///     Ok(None)
131/// );
132/// # });
133/// ```
134pub struct QueueStorage<S: NorFlash, C: CacheImpl<()>> {
135    inner: GenericStorage<S, C, ()>,
136}
137
138impl<S: NorFlash, C: CacheImpl<()>> QueueStorage<S, C> {
139    /// Create a new (fifo) queue instance
140    ///
141    /// The provided cache instance must be new or must be in the exact correct state for the current flash contents.
142    /// If the cache is bad, undesirable things will happen.
143    /// So, it's ok to reuse the cache gotten from the [`Self::destroy`] method when the flash hasn't changed since calling destroy.
144    pub const fn new(storage: S, config: QueueConfig<S>, cache: C) -> Self {
145        Self {
146            inner: GenericStorage {
147                flash: storage,
148                flash_range: config.flash_range,
149                cache,
150                _phantom: PhantomData,
151            },
152        }
153    }
154
155    /// Push data into the queue.
156    /// The data can only be taken out with the [`Self::pop`] function.
157    ///
158    /// Old data will not be overwritten unless `allow_overwrite_old_data` is true.
159    /// If it is, then if the queue is full, the oldest data is removed to make space for the new data.
160    ///
161    /// *Note: If a page is already used and you push more data than the remaining capacity of the page,
162    /// the entire remaining capacity will go unused because the data is stored on the next page.*
163    pub async fn push(
164        &mut self,
165        data: &[u8],
166        allow_overwrite_old_data: bool,
167    ) -> Result<(), Error<S::Error>> {
168        run_with_auto_repair!(
169            function = self.push_inner(data, allow_overwrite_old_data).await,
170            repair = self.try_repair().await?
171        )
172    }
173
174    async fn push_inner(
175        &mut self,
176        data: &[u8],
177        allow_overwrite_old_data: bool,
178    ) -> Result<(), Error<S::Error>> {
179        if self.inner.cache.is_dirty() {
180            self.inner.cache.invalidate_cache_state();
181        }
182
183        // Data must fit in a single page
184        if data.len() > u16::MAX as usize
185            || data.len()
186                > calculate_page_size::<S>()
187                    .saturating_sub(ItemHeader::data_address::<S>(0) as usize)
188        {
189            self.inner.cache.unmark_dirty();
190            return Err(Error::ItemTooBig);
191        }
192
193        let current_page = self.find_youngest_page().await?;
194
195        let page_data_start_address =
196            calculate_page_address::<S>(self.flash_range(), current_page) + S::WORD_SIZE as u32;
197        let page_data_end_address =
198            calculate_page_end_address::<S>(self.flash_range(), current_page) - S::WORD_SIZE as u32;
199
200        self.inner.partial_close_page(current_page).await?;
201
202        // Find the last item on the page so we know where we need to write
203
204        let mut next_address = self
205            .inner
206            .find_next_free_item_spot(
207                page_data_start_address,
208                page_data_end_address,
209                data.len() as u32,
210            )
211            .await?;
212
213        if next_address.is_none() {
214            // No cap left on this page, move to the next page
215            let next_page = self.inner.next_page(current_page);
216            let next_page_state = self.inner.get_page_state_cached(next_page).await?;
217            let single_page = next_page == current_page;
218
219            match (next_page_state, single_page) {
220                (PageState::Open, _) => {
221                    self.inner.close_page(current_page).await?;
222                    self.inner.partial_close_page(next_page).await?;
223                    next_address = Some(
224                        calculate_page_address::<S>(self.flash_range(), next_page)
225                            + S::WORD_SIZE as u32,
226                    );
227                }
228                (PageState::Closed, _) | (PageState::PartialOpen, true) => {
229                    let next_page_data_start_address =
230                        calculate_page_address::<S>(self.flash_range(), next_page)
231                            + S::WORD_SIZE as u32;
232
233                    if !allow_overwrite_old_data
234                        && !self
235                            .inner
236                            .is_page_empty(next_page, Some(next_page_state))
237                            .await?
238                    {
239                        self.inner.cache.unmark_dirty();
240                        return Err(Error::FullStorage);
241                    }
242
243                    self.inner.open_page(next_page).await?;
244                    if !single_page {
245                        self.inner.close_page(current_page).await?;
246                    }
247                    self.inner.partial_close_page(next_page).await?;
248                    next_address = Some(next_page_data_start_address);
249                }
250                (PageState::PartialOpen, false) => {
251                    // This should never happen
252                    return Err(Error::Corrupted {
253                        #[cfg(feature = "_test")]
254                        backtrace: std::backtrace::Backtrace::capture(),
255                    });
256                }
257            }
258        }
259
260        Item::write_new(
261            &mut self.inner.flash,
262            self.inner.flash_range.clone(),
263            &mut self.inner.cache,
264            next_address.unwrap(),
265            data,
266        )
267        .await?;
268
269        self.inner.cache.unmark_dirty();
270        Ok(())
271    }
272
273    /// Get an iterator-like interface to iterate over the items stored in the queue.
274    /// This goes from oldest to newest.
275    ///
276    /// The iteration happens non-destructively, or in other words it peeks at every item.
277    /// The returned entry has a [`QueueIteratorEntry::pop`] function with which you can decide to pop the item
278    /// after you've seen the contents.
279    pub async fn iter(&mut self) -> Result<QueueIterator<'_, S, C>, Error<S::Error>> {
280        // Note: Corruption repair is done in these functions already
281        QueueIterator::new(self).await
282    }
283
284    /// Peek at the oldest data.
285    ///
286    /// If you also want to remove the data use [`Self::pop`].
287    ///
288    /// The data is written to the given `data_buffer` and the part that was written is returned.
289    /// It is valid to only use the length of the returned slice and use the original `data_buffer`.
290    /// The `data_buffer` may contain extra data on ranges after the returned slice.
291    /// You should not depend on that data.
292    ///
293    /// If the data buffer is not big enough an error is returned.
294    pub async fn peek<'d>(
295        &mut self,
296        data_buffer: &'d mut [u8],
297    ) -> Result<Option<&'d mut [u8]>, Error<S::Error>> {
298        // Note: Corruption repair is done in these functions already
299        let mut iterator = self.iter().await?;
300
301        let next_value = iterator.next(data_buffer).await?;
302
303        match next_value {
304            Some(entry) => Ok(Some(entry.into_buf())),
305            None => Ok(None),
306        }
307    }
308
309    /// Pop the oldest data from the queue.
310    ///
311    /// If you don't want to remove the data use [`Self::peek`].
312    ///
313    /// The data is written to the given `data_buffer` and the part that was written is returned.
314    /// It is valid to only use the length of the returned slice and use the original `data_buffer`.
315    /// The `data_buffer` may contain extra data on ranges after the returned slice.
316    /// You should not depend on that data.
317    ///
318    /// If the data buffer is not big enough an error is returned.
319    pub async fn pop<'d>(
320        &mut self,
321        data_buffer: &'d mut [u8],
322    ) -> Result<Option<&'d mut [u8]>, Error<S::Error>>
323    where
324        S: MultiwriteNorFlash,
325    {
326        let mut iterator = self.iter().await?;
327
328        let next_value = iterator.next(data_buffer).await?;
329
330        match next_value {
331            Some(entry) => Ok(Some(entry.pop().await?)),
332            None => Ok(None),
333        }
334    }
335
336    /// Find the largest size of data that can be stored.
337    ///
338    /// This will read through the entire flash to find the largest chunk of
339    /// data that can be stored, taking alignment requirements of the item into account.
340    ///
341    /// If there is no space left, `None` is returned.
342    pub async fn find_max_fit(&mut self) -> Result<Option<u32>, Error<S::Error>> {
343        run_with_auto_repair!(
344            function = self.find_max_fit_inner().await,
345            repair = self.try_repair().await?
346        )
347    }
348
349    async fn find_max_fit_inner(&mut self) -> Result<Option<u32>, Error<S::Error>> {
350        if self.inner.cache.is_dirty() {
351            self.inner.cache.invalidate_cache_state();
352        }
353
354        let current_page = self.find_youngest_page().await?;
355
356        // Check if we have space on the next page
357        let next_page = self.inner.next_page(current_page);
358        match self.inner.get_page_state_cached(next_page).await? {
359            state @ PageState::Closed => {
360                if self.inner.is_page_empty(next_page, Some(state)).await? {
361                    self.inner.cache.unmark_dirty();
362                    return Ok(Some((S::ERASE_SIZE - (2 * S::WORD_SIZE)) as u32));
363                }
364            }
365            PageState::Open => {
366                self.inner.cache.unmark_dirty();
367                return Ok(Some((S::ERASE_SIZE - (2 * S::WORD_SIZE)) as u32));
368            }
369            PageState::PartialOpen => {
370                // This should never happen
371                return Err(Error::Corrupted {
372                    #[cfg(feature = "_test")]
373                    backtrace: std::backtrace::Backtrace::capture(),
374                });
375            }
376        }
377
378        // See how much space we can find in the current page.
379        let page_data_start_address =
380            calculate_page_address::<S>(self.flash_range(), current_page) + S::WORD_SIZE as u32;
381        let page_data_end_address =
382            calculate_page_end_address::<S>(self.flash_range(), current_page) - S::WORD_SIZE as u32;
383
384        let next_item_address = match self.inner.cache.first_item_after_written(current_page) {
385            Some(next_item_address) => next_item_address,
386            None => {
387                ItemHeaderIter::new(
388                    self.inner
389                        .cache
390                        .first_item_after_erased(current_page)
391                        .unwrap_or(page_data_start_address),
392                    page_data_end_address,
393                )
394                .traverse(&mut self.inner.flash, |_, _| true)
395                .await?
396                .1
397            }
398        };
399
400        self.inner.cache.unmark_dirty();
401        Ok(ItemHeader::available_data_bytes::<S>(
402            page_data_end_address - next_item_address,
403        ))
404    }
405
406    /// Calculate how much space is left free in the queue (in bytes).
407    ///
408    /// The number given back is accurate, however there are lots of things that add overhead and padding.
409    /// Every push is an item with its own overhead. You can check the overhead per item with [`Self::item_overhead_size`].
410    ///
411    /// Furthermore, every item has to fully fit in a page. So if a page has 50 bytes left and you push an item of 60 bytes,
412    /// the current page is closed and the item is stored on the next page, 'wasting' the 50 you had.
413    ///
414    /// So unless you're tracking all this, the returned number should only be used as a rough indication.
415    pub async fn space_left(&mut self) -> Result<u32, Error<S::Error>> {
416        run_with_auto_repair!(
417            function = self.space_left_inner().await,
418            repair = self.try_repair().await?
419        )
420    }
421
422    async fn space_left_inner(&mut self) -> Result<u32, Error<S::Error>> {
423        if self.inner.cache.is_dirty() {
424            self.inner.cache.invalidate_cache_state();
425        }
426
427        let mut total_free_space = 0;
428
429        for page in self.inner.get_pages(0) {
430            let state = self.inner.get_page_state_cached(page).await?;
431            let page_empty = self.inner.is_page_empty(page, Some(state)).await?;
432
433            if state.is_closed() && !page_empty {
434                continue;
435            }
436
437            // See how much space we can find in the current page.
438            let page_data_start_address =
439                calculate_page_address::<S>(self.flash_range(), page) + S::WORD_SIZE as u32;
440            let page_data_end_address =
441                calculate_page_end_address::<S>(self.flash_range(), page) - S::WORD_SIZE as u32;
442
443            if page_empty {
444                total_free_space += page_data_end_address - page_data_start_address;
445                continue;
446            }
447
448            // Partial open page
449            let next_item_address = match self.inner.cache.first_item_after_written(page) {
450                Some(next_item_address) => next_item_address,
451                None => {
452                    ItemHeaderIter::new(
453                        self.inner
454                            .cache
455                            .first_item_after_erased(page)
456                            .unwrap_or(page_data_start_address),
457                        page_data_end_address,
458                    )
459                    .traverse(&mut self.inner.flash, |_, _| true)
460                    .await?
461                    .1
462                }
463            };
464
465            if ItemHeader::available_data_bytes::<S>(page_data_end_address - next_item_address)
466                .is_none()
467            {
468                // No data fits on this partial open page anymore.
469                // So if all data on this is already erased, then this page might as well be counted as empty.
470                // We can use [is_page_empty] and lie to to it so it checks the items.
471                if self
472                    .inner
473                    .is_page_empty(page, Some(PageState::Closed))
474                    .await?
475                {
476                    total_free_space += page_data_end_address - page_data_start_address;
477                    continue;
478                }
479            }
480
481            total_free_space += page_data_end_address - next_item_address;
482        }
483
484        self.inner.cache.unmark_dirty();
485        Ok(total_free_space)
486    }
487
488    async fn find_youngest_page(&mut self) -> Result<usize, Error<S::Error>> {
489        let last_used_page = self
490            .inner
491            .find_first_page(0, PageState::PartialOpen)
492            .await?;
493
494        if let Some(last_used_page) = last_used_page {
495            return Ok(last_used_page);
496        }
497
498        // We have no partial open page. Search for a closed page to anker ourselves to
499        let first_closed_page = self.inner.find_first_page(0, PageState::Closed).await?;
500
501        let first_open_page = match first_closed_page {
502            Some(anchor) => {
503                // We have at least one closed page
504                // The first one after is the page we need to use
505                self.inner.find_first_page(anchor, PageState::Open).await?
506            }
507            None => {
508                // No closed pages and no partial open pages, so all pages should be open
509                // Might as well start at page 0
510                Some(0)
511            }
512        };
513
514        if let Some(first_open_page) = first_open_page {
515            return Ok(first_open_page);
516        }
517
518        // All pages are closed... This is not correct.
519        Err(Error::Corrupted {
520            #[cfg(feature = "_test")]
521            backtrace: std::backtrace::Backtrace::capture(),
522        })
523    }
524
525    async fn find_oldest_page(&mut self) -> Result<usize, Error<S::Error>> {
526        let youngest_page = self.find_youngest_page().await?;
527
528        // The oldest page is the first non-open page after the youngest page
529        let oldest_closed_page = self
530            .inner
531            .find_first_page(youngest_page, PageState::Closed)
532            .await?;
533
534        Ok(oldest_closed_page.unwrap_or(youngest_page))
535    }
536
537    /// Try to repair the state of the flash to hopefull get back everything in working order.
538    /// Care is taken that no data is lost, but this depends on correctly repairing the state and
539    /// so is only best effort.
540    ///
541    /// This function might be called after a different function returned the [`Error::Corrupted`] error.
542    /// There's no guarantee it will work.
543    ///
544    /// If this function or the function call after this crate returns [`Error::Corrupted`], then it's unlikely
545    /// that the state can be recovered. To at least make everything function again at the cost of losing the data,
546    /// erase the flash range.
547    async fn try_repair(&mut self) -> Result<(), Error<S::Error>> {
548        self.inner.cache.invalidate_cache_state();
549
550        self.inner.try_general_repair().await?;
551        Ok(())
552    }
553
554    async fn find_start_address(&mut self) -> Result<NextAddress, Error<S::Error>> {
555        if self.inner.cache.is_dirty() {
556            self.inner.cache.invalidate_cache_state();
557        }
558
559        let oldest_page = self.find_oldest_page().await?;
560
561        // We start at the start of the oldest page
562        let current_address = match self.inner.cache.first_item_after_erased(oldest_page) {
563            Some(address) => address,
564            None => {
565                calculate_page_address::<S>(self.inner.flash_range.clone(), oldest_page)
566                    + S::WORD_SIZE as u32
567            }
568        };
569
570        Ok(NextAddress::Address(current_address))
571    }
572
573    /// Resets the flash in the entire given flash range.
574    ///
575    /// This is just a thin helper function as it just calls the flash's erase function.
576    pub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>> {
577        self.inner.erase_all()
578    }
579
580    /// Get the minimal overhead size per stored item for the given flash type.
581    ///
582    /// The associated data of each item is additionally padded to a full flash word size, but that's not part of this number.\
583    /// This means the full item length is `returned number + (data length).next_multiple_of(S::WORD_SIZE)`.
584    #[must_use]
585    pub const fn item_overhead_size() -> u32 {
586        GenericStorage::<S, C, ()>::item_overhead_size()
587    }
588
589    /// Destroy the instance to get back the flash and the cache.
590    ///
591    /// The cache can be passed to a new storage instance, but only for the same flash region and if nothing has changed in flash.
592    pub fn destroy(self) -> (S, C) {
593        self.inner.destroy()
594    }
595
596    /// Get a reference to the flash. Mutating the memory is at your own risk.
597    pub const fn flash(&mut self) -> &mut S {
598        self.inner.flash()
599    }
600
601    /// Get the flash range being used
602    pub const fn flash_range(&self) -> Range<u32> {
603        self.inner.flash_range()
604    }
605
606    /// Get a reference to the cache
607    #[cfg(any(test, fuzzing))]
608    pub const fn cache(&mut self) -> &mut C {
609        &mut self.inner.cache
610    }
611
612    #[cfg(any(test, feature = "std", fuzzing))]
613    /// Print all items in flash to the returned string
614    ///
615    /// This is meant as a debugging utility. The string format is not stable.
616    pub fn print_items(&mut self) -> impl Future<Output = String> {
617        self.inner.print_items()
618    }
619}
620
621#[derive(PartialEq, Eq, Clone, Copy, Debug)]
622enum PreviousItemStates {
623    AllPopped,
624    AllButCurrentPopped,
625    Unpopped,
626}
627
628/// An iterator-like interface for peeking into data stored in flash with the option to pop it.
629pub struct QueueIterator<'s, S: NorFlash, C: CacheImpl<()>> {
630    storage: &'s mut QueueStorage<S, C>,
631    next_address: NextAddress,
632    previous_item_states: PreviousItemStates,
633    oldest_page: usize,
634}
635
636impl<S: NorFlash, C: CacheImpl<()>> Debug for QueueIterator<'_, S, C> {
637    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
638        f.debug_struct("QueueIterator")
639            .field("current_address", &self.next_address)
640            .finish_non_exhaustive()
641    }
642}
643
644#[derive(Debug, Clone, Copy)]
645enum NextAddress {
646    Address(u32),
647    PageAfter(usize),
648}
649
650impl<'s, S: NorFlash, C: CacheImpl<()>> QueueIterator<'s, S, C> {
651    async fn new(storage: &'s mut QueueStorage<S, C>) -> Result<Self, Error<S::Error>> {
652        let start_address = run_with_auto_repair!(
653            function = storage.find_start_address().await,
654            repair = storage.try_repair().await?
655        )?;
656
657        let oldest_page = match start_address {
658            NextAddress::Address(address) => {
659                calculate_page_index::<S>(storage.inner.flash_range.clone(), address)
660            }
661            NextAddress::PageAfter(index) => storage.inner.next_page(index),
662        };
663
664        Ok(Self {
665            storage,
666            next_address: start_address,
667            previous_item_states: PreviousItemStates::AllPopped,
668            oldest_page,
669        })
670    }
671
672    /// Get the next entry.
673    ///
674    /// If there are no more entries, None is returned.
675    ///
676    /// The `data_buffer` has to be large enough to be able to hold the largest item in flash.
677    pub async fn next<'d, 'q>(
678        &'q mut self,
679        data_buffer: &'d mut [u8],
680    ) -> Result<Option<QueueIteratorEntry<'s, 'd, 'q, S, C>>, Error<S::Error>> {
681        // We continue from a place where the current item wasn't popped
682        // That means that from now on, the next item will have unpopped items behind it
683        if self.previous_item_states == PreviousItemStates::AllButCurrentPopped {
684            self.previous_item_states = PreviousItemStates::Unpopped;
685        }
686
687        let value = run_with_auto_repair!(
688            function = self.next_inner(data_buffer).await,
689            repair = self.storage.try_repair().await?
690        );
691
692        match value {
693            Ok(Some((item, address))) => Ok(Some(QueueIteratorEntry {
694                iter: self,
695                item: item.reborrow(data_buffer).ok_or_else(|| Error::LogicBug {
696                    #[cfg(feature = "_test")]
697                    backtrace: std::backtrace::Backtrace::capture(),
698                })?,
699                address,
700            })),
701            Ok(None) => Ok(None),
702            Err(e) => Err(e),
703        }
704    }
705
706    async fn next_inner(
707        &mut self,
708        data_buffer: &mut [u8],
709    ) -> Result<Option<(ItemUnborrowed, u32)>, Error<S::Error>> {
710        if self.storage.inner.cache.is_dirty() {
711            self.storage.inner.cache.invalidate_cache_state();
712        }
713
714        loop {
715            // Get the current page and address based on what was stored
716            let (current_page, current_address) = match self.next_address {
717                NextAddress::PageAfter(previous_page) => {
718                    let next_page = self.storage.inner.next_page(previous_page);
719                    if self
720                        .storage
721                        .inner
722                        .get_page_state_cached(next_page)
723                        .await?
724                        .is_open()
725                        || next_page == self.oldest_page
726                    {
727                        self.storage.inner.cache.unmark_dirty();
728                        return Ok(None);
729                    }
730
731                    // We now know the previous page was left because there were no items on there anymore
732                    // If we know all those items were popped, we can proactively open the previous page
733                    // This is amazing for performance
734                    if self.previous_item_states == PreviousItemStates::AllPopped {
735                        self.storage.inner.open_page(previous_page).await?;
736                    }
737
738                    let current_address = calculate_page_address::<S>(
739                        self.storage.inner.flash_range.clone(),
740                        next_page,
741                    ) + S::WORD_SIZE as u32;
742
743                    self.next_address = NextAddress::Address(current_address);
744
745                    (next_page, current_address)
746                }
747                NextAddress::Address(address) => (
748                    calculate_page_index::<S>(self.storage.inner.flash_range.clone(), address),
749                    address,
750                ),
751            };
752
753            let page_data_end_address = calculate_page_end_address::<S>(
754                self.storage.inner.flash_range.clone(),
755                current_page,
756            ) - S::WORD_SIZE as u32;
757
758            // Search for the first item with data
759            let mut it = ItemHeaderIter::new(current_address, page_data_end_address);
760            // No need to worry about cache here since that has been dealt with at the creation of this iterator
761            if let (Some(found_item_header), found_item_address) = it
762                .traverse(&mut self.storage.inner.flash, |header, _| {
763                    header.crc.is_none()
764                })
765                .await?
766            {
767                let maybe_item = found_item_header
768                    .read_item(
769                        &mut self.storage.inner.flash,
770                        data_buffer,
771                        found_item_address,
772                        page_data_end_address,
773                    )
774                    .await?;
775
776                match maybe_item {
777                    item::MaybeItem::Corrupted(header, _) => {
778                        let next_address = header.next_item_address::<S>(found_item_address);
779                        self.next_address = if next_address >= page_data_end_address {
780                            NextAddress::PageAfter(current_page)
781                        } else {
782                            NextAddress::Address(next_address)
783                        };
784                    }
785                    item::MaybeItem::Erased(_, _) => {
786                        // Item is already erased
787                        return Err(Error::LogicBug {
788                            #[cfg(feature = "_test")]
789                            backtrace: std::backtrace::Backtrace::capture(),
790                        });
791                    }
792                    item::MaybeItem::Present(item) => {
793                        let next_address = item.header.next_item_address::<S>(found_item_address);
794                        self.next_address = if next_address >= page_data_end_address {
795                            NextAddress::PageAfter(current_page)
796                        } else {
797                            NextAddress::Address(next_address)
798                        };
799
800                        // Record that the current item hasn't been popped (yet)
801                        if self.previous_item_states == PreviousItemStates::AllPopped {
802                            self.previous_item_states = PreviousItemStates::AllButCurrentPopped;
803                        }
804
805                        // Return the item we found
806                        self.storage.inner.cache.unmark_dirty();
807                        return Ok(Some((item.unborrow(), found_item_address)));
808                    }
809                }
810            } else {
811                self.next_address = NextAddress::PageAfter(current_page);
812            }
813        }
814    }
815}
816
817/// An entry in the iteration over the queue flash
818pub struct QueueIteratorEntry<'s, 'd, 'q, S: NorFlash, CI: CacheImpl<()>> {
819    iter: &'q mut QueueIterator<'s, S, CI>,
820    address: u32,
821    item: Item<'d>,
822}
823
824impl<S: NorFlash, CI: CacheImpl<()>> Deref for QueueIteratorEntry<'_, '_, '_, S, CI> {
825    type Target = [u8];
826
827    fn deref(&self) -> &Self::Target {
828        self.item.data()
829    }
830}
831
832impl<S: NorFlash, CI: CacheImpl<()>> DerefMut for QueueIteratorEntry<'_, '_, '_, S, CI> {
833    fn deref_mut(&mut self) -> &mut Self::Target {
834        self.item.data_mut()
835    }
836}
837
838impl<'d, S: NorFlash, CI: CacheImpl<()>> QueueIteratorEntry<'_, 'd, '_, S, CI> {
839    /// Get a mutable reference to the data of this entry, but consume the entry too.
840    /// This function has some relaxed lifetime constraints compared to the deref impls.
841    #[must_use]
842    pub fn into_buf(self) -> &'d mut [u8] {
843        self.item.data_owned()
844    }
845
846    /// Pop the data in flash that corresponds to this entry. This makes it so
847    /// future peeks won't find this data anymore.
848    pub async fn pop(self) -> Result<&'d mut [u8], Error<S::Error>>
849    where
850        S: MultiwriteNorFlash,
851    {
852        let (header, item_data_buffer) = self.item.header_and_data_owned();
853
854        // We're popping ourself, so if all previous but us were popped, then now all are popped again
855        if self.iter.previous_item_states == PreviousItemStates::AllButCurrentPopped {
856            self.iter.previous_item_states = PreviousItemStates::AllPopped;
857        }
858
859        header
860            .erase_data(
861                &mut self.iter.storage.inner.flash,
862                self.iter.storage.inner.flash_range.clone(),
863                &mut self.iter.storage.inner.cache,
864                self.address,
865            )
866            .await?;
867
868        self.iter.storage.inner.cache.unmark_dirty();
869        Ok(item_data_buffer)
870    }
871
872    /// Get the flash address of the item
873    #[cfg(feature = "_test")]
874    pub fn address(&self) -> u32 {
875        self.address
876    }
877}
878
879#[cfg(test)]
880mod tests {
881    use crate::{
882        AlignedBuf,
883        cache::Cache,
884        mock_flash::{self, FlashAverageStatsResult, FlashStatsResult, WriteCountCheck},
885    };
886
887    use super::*;
888    use futures_test::test;
889
890    type MockFlashBig = mock_flash::MockFlashBase<4, 4, 256>;
891    type MockFlashTiny = mock_flash::MockFlashBase<2, 1, 32>;
892
893    #[test]
894    async fn peek_and_overwrite_old_data() {
895        let mut storage = QueueStorage::new(
896            MockFlashTiny::new(WriteCountCheck::Twice, None, true),
897            const { QueueConfig::new(0x00..0x40) },
898            Cache::new_uncached(),
899        );
900        let mut data_buffer = AlignedBuf([0; 1024]);
901        const DATA_SIZE: usize = 22;
902
903        assert_eq!(storage.space_left().await.unwrap(), 60);
904
905        assert_eq!(storage.peek(&mut data_buffer).await.unwrap(), None);
906
907        data_buffer[..DATA_SIZE].copy_from_slice(&[0xAA; DATA_SIZE]);
908        storage
909            .push(&data_buffer[..DATA_SIZE], false)
910            .await
911            .unwrap();
912
913        assert_eq!(storage.space_left().await.unwrap(), 30);
914
915        assert_eq!(
916            storage.peek(&mut data_buffer).await.unwrap().unwrap(),
917            &[0xAA; DATA_SIZE]
918        );
919        data_buffer[..DATA_SIZE].copy_from_slice(&[0xBB; DATA_SIZE]);
920        storage
921            .push(&data_buffer[..DATA_SIZE], false)
922            .await
923            .unwrap();
924
925        assert_eq!(storage.space_left().await.unwrap(), 0);
926
927        assert_eq!(
928            storage.peek(&mut data_buffer).await.unwrap().unwrap(),
929            &[0xAA; DATA_SIZE]
930        );
931
932        // Flash is full, this should fail
933        data_buffer[..DATA_SIZE].copy_from_slice(&[0xCC; DATA_SIZE]);
934        storage
935            .push(&data_buffer[..DATA_SIZE], false)
936            .await
937            .unwrap_err();
938        // Now we allow overwrite, so it should work
939        data_buffer[..DATA_SIZE].copy_from_slice(&[0xDD; DATA_SIZE]);
940        storage.push(&data_buffer[..DATA_SIZE], true).await.unwrap();
941
942        assert_eq!(
943            storage.peek(&mut data_buffer).await.unwrap().unwrap(),
944            &[0xBB; DATA_SIZE]
945        );
946        assert_eq!(
947            storage.pop(&mut data_buffer).await.unwrap().unwrap(),
948            &[0xBB; DATA_SIZE]
949        );
950
951        assert_eq!(storage.space_left().await.unwrap(), 30);
952
953        assert_eq!(
954            storage.peek(&mut data_buffer).await.unwrap().unwrap(),
955            &[0xDD; DATA_SIZE]
956        );
957        assert_eq!(
958            storage.pop(&mut data_buffer).await.unwrap().unwrap(),
959            &[0xDD; DATA_SIZE]
960        );
961
962        assert_eq!(storage.space_left().await.unwrap(), 60);
963
964        assert_eq!(storage.peek(&mut data_buffer).await.unwrap(), None);
965        assert_eq!(storage.pop(&mut data_buffer).await.unwrap(), None);
966    }
967
968    #[test]
969    async fn push_pop() {
970        let mut storage = QueueStorage::new(
971            MockFlashBig::new(WriteCountCheck::Twice, None, true),
972            const { QueueConfig::new(0x000..0x1000) },
973            Cache::new_uncached(),
974        );
975
976        let mut data_buffer = AlignedBuf([0; 1024]);
977
978        for i in 0..2000 {
979            println!("{i}");
980            let data = vec![i as u8; i % 512 + 1];
981
982            storage.push(&data, true).await.unwrap();
983            assert_eq!(
984                storage.peek(&mut data_buffer).await.unwrap().unwrap(),
985                &data,
986                "At {i}"
987            );
988            assert_eq!(
989                storage.pop(&mut data_buffer).await.unwrap().unwrap(),
990                &data,
991                "At {i}"
992            );
993            assert_eq!(
994                storage.peek(&mut data_buffer).await.unwrap(),
995                None,
996                "At {i}"
997            );
998        }
999    }
1000
1001    #[test]
1002    async fn iter_pop_out_of_order() {
1003        let mut storage = QueueStorage::new(
1004            MockFlashBig::new(WriteCountCheck::Twice, None, true),
1005            const { QueueConfig::new(0x000..0x1000) },
1006            Cache::new_uncached(),
1007        );
1008
1009        let mut data_buffer = AlignedBuf([0; 1024]);
1010
1011        let gen_data = |i: usize| vec![i as u8; i % 512 + 1];
1012        const COUNT: usize = 20;
1013
1014        for i in 0..COUNT {
1015            storage.push(&gen_data(i), false).await.unwrap();
1016        }
1017
1018        let mut iterator = storage.iter().await.unwrap();
1019        let mut i = 0;
1020        while let Some(entry) = iterator.next(&mut data_buffer).await.unwrap() {
1021            if i % 2 == 1 {
1022                assert_eq!(entry.pop().await.unwrap(), gen_data(i));
1023            }
1024
1025            i += 1;
1026        }
1027        assert_eq!(i, COUNT);
1028
1029        let mut iterator = storage.iter().await.unwrap();
1030        let mut i = 0;
1031        while let Some(entry) = iterator.next(&mut data_buffer).await.unwrap() {
1032            assert_eq!(entry.into_buf(), gen_data(i));
1033            i += 2;
1034        }
1035        assert_eq!(i, COUNT);
1036    }
1037
1038    #[test]
1039    async fn push_pop_tiny() {
1040        let mut storage = QueueStorage::new(
1041            MockFlashTiny::new(WriteCountCheck::Twice, None, true),
1042            const { QueueConfig::new(0x00..0x40) },
1043            Cache::new_uncached(),
1044        );
1045        let mut data_buffer = AlignedBuf([0; 1024]);
1046
1047        for i in 0..2000 {
1048            println!("{i}");
1049            let data = vec![i as u8; i % 20 + 1];
1050
1051            println!("PUSH");
1052            storage.push(&data, true).await.unwrap();
1053            assert_eq!(
1054                storage.peek(&mut data_buffer).await.unwrap().unwrap(),
1055                &data,
1056                "At {i}"
1057            );
1058            println!("POP");
1059            assert_eq!(
1060                storage.pop(&mut data_buffer).await.unwrap().unwrap(),
1061                &data,
1062                "At {i}"
1063            );
1064            println!("PEEK");
1065            assert_eq!(
1066                storage.peek(&mut data_buffer).await.unwrap(),
1067                None,
1068                "At {i}"
1069            );
1070            println!("DONE");
1071        }
1072    }
1073
1074    #[test]
1075    /// Same as [push_lots_then_pop_lots], except with added peeking and using the iterator style
1076    async fn push_peek_pop_many() {
1077        let mut storage = QueueStorage::new(
1078            MockFlashBig::new(WriteCountCheck::Twice, None, true),
1079            const { QueueConfig::new(0x000..0x1000) },
1080            Cache::new_uncached(),
1081        );
1082        let mut data_buffer = AlignedBuf([0; 1024]);
1083
1084        let mut push_stats = FlashStatsResult::default();
1085        let mut pushes = 0;
1086        let mut peek_stats = FlashStatsResult::default();
1087        let mut peeks = 0;
1088        let mut pop_stats = FlashStatsResult::default();
1089        let mut pops = 0;
1090
1091        for loop_index in 0..100 {
1092            println!("Loop index: {loop_index}");
1093
1094            for i in 0..20 {
1095                let start_snapshot = storage.flash().stats_snapshot();
1096                let data = vec![i as u8; 50];
1097                storage.push(&data, false).await.unwrap();
1098                pushes += 1;
1099                push_stats += start_snapshot.compare_to(storage.flash().stats_snapshot());
1100            }
1101
1102            let start_snapshot = storage.flash().stats_snapshot();
1103            let mut iterator = storage.iter().await.unwrap();
1104            peek_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1105            for i in 0..5 {
1106                let start_snapshot = iterator.storage.flash().stats_snapshot();
1107                let data = [i as u8; 50];
1108                assert_eq!(
1109                    iterator
1110                        .next(&mut data_buffer)
1111                        .await
1112                        .unwrap()
1113                        .unwrap()
1114                        .deref(),
1115                    &data[..],
1116                    "At {i}"
1117                );
1118                peeks += 1;
1119                peek_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1120            }
1121
1122            let start_snapshot = storage.flash().stats_snapshot();
1123            let mut iterator = storage.iter().await.unwrap();
1124            pop_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1125            for i in 0..5 {
1126                let start_snapshot = iterator.storage.flash().stats_snapshot();
1127                let data = vec![i as u8; 50];
1128                assert_eq!(
1129                    iterator
1130                        .next(&mut data_buffer)
1131                        .await
1132                        .unwrap()
1133                        .unwrap()
1134                        .pop()
1135                        .await
1136                        .unwrap(),
1137                    &data,
1138                    "At {i}"
1139                );
1140                pops += 1;
1141                pop_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1142            }
1143
1144            for i in 20..25 {
1145                let start_snapshot = storage.flash().stats_snapshot();
1146                let data = vec![i as u8; 50];
1147                storage.push(&data, false).await.unwrap();
1148                pushes += 1;
1149                push_stats += start_snapshot.compare_to(storage.flash().stats_snapshot());
1150            }
1151
1152            let start_snapshot = storage.flash().stats_snapshot();
1153            let mut iterator = storage.iter().await.unwrap();
1154            peek_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1155            for i in 5..25 {
1156                let start_snapshot = iterator.storage.flash().stats_snapshot();
1157                let data = vec![i as u8; 50];
1158                assert_eq!(
1159                    iterator
1160                        .next(&mut data_buffer)
1161                        .await
1162                        .unwrap()
1163                        .unwrap()
1164                        .deref(),
1165                    &data,
1166                    "At {i}"
1167                );
1168                peeks += 1;
1169                peek_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1170            }
1171
1172            let start_snapshot = storage.flash().stats_snapshot();
1173            let mut iterator = storage.iter().await.unwrap();
1174            pop_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1175            for i in 5..25 {
1176                let start_snapshot = iterator.storage.flash().stats_snapshot();
1177                let data = vec![i as u8; 50];
1178                assert_eq!(
1179                    iterator
1180                        .next(&mut data_buffer)
1181                        .await
1182                        .unwrap()
1183                        .unwrap()
1184                        .pop()
1185                        .await
1186                        .unwrap(),
1187                    &data,
1188                    "At {i}"
1189                );
1190                pops += 1;
1191                pop_stats += start_snapshot.compare_to(iterator.storage.flash().stats_snapshot());
1192            }
1193        }
1194
1195        // Assert the performance. These numbers can be changed if acceptable.
1196        approx::assert_relative_eq!(
1197            push_stats.take_average(pushes),
1198            FlashAverageStatsResult {
1199                avg_erases: 0.0,
1200                avg_reads: 16.864,
1201                avg_writes: 3.1252,
1202                avg_bytes_read: 105.4112,
1203                avg_bytes_written: 60.5008
1204            }
1205        );
1206        approx::assert_relative_eq!(
1207            peek_stats.take_average(peeks),
1208            FlashAverageStatsResult {
1209                avg_erases: 0.0052,
1210                avg_reads: 3.8656,
1211                avg_writes: 0.0,
1212                avg_bytes_read: 70.4256,
1213                avg_bytes_written: 0.0
1214            }
1215        );
1216        approx::assert_relative_eq!(
1217            pop_stats.take_average(pops),
1218            FlashAverageStatsResult {
1219                avg_erases: 0.0572,
1220                avg_reads: 3.7772,
1221                avg_writes: 1.0,
1222                avg_bytes_read: 69.7184,
1223                avg_bytes_written: 8.0
1224            }
1225        );
1226    }
1227
1228    #[test]
1229    async fn push_lots_then_pop_lots() {
1230        let mut storage = QueueStorage::new(
1231            MockFlashBig::new(WriteCountCheck::Twice, None, true),
1232            const { QueueConfig::new(0x000..0x1000) },
1233            Cache::new_uncached(),
1234        );
1235        let mut data_buffer = AlignedBuf([0; 1024]);
1236
1237        let mut push_stats = FlashStatsResult::default();
1238        let mut pushes = 0;
1239        let mut pop_stats = FlashStatsResult::default();
1240        let mut pops = 0;
1241
1242        for loop_index in 0..100 {
1243            println!("Loop index: {loop_index}");
1244
1245            for i in 0..20 {
1246                let start_snapshot = storage.flash().stats_snapshot();
1247                let data = vec![i as u8; 50];
1248                storage.push(&data, false).await.unwrap();
1249                pushes += 1;
1250                push_stats += start_snapshot.compare_to(storage.flash().stats_snapshot());
1251            }
1252
1253            for i in 0..5 {
1254                let start_snapshot = storage.flash().stats_snapshot();
1255                let data = vec![i as u8; 50];
1256                assert_eq!(
1257                    storage.pop(&mut data_buffer).await.unwrap().unwrap(),
1258                    &data,
1259                    "At {i}"
1260                );
1261                pops += 1;
1262                pop_stats += start_snapshot.compare_to(storage.flash().stats_snapshot());
1263            }
1264
1265            for i in 20..25 {
1266                let start_snapshot = storage.flash().stats_snapshot();
1267                let data = vec![i as u8; 50];
1268                storage.push(&data, false).await.unwrap();
1269                pushes += 1;
1270                push_stats += start_snapshot.compare_to(storage.flash().stats_snapshot());
1271            }
1272
1273            for i in 5..25 {
1274                let start_snapshot = storage.flash().stats_snapshot();
1275                let data = vec![i as u8; 50];
1276                assert_eq!(
1277                    storage.pop(&mut data_buffer).await.unwrap().unwrap(),
1278                    &data,
1279                    "At {i}"
1280                );
1281                pops += 1;
1282                pop_stats += start_snapshot.compare_to(storage.flash().stats_snapshot());
1283            }
1284        }
1285
1286        // Assert the performance. These numbers can be changed if acceptable.
1287        approx::assert_relative_eq!(
1288            push_stats.take_average(pushes),
1289            FlashAverageStatsResult {
1290                avg_erases: 0.0,
1291                avg_reads: 16.864,
1292                avg_writes: 3.1252,
1293                avg_bytes_read: 105.4112,
1294                avg_bytes_written: 60.5008
1295            }
1296        );
1297        approx::assert_relative_eq!(
1298            pop_stats.take_average(pops),
1299            FlashAverageStatsResult {
1300                avg_erases: 0.0624,
1301                avg_reads: 23.5768,
1302                avg_writes: 1.0,
1303                avg_bytes_read: 180.512,
1304                avg_bytes_written: 8.0
1305            }
1306        );
1307    }
1308
1309    #[test]
1310    async fn pop_with_empty_section() {
1311        let mut storage = QueueStorage::new(
1312            MockFlashTiny::new(WriteCountCheck::Twice, None, true),
1313            const { QueueConfig::new(0x00..0x40) },
1314            Cache::new_uncached(),
1315        );
1316        let mut data_buffer = AlignedBuf([0; 1024]);
1317
1318        data_buffer[..20].copy_from_slice(&[0xAA; 20]);
1319        storage.push(&data_buffer[0..20], false).await.unwrap();
1320        data_buffer[..20].copy_from_slice(&[0xBB; 20]);
1321        storage.push(&data_buffer[0..20], false).await.unwrap();
1322
1323        // There's now an unused gap at the end of the first page
1324
1325        assert_eq!(
1326            storage.pop(&mut data_buffer).await.unwrap().unwrap(),
1327            &[0xAA; 20]
1328        );
1329
1330        assert_eq!(
1331            storage.pop(&mut data_buffer).await.unwrap().unwrap(),
1332            &[0xBB; 20]
1333        );
1334    }
1335
1336    #[test]
1337    async fn search_pages() {
1338        let mut storage = QueueStorage::new(
1339            MockFlashBig::new(WriteCountCheck::Twice, None, true),
1340            const { QueueConfig::new(0x000..0x1000) },
1341            Cache::new_uncached(),
1342        );
1343
1344        storage.inner.close_page(0).await.unwrap();
1345        storage.inner.close_page(1).await.unwrap();
1346        storage.inner.partial_close_page(2).await.unwrap();
1347
1348        assert_eq!(storage.find_youngest_page().await.unwrap(), 2);
1349        assert_eq!(storage.find_oldest_page().await.unwrap(), 0);
1350    }
1351
1352    #[test]
1353    async fn store_too_big_item() {
1354        let mut storage = QueueStorage::new(
1355            MockFlashBig::new(WriteCountCheck::Twice, None, true),
1356            const { QueueConfig::new(0x000..0x1000) },
1357            Cache::new_uncached(),
1358        );
1359
1360        storage
1361            .push(&AlignedBuf([0; 1024 - 4 * 2 - 8]), false)
1362            .await
1363            .unwrap();
1364
1365        assert_eq!(
1366            storage
1367                .push(&AlignedBuf([0; 1024 - 4 * 2 - 8 + 1]), false,)
1368                .await,
1369            Err(Error::ItemTooBig)
1370        );
1371    }
1372
1373    #[test]
1374    async fn push_on_single_page() {
1375        let mut storage = QueueStorage::new(
1376            mock_flash::MockFlashBase::<1, 4, 256>::new(WriteCountCheck::Twice, None, true),
1377            const { QueueConfig::new(0x000..0x400) },
1378            Cache::new_uncached(),
1379        );
1380
1381        for _ in 0..100 {
1382            match storage.push(&[0, 1, 2, 3, 4], true).await {
1383                Ok(_) => {}
1384                Err(e) => {
1385                    println!("{}", storage.print_items().await);
1386                    panic!("{e}");
1387                }
1388            }
1389        }
1390    }
1391}