use core::{fmt::Debug, ops::Range};
use embedded_storage_async::nor_flash::NorFlash;
use crate::{PageState, item::ItemHeader, map::Key};
use self::{
key_pointers::{KeyPointersCache, UncachedKeyPointers},
page_pointers::UncachedPagePointers,
page_states::UncachedPageStates,
};
pub(crate) mod array_impl;
#[cfg(feature = "alloc")]
pub(crate) mod heap_impl;
pub(crate) mod key_pointers;
pub(crate) mod page_pointers;
pub(crate) mod page_states;
mod tests;
pub use array_impl::*;
#[cfg(feature = "alloc")]
pub use heap_impl::*;
pub(crate) use page_pointers::PagePointersCache;
pub(crate) use page_states::PageStatesCache;
#[allow(private_bounds)]
pub trait CacheImpl: PrivateCacheImpl {}
#[allow(private_bounds)]
pub trait KeyCacheImpl<KEY: Key>: CacheImpl + PrivateKeyCacheImpl<KEY> {}
pub(crate) trait Invalidate {
fn invalidate_cache_state(&mut self);
}
pub(crate) trait PrivateCacheImpl: Invalidate {
type PSC<'a>: PageStatesCache
where
Self: 'a;
type PPC<'a>: PagePointersCache
where
Self: 'a;
fn dirt_tracker<R>(&mut self, f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R>;
fn page_states(&mut self) -> Self::PSC<'_>;
fn page_pointers(&mut self) -> Self::PPC<'_>;
fn is_dirty(&mut self) -> bool {
self.dirt_tracker(|d| d.is_dirty()).unwrap_or_default()
}
fn mark_dirty(&mut self) {
self.dirt_tracker(DirtTracker::mark_dirty);
}
fn unmark_dirty(&mut self) {
self.dirt_tracker(DirtTracker::unmark_dirty);
}
fn get_page_state(&mut self, page_index: usize) -> Option<PageState> {
self.page_states().get_page_state(page_index)
}
fn notice_page_state(&mut self, page_index: usize, new_state: PageState, dirty: bool) {
if dirty {
self.mark_dirty();
}
self.page_states().notice_page_state(page_index, new_state);
self.page_pointers()
.notice_page_state(page_index, new_state);
}
fn first_item_after_erased(&mut self, page_index: usize) -> Option<u32> {
self.page_pointers().first_item_after_erased(page_index)
}
fn first_item_after_written(&mut self, page_index: usize) -> Option<u32> {
self.page_pointers().first_item_after_written(page_index)
}
fn notice_item_written<S: NorFlash>(
&mut self,
flash_range: Range<u32>,
item_address: u32,
item_header: &ItemHeader,
) {
self.mark_dirty();
self.page_pointers()
.notice_item_written::<S>(flash_range, item_address, item_header);
}
fn notice_item_erased<S: NorFlash>(
&mut self,
flash_range: Range<u32>,
item_address: u32,
item_header: &ItemHeader,
) {
self.mark_dirty();
self.page_pointers()
.notice_item_erased::<S>(flash_range, item_address, item_header);
}
}
pub(crate) trait PrivateKeyCacheImpl<KEY: Key>: PrivateCacheImpl {
type KPC<'a>: KeyPointersCache<KEY>
where
Self: 'a;
fn key_pointers(&mut self) -> Self::KPC<'_>;
fn key_location(&mut self, key: &KEY) -> Option<u32> {
self.key_pointers().key_location(key)
}
fn notice_key_location(&mut self, key: &KEY, item_address: u32, dirty: bool) {
if dirty {
self.mark_dirty();
}
self.key_pointers().notice_key_location(key, item_address);
}
#[allow(unused)]
fn notice_key_erased(&mut self, key: &KEY) {
self.mark_dirty();
self.key_pointers().notice_key_erased(key);
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct DirtTracker {
dirty: bool,
}
impl DirtTracker {
pub const fn new() -> Self {
DirtTracker { dirty: false }
}
pub fn is_dirty(&self) -> bool {
self.dirty
}
pub fn mark_dirty(&mut self) {
self.dirty = true;
}
pub fn unmark_dirty(&mut self) {
self.dirty = false;
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct NoCache;
impl NoCache {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl Default for NoCache {
fn default() -> Self {
Self::new()
}
}
impl PrivateCacheImpl for NoCache {
type PSC<'a>
= UncachedPageStates
where
Self: 'a;
type PPC<'a>
= UncachedPagePointers
where
Self: 'a;
fn dirt_tracker<R>(&mut self, _f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R> {
None
}
fn page_states(&mut self) -> Self::PSC<'_> {
UncachedPageStates
}
fn page_pointers(&mut self) -> Self::PPC<'_> {
UncachedPagePointers
}
}
impl CacheImpl for NoCache {}
impl<KEY: Key> KeyCacheImpl<KEY> for NoCache {}
impl Invalidate for NoCache {
fn invalidate_cache_state(&mut self) {}
}
impl<KEY: Key> PrivateKeyCacheImpl<KEY> for NoCache {
type KPC<'a>
= UncachedKeyPointers
where
Self: 'a;
fn key_pointers(&mut self) -> Self::KPC<'_> {
UncachedKeyPointers
}
}