diff --git a/Cargo.toml b/Cargo.toml index 2fb06c3..06c50be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ defmt = ["dep:defmt"] std = [] # Enable the implementation of the map Key trait for ArrayVec and ArrayString arrayvec = ["dep:arrayvec"] -alloc = [] +alloc = ["defmt/alloc"] heapless = ["dep:heapless"] heapless-09 = ["dep:heapless-09"] _test = ["dep:futures", "dep:approx", "std", "arrayvec", "alloc", "heapless"] diff --git a/src/cache/key_pointers.rs b/src/cache/key_pointers.rs index 6abacad..d598117 100644 --- a/src/cache/key_pointers.rs +++ b/src/cache/key_pointers.rs @@ -2,6 +2,8 @@ use core::{fmt::Debug, num::NonZeroU32}; use crate::map::Key; +use super::list::List; + pub(crate) trait KeyPointersCache { fn key_location(&self, key: &KEY) -> Option; @@ -14,7 +16,7 @@ pub(crate) trait KeyPointersCache { #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) struct CachedKeyPointers { - key_pointers: [Option<(KEY, NonZeroU32)>; KEYS], + key_pointers: List, KEYS>, } impl CachedKeyPointers { @@ -22,12 +24,23 @@ impl CachedKeyPointers { pub(crate) const fn new() -> Self { Self { - key_pointers: [Self::ARRAY_REPEAT_VALUE; KEYS], + key_pointers: List::Arr([Self::ARRAY_REPEAT_VALUE; KEYS]), + } + } + + #[cfg(feature = "alloc")] + pub(crate) fn new_heap(n: usize) -> Self + where + KEY: Clone, + { + Self { + key_pointers: List::from_elem_vec(Self::ARRAY_REPEAT_VALUE, n), } } fn key_index(&self, key: &KEY) -> Option { self.key_pointers + .as_slice() .iter() .enumerate() .filter_map(|(index, val)| val.as_ref().map(|val| (index, val))) @@ -39,8 +52,9 @@ impl CachedKeyPointers { } fn insert_front(&mut self, value: (KEY, NonZeroU32)) { - self.key_pointers[KEYS - 1] = Some(value); - move_to_front(&mut self.key_pointers, KEYS - 1); + let keys = self.key_pointers.len(); + self.key_pointers[keys - 1] = Some(value); + move_to_front(self.key_pointers.as_mut_slice(), keys - 1); } } @@ -55,7 +69,7 @@ impl KeyPointersCache for CachedKeyPointers { self.key_pointers[existing_index] = Some((key.clone(), NonZeroU32::new(item_address).unwrap())); - move_to_front(&mut self.key_pointers, existing_index); + move_to_front(self.key_pointers.as_mut_slice(), existing_index); } None => self.insert_front((key.clone(), NonZeroU32::new(item_address).unwrap())), } @@ -64,12 +78,12 @@ impl KeyPointersCache for CachedKeyPointers { + Arr([T; N]), + #[cfg(feature = "alloc")] + BS(Box<[T]>), +} + +impl List { + #[allow(unused)] + pub fn from_elem(elem: T, list_kind: ListKind) -> Self + where + T: Copy, + { + match list_kind { + ListKind::Arr => Self::Arr([elem; N]), + #[cfg(feature = "alloc")] + ListKind::BS(n) => Self::BS(vec![elem; n].into()), + } + } + + #[cfg(feature = "alloc")] + pub fn from_elem_vec(elem: T, n: usize) -> Self + where + T: Clone, + { + Self::BS(vec![elem; n].into()) + } + + pub const fn from_elem_arr(elem: T) -> Self + where + T: Copy, + { + Self::Arr([elem; N]) + } + + pub fn as_slice(&self) -> &[T] { + match self { + Self::Arr(a) => &a[..], + #[cfg(feature = "alloc")] + Self::BS(bs) => bs, + } + } + + pub fn as_mut_slice(&mut self) -> &mut [T] { + match self { + Self::Arr(a) => &mut a[..], + #[cfg(feature = "alloc")] + Self::BS(bs) => bs, + } + } + + pub fn len(&self) -> usize { + match self { + Self::Arr(_) => N, + #[cfg(feature = "alloc")] + List::BS(bs) => bs.len(), + } + } +} + +impl core::ops::Index for List { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + match self { + Self::Arr(a) => a.index(index), + #[cfg(feature = "alloc")] + Self::BS(bs) => bs.index(index), + } + } +} + +impl core::ops::IndexMut for List { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match self { + Self::Arr(a) => a.index_mut(index), + #[cfg(feature = "alloc")] + Self::BS(bs) => bs.index_mut(index), + } + } +} diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 837f9ad..8832569 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -12,6 +12,8 @@ use self::{ page_states::{CachedPageStates, UncachedPageStates}, }; +pub(crate) mod list; + pub(crate) mod key_pointers; pub(crate) mod page_pointers; pub(crate) mod page_states; @@ -286,6 +288,17 @@ impl PageStateCache { key_pointers: UncachedKeyPointers, } } + + /// Construct a new instance on the heap, generics are discarded + #[cfg(feature = "alloc")] + pub fn new_heap(page_count: usize) -> Self { + Self { + dirt_tracker: DirtTracker::new(), + page_states: CachedPageStates::new_heap(page_count), + page_pointers: UncachedPagePointers, + key_pointers: UncachedKeyPointers, + } + } } impl Default for PageStateCache { @@ -360,6 +373,17 @@ impl PagePointerCache { key_pointers: UncachedKeyPointers, } } + + /// Construct a new instance on the heap, generics are discarded + #[cfg(feature = "alloc")] + pub fn new_heap(page_count: usize) -> Self { + Self { + dirt_tracker: DirtTracker::new(), + page_states: CachedPageStates::new_heap(page_count), + page_pointers: CachedPagePointers::new_heap(page_count), + key_pointers: UncachedKeyPointers, + } + } } impl Default for PagePointerCache { @@ -439,6 +463,17 @@ impl KeyPointerCache Self { + Self { + dirt_tracker: DirtTracker::new(), + page_states: CachedPageStates::new_heap(page_count), + page_pointers: CachedPagePointers::new_heap(page_count), + key_pointers: CachedKeyPointers::new_heap(keys), + } + } } impl Default diff --git a/src/cache/page_pointers.rs b/src/cache/page_pointers.rs index 81b3bbf..0afba72 100644 --- a/src/cache/page_pointers.rs +++ b/src/cache/page_pointers.rs @@ -6,6 +6,8 @@ use crate::{ NorFlashExt, PageState, calculate_page_address, calculate_page_index, item::ItemHeader, }; +use super::list::List; + pub(crate) trait PagePointersCache: Debug { fn first_item_after_erased(&self, page_index: usize) -> Option; fn first_item_after_written(&self, page_index: usize) -> Option; @@ -31,14 +33,14 @@ pub(crate) trait PagePointersCache: Debug { // and so Option can make use of the niche so we save bytes #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) struct CachedPagePointers { - after_erased_pointers: [Option; PAGE_COUNT], - after_written_pointers: [Option; PAGE_COUNT], + after_erased_pointers: List, PAGE_COUNT>, + after_written_pointers: List, PAGE_COUNT>, } impl Debug for CachedPagePointers { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{{ after_erased_pointers: [")?; - for (i, val) in self.after_erased_pointers.iter().enumerate() { + for (i, val) in self.after_erased_pointers.as_slice().iter().enumerate() { if i > 0 { write!(f, ", ")?; } @@ -50,7 +52,7 @@ impl Debug for CachedPagePointers { } } write!(f, "], after_written_pointers: [")?; - for (i, val) in self.after_written_pointers.iter().enumerate() { + for (i, val) in self.after_written_pointers.as_slice().iter().enumerate() { if i > 0 { write!(f, ", ")?; } @@ -70,8 +72,16 @@ impl Debug for CachedPagePointers { impl CachedPagePointers { pub const fn new() -> Self { Self { - after_erased_pointers: [None; PAGE_COUNT], - after_written_pointers: [None; PAGE_COUNT], + after_erased_pointers: List::from_elem_arr(None), + after_written_pointers: List::from_elem_arr(None), + } + } + + #[cfg(feature = "alloc")] + pub fn new_heap(n: usize) -> Self { + Self { + after_erased_pointers: List::from_elem_vec(None, n), + after_written_pointers: List::from_elem_vec(None, n), } } } @@ -133,8 +143,8 @@ impl PagePointersCache for CachedPagePointers Option; @@ -10,13 +11,13 @@ pub(crate) trait PageStatesCache: Debug { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) struct CachedPageStates { - pages: [Option; PAGE_COUNT], + pages: List, PAGE_COUNT>, } impl Debug for CachedPageStates { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "[")?; - for (i, val) in self.pages.iter().enumerate() { + for (i, val) in self.pages.as_slice().iter().enumerate() { if i > 0 { write!(f, ", ")?; } @@ -36,7 +37,14 @@ impl Debug for CachedPageStates { impl CachedPageStates { pub const fn new() -> Self { Self { - pages: [None; PAGE_COUNT], + pages: List::from_elem_arr(None), + } + } + + #[cfg(feature = "alloc")] + pub fn new_heap(n: usize) -> Self { + Self { + pages: List::from_elem_vec(None, n), } } } @@ -51,7 +59,7 @@ impl PageStatesCache for CachedPageStates { } fn invalidate_cache_state(&mut self) { - *self = Self::new(); + self.pages.as_mut_slice().fill(None); } } diff --git a/src/lib.rs b/src/lib.rs index c9b29af..589f085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,8 @@ use core::{ use embedded_storage_async::nor_flash::NorFlash; use map::SerializationError; +#[cfg(feature = "alloc")] +extern crate alloc; #[cfg(feature = "alloc")] mod alloc_impl; #[cfg(feature = "arrayvec")]