diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 339a0ac..9f14f12 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -96,7 +96,7 @@ pub(crate) trait PrivateCacheImpl: Invalidate { &mut self, flash_range: Range, item_address: u32, - item_header: &ItemHeader, + item_header: &ItemHeader, ) { self.mark_dirty(); self.page_pointers() @@ -108,7 +108,7 @@ pub(crate) trait PrivateCacheImpl: Invalidate { &mut self, flash_range: Range, item_address: u32, - item_header: &ItemHeader, + item_header: &ItemHeader, ) { self.mark_dirty(); self.page_pointers() diff --git a/src/cache/page_pointers.rs b/src/cache/page_pointers.rs index 34f4280..e9dcef8 100644 --- a/src/cache/page_pointers.rs +++ b/src/cache/page_pointers.rs @@ -14,13 +14,13 @@ pub(crate) trait PagePointersCache: Debug { &mut self, flash_range: Range, item_address: u32, - item_header: &ItemHeader, + item_header: &ItemHeader, ); fn notice_item_erased( &mut self, flash_range: Range, item_address: u32, - item_header: &ItemHeader, + item_header: &ItemHeader, ); fn notice_page_state(&mut self, page_index: usize, new_state: PageState); @@ -89,11 +89,11 @@ impl PagePointersCache for CachedPagePointers, item_address: u32, - item_header: &ItemHeader, + item_header: &ItemHeader, ) { let page_index = calculate_page_index::(flash_range, item_address); - let next_item_address = item_header.next_item_address::(item_address); + let next_item_address = item_header.next_item_address(item_address); // We only care about the furthest written item, so discard if this is an earlier item if let Some(first_item_after_written) = self.first_item_after_written(page_index) { @@ -109,7 +109,7 @@ impl PagePointersCache for CachedPagePointers, item_address: u32, - item_header: &ItemHeader, + item_header: &ItemHeader, ) { let page_index = calculate_page_index::(flash_range.clone(), item_address); @@ -120,7 +120,7 @@ impl PagePointersCache for CachedPagePointers(item_address)); + NonZeroU32::new(item_header.next_item_address(item_address)); } } @@ -155,7 +155,7 @@ impl PagePointersCache for UncachedPagePointers { &mut self, _flash_range: Range, _item_address: u32, - _item_header: &ItemHeader, + _item_header: &ItemHeader, ) { } @@ -163,7 +163,7 @@ impl PagePointersCache for UncachedPagePointers { &mut self, _flash_range: Range, _item_address: u32, - _item_header: &ItemHeader, + _item_header: &ItemHeader, ) { } diff --git a/src/cache/tests.rs b/src/cache/tests.rs index 73d2f25..34a9773 100644 --- a/src/cache/tests.rs +++ b/src/cache/tests.rs @@ -23,7 +23,7 @@ mod queue_tests { reads: 594934, writes: 6299, bytes_read: 2766058, - bytes_written: 53299 + bytes_written: 45299, } ); } @@ -37,7 +37,7 @@ mod queue_tests { reads: 308740, writes: 6299, bytes_read: 2479864, - bytes_written: 53299 + bytes_written: 45299 } ); } @@ -51,7 +51,7 @@ mod queue_tests { reads: 211172, writes: 6299, bytes_read: 1699320, - bytes_written: 53299 + bytes_written: 45299 } ); } diff --git a/src/item.rs b/src/item.rs index 6361fb0..76c8e49 100644 --- a/src/item.rs +++ b/src/item.rs @@ -6,10 +6,12 @@ //! ```text //! ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ //! │ : : : │ : │ : │ : : : : : │ : : : : : : : : : │ : : : : : │ -//! │ CRC │ Length │ Length' │Pad to word align│ Data │Pad to word align│ +//! │ CRC ... │ Length │ Length' │Pad to word align│ Data │Pad to word align│ //! │ : : : │ : │ : │ : : : : : │ : : : : : : : : : │ : : : : : │ //! └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┴──┴──┴──┴─┴──┴──┴──┴──┴──┴──┘ -//! 0 1 2 3 4 5 6 7 8 8+padding 8+padding+length 8+padding+length+endpadding +//! 0 1 2 3 ... WS WS+2 WS+4 WS+4+padding WS+4+padding+length WS+4+padding+length+endpadding +//! +//! WS = max(4, WORD_SIZE) //! ``` //! //! An item consists of an [ItemHeader] and some data. @@ -21,36 +23,42 @@ //! and has some other modifications to make corruption less likely to happen. //! -use core::num::NonZeroU32; use core::ops::Range; +use core::{marker::PhantomData, num::NonZeroU32}; -use embedded_storage_async::nor_flash::{MultiwriteNorFlash, NorFlash}; +use embedded_storage_async::nor_flash::NorFlash; use crate::{ cache::PrivateCacheImpl, calculate_page_address, calculate_page_end_address, calculate_page_index, get_page_state, round_down_to_alignment, round_down_to_alignment_usize, round_up_to_alignment, round_up_to_alignment_usize, AlignedBuf, Error, NorFlashExt, PageState, - MAX_WORD_SIZE, + WordclearNorFlash, MAX_WORD_SIZE, }; #[derive(Debug, Clone)] -pub struct ItemHeader { +pub struct ItemHeader { /// Length of the item payload (so not including the header and not including word alignment) pub length: u16, pub crc: Option, + _p: PhantomData, } -impl ItemHeader { - const LENGTH: usize = 8; +impl ItemHeader { + const DATA_CRC_LENGTH: usize = if ::WORD_SIZE < 4 { + 4 // The minimum is 4 to hold the CRC32. + } else { + ::WORD_SIZE + }; + const LENGTH: usize = Self::DATA_CRC_LENGTH + 4; - const DATA_CRC_FIELD: Range = 0..4; - const LENGTH_FIELD: Range = 4..6; - const LENGTH_CRC_FIELD: Range = 6..8; + const DATA_CRC_FIELD: Range = 0..Self::DATA_CRC_LENGTH; + const LENGTH_FIELD: Range = Self::DATA_CRC_LENGTH..Self::DATA_CRC_LENGTH + 2; + const LENGTH_CRC_FIELD: Range = Self::DATA_CRC_LENGTH + 2..Self::DATA_CRC_LENGTH + 4; /// Read the header from the flash at the given address. /// /// If the item doesn't exist or doesn't fit between the address and the end address, none is returned. - pub async fn read_new( + pub async fn read_new( flash: &mut S, address: u32, end_address: u32, @@ -90,25 +98,28 @@ impl ItemHeader { Ok(Some(Self { length: u16::from_le_bytes(header_slice[Self::LENGTH_FIELD].try_into().unwrap()), crc: { - match u32::from_le_bytes(header_slice[Self::DATA_CRC_FIELD].try_into().unwrap()) { + match u32::from_le_bytes( + header_slice[Self::DATA_CRC_FIELD][..4].try_into().unwrap(), + ) { 0 => None, value => Some(NonZeroU32::new(value).unwrap()), } }, + _p: PhantomData, })) } - pub async fn read_item<'d, S: NorFlash>( + pub async fn read_item<'d>( self, flash: &mut S, data_buffer: &'d mut [u8], address: u32, end_address: u32, - ) -> Result, Error> { + ) -> Result, Error> { match self.crc { None => Ok(MaybeItem::Erased(self, data_buffer)), Some(header_crc) => { - let data_address = ItemHeader::data_address::(address); + let data_address = Self::data_address(address); let read_len = round_up_to_alignment_usize::(self.length as usize); if data_buffer.len() < read_len { return Err(Error::BufferTooSmall(read_len)); @@ -141,7 +152,7 @@ impl ItemHeader { } } - async fn write(&self, flash: &mut S, address: u32) -> Result<(), Error> { + async fn write(&self, flash: &mut S, address: u32) -> Result<(), Error> { let mut buffer = AlignedBuf([0xFF; MAX_WORD_SIZE]); buffer[Self::DATA_CRC_FIELD] @@ -163,47 +174,62 @@ impl ItemHeader { }) } - /// Erase this item by setting the crc to none and overwriting the header with it - pub async fn erase_data( - mut self, - flash: &mut S, - flash_range: Range, - cache: &mut impl PrivateCacheImpl, - address: u32, - ) -> Result> { - self.crc = None; - cache.notice_item_erased::(flash_range.clone(), address, &self); - self.write(flash, address).await?; - Ok(self) + async fn clear_data_crc(&self, flash: &mut S, address: u32) -> Result<(), Error> { + let buffer = AlignedBuf([0x0; MAX_WORD_SIZE]); + + flash + .write(address, &buffer[Self::DATA_CRC_FIELD]) + .await + .map_err(|e| Error::Storage { + value: e, + #[cfg(feature = "_test")] + backtrace: std::backtrace::Backtrace::capture(), + }) } /// Get the address of the start of the data for this item - pub const fn data_address(address: u32) -> u32 { + pub const fn data_address(address: u32) -> u32 { address + round_up_to_alignment::(Self::LENGTH as u32) } /// Get the location of the next item in flash - pub const fn next_item_address(&self, address: u32) -> u32 { - let data_address = ItemHeader::data_address::(address); + pub const fn next_item_address(&self, address: u32) -> u32 { + let data_address = Self::data_address(address); data_address + round_up_to_alignment::(self.length as u32) } /// Calculates the amount of bytes available for data. /// Essentially, it's the given amount minus the header and minus some alignment padding. - pub const fn available_data_bytes(total_available: u32) -> Option { - let data_start = Self::data_address::(0); + pub const fn available_data_bytes(total_available: u32) -> Option { + let data_start = Self::data_address(0); let data_end = round_down_to_alignment::(total_available); data_end.checked_sub(data_start) } } -pub struct Item<'d> { - pub header: ItemHeader, +impl ItemHeader { + /// Erase this item by setting the crc to none and overwriting the header with it + pub async fn erase_data( + mut self, + flash: &mut S, + flash_range: Range, + cache: &mut impl PrivateCacheImpl, + address: u32, + ) -> Result> { + self.crc = None; + cache.notice_item_erased::(flash_range.clone(), address, &self); + self.clear_data_crc(flash, address).await?; + Ok(self) + } +} + +pub struct Item<'d, S> { + pub header: ItemHeader, data_buffer: &'d mut [u8], } -impl<'d> Item<'d> { +impl<'d, S: NorFlash> Item<'d, S> { pub fn data(&self) -> &[u8] { &self.data_buffer[..self.header.length as usize] } @@ -213,20 +239,21 @@ impl<'d> Item<'d> { } /// Destruct the item to get back the full data buffer - pub fn destruct(self) -> (ItemHeader, &'d mut [u8]) { + pub fn destruct(self) -> (ItemHeader, &'d mut [u8]) { (self.header, self.data_buffer) } - pub async fn write_new( + pub async fn write_new( flash: &mut S, flash_range: Range, cache: &mut impl PrivateCacheImpl, address: u32, data: &'d [u8], - ) -> Result> { + ) -> Result, Error> { let header = ItemHeader { length: data.len() as u16, crc: Some(adapted_crc32(data)), + _p: PhantomData, }; Self::write_raw(flash, flash_range, cache, &header, data, address).await?; @@ -234,11 +261,11 @@ impl<'d> Item<'d> { Ok(header) } - async fn write_raw( + async fn write_raw( flash: &mut S, flash_range: Range, cache: &mut impl PrivateCacheImpl, - header: &ItemHeader, + header: &ItemHeader, data: &[u8], address: u32, ) -> Result<(), Error> { @@ -247,7 +274,7 @@ impl<'d> Item<'d> { let (data_block, data_left) = data.split_at(round_down_to_alignment_usize::(data.len())); - let data_address = ItemHeader::data_address::(address); + let data_address = ItemHeader::::data_address(address); flash .write(data_address, data_block) .await @@ -276,7 +303,7 @@ impl<'d> Item<'d> { Ok(()) } - pub async fn write( + pub async fn write( &self, flash: &mut S, flash_range: Range, @@ -294,7 +321,7 @@ impl<'d> Item<'d> { .await } - pub fn unborrow(self) -> ItemUnborrowed { + pub fn unborrow(self) -> ItemUnborrowed { ItemUnborrowed { header: self.header, data_buffer_len: self.data_buffer.len(), @@ -302,7 +329,7 @@ impl<'d> Item<'d> { } } -impl<'d> core::fmt::Debug for Item<'d> { +impl<'d, S: core::fmt::Debug> core::fmt::Debug for Item<'d, S> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Item") .field("header", &self.header) @@ -315,14 +342,14 @@ impl<'d> core::fmt::Debug for Item<'d> { } /// A version of [Item] that does not borrow the data. This is to circumvent the borrowchecker in some places. -pub struct ItemUnborrowed { - pub header: ItemHeader, +pub struct ItemUnborrowed { + pub header: ItemHeader, data_buffer_len: usize, } -impl ItemUnborrowed { +impl ItemUnborrowed { /// Reborrows the data. Watch out! Make sure the data buffer hasn't changed since unborrowing! - pub fn reborrow(self, data_buffer: &mut [u8]) -> Item<'_> { + pub fn reborrow(self, data_buffer: &mut [u8]) -> Item<'_, S> { Item { header: self.header, data_buffer: &mut data_buffer[..self.data_buffer_len], @@ -359,7 +386,7 @@ pub async fn find_next_free_item_spot( } }; - if let Some(available) = ItemHeader::available_data_bytes::(end_address - free_item_address) + if let Some(available) = ItemHeader::::available_data_bytes(end_address - free_item_address) { if available >= data_length { Ok(Some(free_item_address)) @@ -371,13 +398,13 @@ pub async fn find_next_free_item_spot( } } -pub enum MaybeItem<'d> { - Corrupted(ItemHeader, &'d mut [u8]), - Erased(ItemHeader, &'d mut [u8]), - Present(Item<'d>), +pub enum MaybeItem<'d, S> { + Corrupted(ItemHeader, &'d mut [u8]), + Erased(ItemHeader, &'d mut [u8]), + Present(Item<'d, S>), } -impl<'d> core::fmt::Debug for MaybeItem<'d> { +impl<'d, S: core::fmt::Debug> core::fmt::Debug for MaybeItem<'d, S> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Corrupted(arg0, arg1) => f @@ -391,8 +418,8 @@ impl<'d> core::fmt::Debug for MaybeItem<'d> { } } -impl<'d> MaybeItem<'d> { - pub fn unwrap(self) -> Result, Error> { +impl<'d, S> MaybeItem<'d, S> { + pub fn unwrap(self) -> Result, Error> { match self { MaybeItem::Corrupted(_, _) => Err(Error::Corrupted { #[cfg(feature = "_test")] @@ -521,7 +548,7 @@ impl ItemIter { &mut self, flash: &mut S, data_buffer: &'m mut [u8], - ) -> Result, u32)>, Error> { + ) -> Result, u32)>, Error> { let mut data_buffer = Some(data_buffer); while let (Some(header), address) = self.header.next(flash).await? { let buffer = data_buffer.take().unwrap(); @@ -558,7 +585,7 @@ impl ItemHeaderIter { pub async fn next( &mut self, flash: &mut S, - ) -> Result<(Option, u32), Error> { + ) -> Result<(Option>, u32), Error> { self.traverse(flash, |_, _| false).await } @@ -569,12 +596,12 @@ impl ItemHeaderIter { pub async fn traverse( &mut self, flash: &mut S, - callback: impl Fn(&ItemHeader, u32) -> bool, - ) -> Result<(Option, u32), Error> { + callback: impl Fn(&ItemHeader, u32) -> bool, + ) -> Result<(Option>, u32), Error> { loop { match ItemHeader::read_new(flash, self.current_address, self.end_address).await { Ok(Some(header)) => { - let next_address = header.next_item_address::(self.current_address); + let next_address = header.next_item_address(self.current_address); if callback(&header, self.current_address) { self.current_address = next_address; } else { @@ -587,7 +614,7 @@ impl ItemHeaderIter { return Ok((None, self.current_address)); } Err(Error::Corrupted { .. }) => { - self.current_address = ItemHeader::data_address::(self.current_address); + self.current_address = ItemHeader::::data_address(self.current_address); } Err(e) => return Err(e), } diff --git a/src/lib.rs b/src/lib.rs index 567c4ab..879a525 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ use core::{ fmt::Debug, ops::{Deref, DerefMut, Range}, }; -use embedded_storage_async::nor_flash::NorFlash; +use embedded_storage_async::nor_flash::{MultiwriteNorFlash, NorFlash}; use map::SerializationError; #[cfg(feature = "arrayvec")] @@ -32,6 +32,12 @@ pub mod mock_flash; /// Many flashes have 4-byte or 1-byte words. const MAX_WORD_SIZE: usize = 32; +// TODO: Move this to `embedded-storage`. +/// Marker trait that guarantees that a word can be cleared to all 0s. +pub trait WordclearNorFlash: NorFlash {} + +impl WordclearNorFlash for T where T: MultiwriteNorFlash {} + /// Resets the flash in the entire given flash range. /// /// This is just a thin helper function as it just calls the flash's erase function. @@ -54,7 +60,7 @@ pub async fn erase_all( /// The associated data of each item is additionally padded to a full flash word size, but that's not part of this number. /// This means the full item length is `returned number + (data length).next_multiple_of(S::WORD_SIZE)`. pub const fn item_overhead_size() -> u32 { - item::ItemHeader::data_address::(0) + item::ItemHeader::::data_address(0) } // Type representing buffer aligned to 4 byte boundary. diff --git a/src/map.rs b/src/map.rs index 5e7f59f..e7c53ae 100644 --- a/src/map.rs +++ b/src/map.rs @@ -97,8 +97,6 @@ //! For your convenience there are premade implementations for the [Key] and [Value] traits. //! -use embedded_storage_async::nor_flash::MultiwriteNorFlash; - use crate::item::{find_next_free_item_spot, Item, ItemHeader, ItemIter}; use self::{ @@ -161,7 +159,7 @@ async fn fetch_item_with_location<'d, K: Key, S: NorFlash>( cache: &mut impl PrivateKeyCacheImpl, data_buffer: &'d mut [u8], search_key: &K, -) -> Result)>, Error> { +) -> Result, u32, Option)>, Error> { assert_eq!(flash_range.start % S::ERASE_SIZE as u32, 0); assert_eq!(flash_range.end % S::ERASE_SIZE as u32, 0); assert!(flash_range.end - flash_range.start >= S::ERASE_SIZE as u32 * 2); @@ -415,7 +413,7 @@ async fn store_item_inner<'d, K: Key, S: NorFlash>( if item_data_length > u16::MAX as usize || item_data_length > calculate_page_size::() - .saturating_sub(ItemHeader::data_address::(0) as usize) + .saturating_sub(ItemHeader::::data_address(0) as usize) { cache.unmark_dirty(); return Err(Error::ItemTooBig); @@ -540,7 +538,7 @@ async fn store_item_inner<'d, K: Key, S: NorFlash>( /// Also watch out for using integers. This function will take any integer and it's easy to pass the wrong type. /// /// -pub async fn remove_item( +pub async fn remove_item( flash: &mut S, flash_range: Range, cache: &mut impl KeyCacheImpl, @@ -573,7 +571,7 @@ pub async fn remove_item( /// *multiple [Value] types. See the module-level docs for more information about this.* /// /// -pub async fn remove_all_items( +pub async fn remove_all_items( flash: &mut S, flash_range: Range, cache: &mut impl KeyCacheImpl, @@ -587,7 +585,7 @@ pub async fn remove_all_items( } /// If `search_key` is None, then all items will be removed -async fn remove_item_inner( +async fn remove_item_inner( flash: &mut S, flash_range: Range, cache: &mut impl KeyCacheImpl, @@ -908,9 +906,7 @@ async fn migrate_items( found_item .write(flash, flash_range.clone(), cache, next_page_write_address) .await?; - next_page_write_address = found_item - .header - .next_item_address::(next_page_write_address); + next_page_write_address = found_item.header.next_item_address(next_page_write_address); } } diff --git a/src/mock_flash.rs b/src/mock_flash.rs index 427fc59..a53d9fb 100644 --- a/src/mock_flash.rs +++ b/src/mock_flash.rs @@ -1,6 +1,6 @@ use core::ops::{Add, AddAssign, Range}; use embedded_storage_async::nor_flash::{ - ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, + ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, }; /// State of a word in the flash. @@ -16,6 +16,8 @@ enum Writable { use Writable::*; +use crate::WordclearNorFlash; + /// Base type for in memory flash that can be used for mocking. #[derive(Debug, Clone)] pub struct MockFlashBase { @@ -154,7 +156,7 @@ impl let mut it = crate::item::ItemHeaderIter::new(page_data_start, page_data_end); while let (Some(header), item_address) = it.traverse(self, |_, _| false).await.unwrap() { - let next_item_address = header.next_item_address::(item_address); + let next_item_address = header.next_item_address(item_address); let maybe_item = header .read_item(self, &mut buf, item_address, page_data_end) .await @@ -198,7 +200,7 @@ impl let mut found_item = None; let mut it = crate::item::ItemHeaderIter::new(page_data_start, page_data_end); while let (Some(header), item_address) = it.traverse(self, |_, _| false).await.unwrap() { - let next_item_address = header.next_item_address::(item_address); + let next_item_address = header.next_item_address(item_address); if (item_address..next_item_address).contains(&target_item_address) { let maybe_item = header @@ -255,7 +257,7 @@ impl R } } -impl MultiwriteNorFlash +impl WordclearNorFlash for MockFlashBase { } diff --git a/src/queue.rs b/src/queue.rs index a56d965..3d39c98 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -60,7 +60,6 @@ use crate::item::{find_next_free_item_spot, is_page_empty, Item, ItemHeader, Ite use self::{cache::CacheImpl, item::ItemUnborrowed}; use super::*; -use embedded_storage_async::nor_flash::MultiwriteNorFlash; /// Push data into the queue in the given flash memory with the given range. /// The data can only be taken out with the [pop] function. @@ -110,7 +109,7 @@ async fn push_inner( // Data must fit in a single page if data.len() > u16::MAX as usize || data.len() - > calculate_page_size::().saturating_sub(ItemHeader::data_address::(0) as usize) + > calculate_page_size::().saturating_sub(ItemHeader::::data_address(0) as usize) { cache.unmark_dirty(); return Err(Error::ItemTooBig); @@ -242,7 +241,7 @@ pub async fn peek<'d, S: NorFlash>( /// You should not depend on that data. /// /// If the data buffer is not big enough an error is returned. -pub async fn pop<'d, S: MultiwriteNorFlash>( +pub async fn pop<'d, S: WordclearNorFlash>( flash: &mut S, flash_range: Range, cache: &mut impl CacheImpl, @@ -353,7 +352,7 @@ impl<'s, S: NorFlash, CI: CacheImpl> QueueIterator<'s, S, CI> { async fn next_inner( &mut self, data_buffer: &mut [u8], - ) -> Result, Error> { + ) -> Result, u32)>, Error> { let mut data_buffer = Some(data_buffer); if self.cache.is_dirty() { @@ -421,7 +420,7 @@ impl<'s, S: NorFlash, CI: CacheImpl> QueueIterator<'s, S, CI> { match maybe_item { item::MaybeItem::Corrupted(header, db) => { - let next_address = header.next_item_address::(found_item_address); + let next_address = header.next_item_address(found_item_address); self.next_address = if next_address >= page_data_end_address { NextAddress::PageAfter(current_page) } else { @@ -431,7 +430,7 @@ impl<'s, S: NorFlash, CI: CacheImpl> QueueIterator<'s, S, CI> { } item::MaybeItem::Erased(_, _) => unreachable!("Item is already erased"), item::MaybeItem::Present(item) => { - let next_address = item.header.next_item_address::(found_item_address); + let next_address = item.header.next_item_address(found_item_address); self.next_address = if next_address >= page_data_end_address { NextAddress::PageAfter(current_page) } else { @@ -453,7 +452,7 @@ impl<'s, S: NorFlash, CI: CacheImpl> QueueIterator<'s, S, CI> { pub struct QueueIteratorEntry<'s, 'd, 'q, S: NorFlash, CI: CacheImpl> { iter: &'q mut QueueIterator<'s, S, CI>, address: u32, - item: Item<'d>, + item: Item<'d, S>, } impl<'s, 'd, 'q, S: NorFlash, CI: CacheImpl> Deref for QueueIteratorEntry<'s, 'd, 'q, S, CI> { @@ -482,7 +481,7 @@ impl<'s, 'd, 'q, S: NorFlash, CI: CacheImpl> QueueIteratorEntry<'s, 'd, 'q, S, C /// future peeks won't find this data anymore. pub async fn pop(self) -> Result<&'d mut [u8], Error> where - S: MultiwriteNorFlash, + S: WordclearNorFlash, { let (header, data_buffer) = self.item.destruct(); let ret = &mut data_buffer[..header.length as usize]; @@ -579,7 +578,7 @@ async fn find_max_fit_inner( }; cache.unmark_dirty(); - Ok(ItemHeader::available_data_bytes::( + Ok(ItemHeader::::available_data_bytes( page_data_end_address - next_item_address, )) } @@ -657,7 +656,7 @@ async fn space_left_inner( } }; - if ItemHeader::available_data_bytes::(page_data_end_address - next_item_address) + if ItemHeader::::available_data_bytes(page_data_end_address - next_item_address) .is_none() { // No data fits on this partial open page anymore. @@ -1237,7 +1236,7 @@ mod tests { avg_reads: 8.0188, avg_writes: 1.0, avg_bytes_read: 96.4224, - avg_bytes_written: 8.0 + avg_bytes_written: 4.0 } ); } @@ -1347,7 +1346,7 @@ mod tests { avg_reads: 82.618, avg_writes: 1.0, avg_bytes_read: 567.9904, - avg_bytes_written: 8.0 + avg_bytes_written: 4.0 } ); }