sequential_storage/cache/
mod.rs1use core::marker::PhantomData;
4use core::{fmt::Debug, ops::Range};
5
6use embedded_storage_async::nor_flash::NorFlash;
7
8use crate::cache::key_pointers::KeyPointersCache;
9use crate::cache::page_pointers::SealedPagePointersCache;
10use crate::cache::page_states::SealedPageStatesCache;
11use crate::{PageState, item::ItemHeader};
12
13use key_pointers::SealedKeyPointersCache;
14use page_pointers::PagePointersCache;
15use page_states::PageStatesCache;
16
17pub mod key_pointers;
18pub mod page_pointers;
19pub mod page_states;
20
21mod tests;
22
23pub(crate) trait SealedCacheImpl {
25 fn is_dirty(&mut self) -> bool;
27 fn mark_dirty(&mut self);
29 fn unmark_dirty(&mut self);
31
32 fn get_page_state(&mut self, page_index: usize) -> Option<PageState>;
34 fn notice_page_state(&mut self, page_index: usize, new_state: PageState, dirty: bool);
39
40 fn first_item_after_erased(&mut self, page_index: usize) -> Option<u32>;
44 fn first_item_after_written(&mut self, page_index: usize) -> Option<u32>;
46 fn notice_item_written<S: NorFlash>(
48 &mut self,
49 flash_range: Range<u32>,
50 item_address: u32,
51 item_header: &ItemHeader,
52 );
53 fn notice_item_erased<S: NorFlash>(
55 &mut self,
56 flash_range: Range<u32>,
57 item_address: u32,
58 item_header: &ItemHeader,
59 );
60 fn invalidate_cache_state(&mut self);
62}
63pub(crate) trait SealedKeyCacheImpl<KEY> {
64 fn key_location(&mut self, key: &KEY) -> Option<u32>;
66 fn notice_key_location(&mut self, key: &KEY, item_address: u32, dirty: bool);
68 fn notice_key_erased(&mut self, key: &KEY);
70}
71
72#[allow(private_bounds)]
73pub trait CacheImpl<KEY>: SealedCacheImpl + SealedKeyCacheImpl<KEY> {}
76
77#[derive(Debug)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91pub struct Cache<
92 PAGE: PageStatesCache,
93 POINTERS: PagePointersCache,
94 KEYS: KeyPointersCache<KEY>,
95 KEY = (),
96> {
97 dirt_tracker: DirtTracker,
98 page_states: PAGE,
99 page_pointers: POINTERS,
100 key_pointers: KEYS,
101 _phantom: PhantomData<KEY>,
102}
103
104impl<PAGE: PageStatesCache, POINTERS: PagePointersCache, KEYS: KeyPointersCache<KEY>, KEY>
105 Cache<PAGE, POINTERS, KEYS, KEY>
106{
107 pub fn new(page_states: PAGE, page_pointers: POINTERS, key_pointers: KEYS) -> Self {
109 Self {
110 dirt_tracker: DirtTracker::new(),
111 page_states,
112 page_pointers,
113 key_pointers,
114 _phantom: PhantomData,
115 }
116 }
117}
118
119impl<KEY> Cache<Uncached, Uncached, Uncached, KEY> {
120 pub const fn new_uncached() -> Self {
122 Self {
123 dirt_tracker: DirtTracker::new(),
124 page_states: Uncached,
125 page_pointers: Uncached,
126 key_pointers: Uncached,
127 _phantom: PhantomData,
128 }
129 }
130}
131
132impl<PAGE: PageStatesCache, POINTERS: PagePointersCache, KEYS: KeyPointersCache<KEY>, KEY>
133 SealedCacheImpl for Cache<PAGE, POINTERS, KEYS, KEY>
134{
135 fn is_dirty(&mut self) -> bool {
137 self.dirt_tracker.is_dirty()
138 }
139
140 fn mark_dirty(&mut self) {
142 self.dirt_tracker.mark_dirty();
143 }
144
145 fn unmark_dirty(&mut self) {
147 self.dirt_tracker.unmark_dirty();
148 }
149
150 fn get_page_state(&mut self, page_index: usize) -> Option<PageState> {
152 self.page_states.get_page_state(page_index)
153 }
154
155 fn notice_page_state(&mut self, page_index: usize, new_state: PageState, dirty: bool) {
160 if dirty {
161 self.mark_dirty();
162 }
163 self.page_states.notice_page_state(page_index, new_state);
164 self.page_pointers.notice_page_state(page_index, new_state);
165 }
166
167 fn first_item_after_erased(&mut self, page_index: usize) -> Option<u32> {
171 self.page_pointers.first_item_after_erased(page_index)
172 }
173
174 fn first_item_after_written(&mut self, page_index: usize) -> Option<u32> {
176 self.page_pointers.first_item_after_written(page_index)
177 }
178
179 fn notice_item_written<S: NorFlash>(
181 &mut self,
182 flash_range: Range<u32>,
183 item_address: u32,
184 item_header: &ItemHeader,
185 ) {
186 self.mark_dirty();
187 self.page_pointers
188 .notice_item_written::<S>(flash_range, item_address, item_header);
189 }
190
191 fn notice_item_erased<S: NorFlash>(
193 &mut self,
194 flash_range: Range<u32>,
195 item_address: u32,
196 item_header: &ItemHeader,
197 ) {
198 self.mark_dirty();
199 self.page_pointers
200 .notice_item_erased::<S>(flash_range, item_address, item_header);
201 }
202
203 fn invalidate_cache_state(&mut self) {
204 self.dirt_tracker.unmark_dirty();
205 self.page_states.invalidate_cache_state();
206 self.page_pointers.invalidate_cache_state();
207 self.key_pointers.invalidate_cache_state();
208 }
209}
210
211impl<PAGE: PageStatesCache, POINTERS: PagePointersCache, KEYS: KeyPointersCache<KEY>, KEY>
212 SealedKeyCacheImpl<KEY> for Cache<PAGE, POINTERS, KEYS, KEY>
213{
214 fn key_location(&mut self, key: &KEY) -> Option<u32> {
215 self.key_pointers.key_location(key)
216 }
217
218 fn notice_key_location(&mut self, key: &KEY, item_address: u32, dirty: bool) {
219 if dirty {
220 self.mark_dirty();
221 }
222 self.key_pointers.notice_key_location(key, item_address);
223 }
224
225 fn notice_key_erased(&mut self, key: &KEY) {
226 self.mark_dirty();
227 self.key_pointers.notice_key_erased(key);
228 }
229}
230
231impl<PAGE: PageStatesCache, POINTERS: PagePointersCache, KEYS: KeyPointersCache<KEY>, KEY>
232 CacheImpl<KEY> for Cache<PAGE, POINTERS, KEYS, KEY>
233{
234}
235
236#[derive(Debug)]
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub(crate) struct DirtTracker {
239 dirty: bool,
244}
245
246impl DirtTracker {
247 pub const fn new() -> Self {
248 DirtTracker { dirty: false }
249 }
250
251 pub fn is_dirty(&self) -> bool {
253 self.dirty
254 }
255
256 pub fn mark_dirty(&mut self) {
258 self.dirty = true;
259 }
260
261 pub fn unmark_dirty(&mut self) {
263 self.dirty = false;
264 }
265}
266
267#[derive(Debug)]
269#[cfg_attr(feature = "defmt", derive(defmt::Format))]
270pub struct Uncached;
271
272impl SealedPageStatesCache for Uncached {
273 fn get_page_state(&self, _page_index: usize) -> Option<PageState> {
274 None
275 }
276 fn notice_page_state(&mut self, _page_index: usize, _new_state: PageState) {}
277 fn invalidate_cache_state(&mut self) {}
278}
279impl PageStatesCache for Uncached {}
280
281impl SealedPagePointersCache for Uncached {
282 fn first_item_after_erased(&self, _page_index: usize) -> Option<u32> {
283 None
284 }
285 fn first_item_after_written(&self, _page_index: usize) -> Option<u32> {
286 None
287 }
288 fn notice_item_written<S: NorFlash>(
289 &mut self,
290 _flash_range: Range<u32>,
291 _item_address: u32,
292 _item_header: &ItemHeader,
293 ) {
294 }
295 fn notice_item_erased<S: NorFlash>(
296 &mut self,
297 _flash_range: Range<u32>,
298 _item_address: u32,
299 _item_header: &ItemHeader,
300 ) {
301 }
302 fn notice_page_state(&mut self, _page_index: usize, _new_state: PageState) {}
303 fn invalidate_cache_state(&mut self) {}
304}
305impl PagePointersCache for Uncached {}
306
307impl<KEY> SealedKeyPointersCache<KEY> for Uncached {
308 fn key_location(&self, _key: &KEY) -> Option<u32> {
309 None
310 }
311 fn notice_key_location(&mut self, _key: &KEY, _item_address: u32) {}
312 fn notice_key_erased(&mut self, _key: &KEY) {}
313 fn invalidate_cache_state(&mut self) {}
314}
315impl<KEY> KeyPointersCache<KEY> for Uncached {}