1pub 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
16pub struct QueueConfig<S> {
18 flash_range: Range<u32>,
19 _phantom: PhantomData<S>,
20}
21
22impl<S: NorFlash> QueueConfig<S> {
23 #[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 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 if flash_range.end - flash_range.start < (S::ERASE_SIZE as u32) {
43 return Err(QueueConfigError::RangeTooSmall);
44 }
45
46 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#[derive(Debug, Clone, PartialEq, Eq)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub enum QueueConfigError {
65 StartRangeNotAtPageBoundary,
67 EndRangeNotAtPageBoundary,
69 RangeTooSmall,
71 PagesTooSmall,
73 WordSizeTooLarge,
75}
76
77pub struct QueueStorage<S: NorFlash, C: CacheImpl<()>> {
135 inner: GenericStorage<S, C, ()>,
136}
137
138impl<S: NorFlash, C: CacheImpl<()>> QueueStorage<S, C> {
139 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 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 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 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 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 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 pub async fn iter(&mut self) -> Result<QueueIterator<'_, S, C>, Error<S::Error>> {
280 QueueIterator::new(self).await
282 }
283
284 pub async fn peek<'d>(
295 &mut self,
296 data_buffer: &'d mut [u8],
297 ) -> Result<Option<&'d mut [u8]>, Error<S::Error>> {
298 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 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 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 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 return Err(Error::Corrupted {
372 #[cfg(feature = "_test")]
373 backtrace: std::backtrace::Backtrace::capture(),
374 });
375 }
376 }
377
378 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 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 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 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 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 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 self.inner.find_first_page(anchor, PageState::Open).await?
506 }
507 None => {
508 Some(0)
511 }
512 };
513
514 if let Some(first_open_page) = first_open_page {
515 return Ok(first_open_page);
516 }
517
518 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 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 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 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 pub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>> {
577 self.inner.erase_all()
578 }
579
580 #[must_use]
585 pub const fn item_overhead_size() -> u32 {
586 GenericStorage::<S, C, ()>::item_overhead_size()
587 }
588
589 pub fn destroy(self) -> (S, C) {
593 self.inner.destroy()
594 }
595
596 pub const fn flash(&mut self) -> &mut S {
598 self.inner.flash()
599 }
600
601 pub const fn flash_range(&self) -> Range<u32> {
603 self.inner.flash_range()
604 }
605
606 #[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 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
628pub 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 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 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 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 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 let mut it = ItemHeaderIter::new(current_address, page_data_end_address);
760 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 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 if self.previous_item_states == PreviousItemStates::AllPopped {
802 self.previous_item_states = PreviousItemStates::AllButCurrentPopped;
803 }
804
805 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
817pub 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 #[must_use]
842 pub fn into_buf(self) -> &'d mut [u8] {
843 self.item.data_owned()
844 }
845
846 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 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 #[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 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 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 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 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 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 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}