sequential_storage/cache/
mod.rs1use core::{fmt::Debug, ops::Range};
4
5use embedded_storage_async::nor_flash::NorFlash;
6
7use crate::{PageState, item::ItemHeader, map::Key};
8
9use self::{
10 key_pointers::{KeyPointersCache, UncachedKeyPointers},
11 page_pointers::UncachedPagePointers,
12 page_states::UncachedPageStates,
13};
14
15pub(crate) mod array_impl;
16#[cfg(feature = "alloc")]
17pub(crate) mod heap_impl;
18pub(crate) mod key_pointers;
19pub(crate) mod page_pointers;
20pub(crate) mod page_states;
21
22mod tests;
23
24pub use array_impl::*;
25#[cfg(feature = "alloc")]
26pub use heap_impl::*;
27pub(crate) use page_pointers::PagePointersCache;
28pub(crate) use page_states::PageStatesCache;
29
30#[allow(private_bounds)]
32pub trait CacheImpl: PrivateCacheImpl {}
33
34#[allow(private_bounds)]
36pub trait KeyCacheImpl<KEY: Key>: CacheImpl + PrivateKeyCacheImpl<KEY> {}
37
38pub(crate) trait Invalidate {
39 fn invalidate_cache_state(&mut self);
40}
41
42pub(crate) trait PrivateCacheImpl: Invalidate {
43 type PSC<'a>: PageStatesCache
44 where
45 Self: 'a;
46 type PPC<'a>: PagePointersCache
47 where
48 Self: 'a;
49
50 fn dirt_tracker<R>(&mut self, f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R>;
51 fn page_states(&mut self) -> Self::PSC<'_>;
52 fn page_pointers(&mut self) -> Self::PPC<'_>;
53
54 fn is_dirty(&mut self) -> bool {
56 self.dirt_tracker(|d| d.is_dirty()).unwrap_or_default()
57 }
58
59 fn mark_dirty(&mut self) {
61 self.dirt_tracker(DirtTracker::mark_dirty);
62 }
63
64 fn unmark_dirty(&mut self) {
66 self.dirt_tracker(DirtTracker::unmark_dirty);
67 }
68
69 fn get_page_state(&mut self, page_index: usize) -> Option<PageState> {
71 self.page_states().get_page_state(page_index)
72 }
73
74 fn notice_page_state(&mut self, page_index: usize, new_state: PageState, dirty: bool) {
79 if dirty {
80 self.mark_dirty();
81 }
82 self.page_states().notice_page_state(page_index, new_state);
83 self.page_pointers()
84 .notice_page_state(page_index, new_state);
85 }
86
87 fn first_item_after_erased(&mut self, page_index: usize) -> Option<u32> {
91 self.page_pointers().first_item_after_erased(page_index)
92 }
93
94 fn first_item_after_written(&mut self, page_index: usize) -> Option<u32> {
96 self.page_pointers().first_item_after_written(page_index)
97 }
98
99 fn notice_item_written<S: NorFlash>(
101 &mut self,
102 flash_range: Range<u32>,
103 item_address: u32,
104 item_header: &ItemHeader,
105 ) {
106 self.mark_dirty();
107 self.page_pointers()
108 .notice_item_written::<S>(flash_range, item_address, item_header);
109 }
110
111 fn notice_item_erased<S: NorFlash>(
113 &mut self,
114 flash_range: Range<u32>,
115 item_address: u32,
116 item_header: &ItemHeader,
117 ) {
118 self.mark_dirty();
119 self.page_pointers()
120 .notice_item_erased::<S>(flash_range, item_address, item_header);
121 }
122}
123
124pub(crate) trait PrivateKeyCacheImpl<KEY: Key>: PrivateCacheImpl {
125 type KPC<'a>: KeyPointersCache<KEY>
126 where
127 Self: 'a;
128
129 fn key_pointers(&mut self) -> Self::KPC<'_>;
130
131 fn key_location(&mut self, key: &KEY) -> Option<u32> {
132 self.key_pointers().key_location(key)
133 }
134
135 fn notice_key_location(&mut self, key: &KEY, item_address: u32, dirty: bool) {
136 if dirty {
137 self.mark_dirty();
138 }
139 self.key_pointers().notice_key_location(key, item_address);
140 }
141 #[allow(unused)]
142 fn notice_key_erased(&mut self, key: &KEY) {
143 self.mark_dirty();
144 self.key_pointers().notice_key_erased(key);
145 }
146}
147
148#[derive(Debug)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150pub(crate) struct DirtTracker {
151 dirty: bool,
156}
157
158impl DirtTracker {
159 pub const fn new() -> Self {
160 DirtTracker { dirty: false }
161 }
162
163 pub fn is_dirty(&self) -> bool {
165 self.dirty
166 }
167
168 pub fn mark_dirty(&mut self) {
170 self.dirty = true;
171 }
172
173 pub fn unmark_dirty(&mut self) {
175 self.dirty = false;
176 }
177}
178
179#[derive(Debug)]
184#[cfg_attr(feature = "defmt", derive(defmt::Format))]
185pub struct NoCache;
186
187impl NoCache {
188 #[must_use]
190 pub const fn new() -> Self {
191 Self
192 }
193}
194
195impl Default for NoCache {
196 fn default() -> Self {
197 Self::new()
198 }
199}
200
201impl PrivateCacheImpl for NoCache {
202 type PSC<'a>
203 = UncachedPageStates
204 where
205 Self: 'a;
206 type PPC<'a>
207 = UncachedPagePointers
208 where
209 Self: 'a;
210
211 fn dirt_tracker<R>(&mut self, _f: impl FnOnce(&mut DirtTracker) -> R) -> Option<R> {
212 None
214 }
215
216 fn page_states(&mut self) -> Self::PSC<'_> {
217 UncachedPageStates
218 }
219
220 fn page_pointers(&mut self) -> Self::PPC<'_> {
221 UncachedPagePointers
222 }
223}
224
225impl CacheImpl for NoCache {}
226impl<KEY: Key> KeyCacheImpl<KEY> for NoCache {}
227
228impl Invalidate for NoCache {
229 fn invalidate_cache_state(&mut self) {}
230}
231
232impl<KEY: Key> PrivateKeyCacheImpl<KEY> for NoCache {
233 type KPC<'a>
234 = UncachedKeyPointers
235 where
236 Self: 'a;
237
238 fn key_pointers(&mut self) -> Self::KPC<'_> {
239 UncachedKeyPointers
240 }
241}