1use core::{marker::PhantomData, mem::size_of};
4use embedded_storage_async::nor_flash::MultiwriteNorFlash;
5
6#[cfg(feature = "postcard")]
7use serde::{Deserialize, Serialize};
8
9use crate::{
10 cache::CacheImpl,
11 item::{Item, ItemHeader, ItemIter},
12};
13
14use self::item::{ItemHeaderIter, ItemUnborrowed};
15
16use super::{
17 Debug, Error, GenericStorage, MAX_WORD_SIZE, NorFlash, NorFlashExt, PageState, Range,
18 calculate_page_address, calculate_page_end_address, calculate_page_index, calculate_page_size,
19 item, run_with_auto_repair,
20};
21
22pub struct MapConfig<S> {
24 flash_range: Range<u32>,
25 _phantom: PhantomData<S>,
26}
27
28impl<S: NorFlash> MapConfig<S> {
29 #[must_use]
32 pub const fn new(flash_range: Range<u32>) -> Self {
33 match Self::try_new(flash_range) {
34 Ok(config) => config,
35 Err(_) => panic!("Map config must be correct"),
36 }
37 }
38
39 pub const fn try_new(flash_range: Range<u32>) -> Result<Self, MapConfigError> {
41 if !flash_range.start.is_multiple_of(S::ERASE_SIZE as u32) {
42 return Err(MapConfigError::StartRangeNotAtPageBoundary);
43 }
44 if !flash_range.end.is_multiple_of(S::ERASE_SIZE as u32) {
45 return Err(MapConfigError::EndRangeNotAtPageBoundary);
46 }
47 if flash_range.end - flash_range.start < S::ERASE_SIZE as u32 * 2 {
49 return Err(MapConfigError::RangeTooSmall);
50 }
51
52 if S::ERASE_SIZE < S::WORD_SIZE * 3 + ItemHeader::data_address::<S>(0) as usize {
54 return Err(MapConfigError::PagesTooSmall);
55 }
56 if S::WORD_SIZE > MAX_WORD_SIZE {
57 return Err(MapConfigError::WordSizeTooLarge);
58 }
59
60 Ok(Self {
61 flash_range,
62 _phantom: PhantomData,
63 })
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum MapConfigError {
71 StartRangeNotAtPageBoundary,
73 EndRangeNotAtPageBoundary,
75 RangeTooSmall,
77 PagesTooSmall,
79 WordSizeTooLarge,
81}
82
83pub struct MapStorage<K: Key, S: NorFlash, C: CacheImpl<K>> {
157 inner: GenericStorage<S, C, K>,
158 _phantom: PhantomData<K>,
159}
160
161impl<S: NorFlash, C: CacheImpl<K>, K: Key> MapStorage<K, S, C> {
162 pub const fn new(storage: S, config: MapConfig<S>, cache: C) -> Self {
168 Self {
169 inner: GenericStorage {
170 flash: storage,
171 flash_range: config.flash_range,
172 cache,
173 _phantom: PhantomData,
174 },
175 _phantom: PhantomData,
176 }
177 }
178
179 pub async fn fetch_item<'d, V: Value<'d>>(
188 &mut self,
189 data_buffer: &'d mut [u8],
190 search_key: &K,
191 ) -> Result<Option<V>, Error<S::Error>> {
192 let result = run_with_auto_repair!(
193 function = self.fetch_item_with_location(data_buffer, search_key).await,
194 repair = self.try_repair(data_buffer).await?
195 );
196
197 let Some((item, _, item_key_len)) = result? else {
198 return Ok(None);
199 };
200
201 let data_len = item.header.length as usize;
202 let item_key_len = match item_key_len {
203 Some(item_key_len) => item_key_len,
204 None => K::get_len(&data_buffer[..data_len])?,
205 };
206
207 let (value, _size) =
208 V::deserialize_from(&data_buffer[item_key_len..][..data_len - item_key_len])
209 .map_err(Error::SerializationError)?;
210 Ok(Some(value))
211 }
212
213 #[allow(clippy::type_complexity)]
215 async fn fetch_item_with_location(
216 &mut self,
217 data_buffer: &mut [u8],
218 search_key: &K,
219 ) -> Result<Option<(ItemUnborrowed, u32, Option<usize>)>, Error<S::Error>> {
220 if self.inner.cache.is_dirty() {
221 self.inner.cache.invalidate_cache_state();
222 }
223
224 'cache: {
225 if let Some(cached_location) = self.inner.cache.key_location(search_key) {
226 let page_index = calculate_page_index::<S>(self.flash_range(), cached_location);
227 let page_data_end_address =
228 calculate_page_end_address::<S>(self.flash_range(), page_index)
229 - S::WORD_SIZE as u32;
230
231 let Some(header) = ItemHeader::read_new(
232 &mut self.inner.flash,
233 cached_location,
234 page_data_end_address,
235 )
236 .await?
237 else {
238 #[expect(clippy::assertions_on_constants, reason = "Clippy is wrong here")]
240 {
241 assert!(
242 !cfg!(feature = "_test"),
243 "Wrong cache value. Addr: {cached_location}"
244 );
245 }
246 self.inner.cache.invalidate_cache_state();
247 break 'cache;
248 };
249
250 let item = header
251 .read_item(
252 &mut self.inner.flash,
253 data_buffer,
254 cached_location,
255 page_data_end_address,
256 )
257 .await?;
258
259 match item {
260 item::MaybeItem::Corrupted(_, _) | item::MaybeItem::Erased(_, _) => {
261 #[expect(clippy::assertions_on_constants, reason = "Clippy is wrong here")]
262 {
263 assert!(
264 !cfg!(feature = "_test"),
265 "Wrong cache value. Addr: {cached_location}"
266 );
267 }
268
269 self.inner.cache.invalidate_cache_state();
271 break 'cache;
272 }
273 item::MaybeItem::Present(item) => {
274 return Ok(Some((item.unborrow(), cached_location, None)));
275 }
276 }
277 }
278 }
279
280 let mut last_used_page = self
282 .inner
283 .find_first_page(0, PageState::PartialOpen)
284 .await?;
285
286 if last_used_page.is_none() {
287 if let Some(first_open_page) = self.inner.find_first_page(0, PageState::Open).await? {
290 let previous_page = self.inner.previous_page(first_open_page);
291 if self
292 .inner
293 .get_page_state_cached(previous_page)
294 .await?
295 .is_closed()
296 {
297 last_used_page = Some(previous_page);
298 } else {
299 self.inner.cache.unmark_dirty();
302 return Ok(None);
303 }
304 } else {
305 return Err(Error::Corrupted {
309 #[cfg(feature = "_test")]
310 backtrace: std::backtrace::Backtrace::capture(),
311 });
312 }
313 }
314
315 let mut current_page_to_check = last_used_page.unwrap();
319 let mut newest_found_item_data = None;
320
321 loop {
322 let page_data_start_address =
323 calculate_page_address::<S>(self.flash_range(), current_page_to_check)
324 + S::WORD_SIZE as u32;
325 let page_data_end_address =
326 calculate_page_end_address::<S>(self.flash_range(), current_page_to_check)
327 - S::WORD_SIZE as u32;
328
329 let mut it = ItemIter::new(page_data_start_address, page_data_end_address);
330 while let Some((item, address)) = it.next(&mut self.inner.flash, data_buffer).await? {
331 let (found_key, found_key_len) = K::deserialize_from(item.data())?;
332 if found_key == *search_key {
333 newest_found_item_data = Some((address, found_key_len));
334 }
335 }
336
337 if let Some((newest_found_item_address, _)) = newest_found_item_data.as_ref() {
339 self.inner
340 .cache
341 .notice_key_location(search_key, *newest_found_item_address, false);
342
343 break;
344 }
345
346 let previous_page = self.inner.previous_page(current_page_to_check);
348
349 if self.inner.get_page_state_cached(previous_page).await? != PageState::Closed {
350 self.inner.cache.unmark_dirty();
352 return Ok(None);
353 }
354
355 current_page_to_check = previous_page;
356 }
357
358 self.inner.cache.unmark_dirty();
359
360 if let Some((newest_found_item_address, newest_found_item_key_len)) = newest_found_item_data
363 {
364 let item =
365 ItemHeader::read_new(&mut self.inner.flash, newest_found_item_address, u32::MAX)
366 .await?
367 .ok_or_else(|| {
368 Error::Corrupted {
370 #[cfg(feature = "_test")]
371 backtrace: std::backtrace::Backtrace::capture(),
372 }
373 })?
374 .read_item(
375 &mut self.inner.flash,
376 data_buffer,
377 newest_found_item_address,
378 u32::MAX,
379 )
380 .await?;
381
382 Ok(Some((
383 item.unwrap()?.unborrow(),
384 newest_found_item_address,
385 Some(newest_found_item_key_len),
386 )))
387 } else {
388 Ok(None)
389 }
390 }
391
392 pub async fn store_item<'d, V: Value<'d>>(
398 &mut self,
399 data_buffer: &mut [u8],
400 key: &K,
401 item: &V,
402 ) -> Result<(), Error<S::Error>> {
403 run_with_auto_repair!(
404 function = self
405 .store_item_inner::<dyn Value>(data_buffer, key, item)
406 .await,
407 repair = self.try_repair(data_buffer).await?
408 )
409 }
410
411 pub async fn store_item_generic<'d, V: Value<'d> + ?Sized>(
419 &mut self,
420 data_buffer: &mut [u8],
421 key: &K,
422 item: &V,
423 ) -> Result<(), Error<S::Error>> {
424 run_with_auto_repair!(
425 function = self.store_item_inner::<V>(data_buffer, key, item).await,
426 repair = self.try_repair(data_buffer).await?
427 )
428 }
429
430 async fn store_item_inner<'d, V: Value<'d> + ?Sized>(
431 &mut self,
432 data_buffer: &mut [u8],
433 key: &K,
434 item: &V,
435 ) -> Result<(), Error<S::Error>> {
436 if self.inner.cache.is_dirty() {
437 self.inner.cache.invalidate_cache_state();
438 }
439
440 let mut recursion_level = 0;
441 loop {
442 if recursion_level == self.inner.get_pages(0).count() {
444 self.inner.cache.unmark_dirty();
445 return Err(Error::FullStorage);
446 }
447
448 let next_page_to_use = if let Some(partial_open_page) = self
450 .inner
451 .find_first_page(0, PageState::PartialOpen)
452 .await?
453 {
454 if !self
456 .inner
457 .get_page_state_cached(self.inner.next_page(partial_open_page))
458 .await?
459 .is_open()
460 {
461 return Err(Error::Corrupted {
466 #[cfg(feature = "_test")]
467 backtrace: std::backtrace::Backtrace::capture(),
468 });
469 }
470
471 let page_data_start_address =
474 calculate_page_address::<S>(self.flash_range(), partial_open_page)
475 + S::WORD_SIZE as u32;
476 let page_data_end_address =
477 calculate_page_end_address::<S>(self.flash_range(), partial_open_page)
478 - S::WORD_SIZE as u32;
479
480 let key_len = key.serialize_into(data_buffer)?;
481 let item_data_length = key_len
482 + item
483 .serialize_into(&mut data_buffer[key_len..])
484 .map_err(Error::SerializationError)?;
485
486 if item_data_length > u16::MAX as usize
487 || item_data_length
488 > calculate_page_size::<S>()
489 .saturating_sub(ItemHeader::data_address::<S>(0) as usize)
490 {
491 self.inner.cache.unmark_dirty();
492 return Err(Error::ItemTooBig);
493 }
494
495 let free_spot_address = self
496 .inner
497 .find_next_free_item_spot(
498 page_data_start_address,
499 page_data_end_address,
500 item_data_length as u32,
501 )
502 .await?;
503
504 if let Some(free_spot_address) = free_spot_address {
505 self.inner
506 .cache
507 .notice_key_location(key, free_spot_address, true);
508 Item::write_new(
509 &mut self.inner.flash,
510 self.inner.flash_range.clone(),
511 &mut self.inner.cache,
512 free_spot_address,
513 &data_buffer[..item_data_length],
514 )
515 .await?;
516
517 self.inner.cache.unmark_dirty();
518 return Ok(());
519 }
520
521 self.inner.close_page(partial_open_page).await?;
523 Some(self.inner.next_page(partial_open_page))
524 } else {
525 None
526 };
527
528 if let Some(next_page_to_use) = next_page_to_use {
534 let next_page_state = self.inner.get_page_state_cached(next_page_to_use).await?;
535
536 if !next_page_state.is_open() {
537 return Err(Error::Corrupted {
539 #[cfg(feature = "_test")]
540 backtrace: std::backtrace::Backtrace::capture(),
541 });
542 }
543
544 self.inner.partial_close_page(next_page_to_use).await?;
548
549 let next_buffer_page = self.inner.next_page(next_page_to_use);
550 let next_buffer_page_state =
551 self.inner.get_page_state_cached(next_buffer_page).await?;
552
553 if !next_buffer_page_state.is_open() {
554 self.migrate_items(data_buffer, next_buffer_page, next_page_to_use)
555 .await?;
556 }
557 } else {
558 let Some(first_open_page) = self.inner.find_first_page(0, PageState::Open).await?
560 else {
561 return Err(Error::Corrupted {
565 #[cfg(feature = "_test")]
566 backtrace: std::backtrace::Backtrace::capture(),
567 });
568 };
569
570 self.inner.partial_close_page(first_open_page).await?;
571 }
572
573 recursion_level += 1;
575 }
576 }
577
578 pub async fn remove_item(
591 &mut self,
592 data_buffer: &mut [u8],
593 search_key: &K,
594 ) -> Result<(), Error<S::Error>>
595 where
596 S: MultiwriteNorFlash,
597 {
598 run_with_auto_repair!(
599 function = self.remove_item_inner(data_buffer, Some(search_key)).await,
600 repair = self.try_repair(data_buffer).await?
601 )
602 }
603
604 pub async fn remove_all_items(&mut self, data_buffer: &mut [u8]) -> Result<(), Error<S::Error>>
615 where
616 S: MultiwriteNorFlash,
617 {
618 run_with_auto_repair!(
619 function = self.remove_item_inner(data_buffer, None).await,
620 repair = self.try_repair(data_buffer).await?
621 )
622 }
623
624 async fn remove_item_inner(
626 &mut self,
627 data_buffer: &mut [u8],
628 search_key: Option<&K>,
629 ) -> Result<(), Error<S::Error>>
630 where
631 S: MultiwriteNorFlash,
632 {
633 if let Some(key) = &search_key {
634 self.inner.cache.notice_key_erased(key);
635 } else {
636 self.inner.cache.invalidate_cache_state();
637 }
638
639 let last_used_page = match self
643 .inner
644 .find_first_page(0, PageState::PartialOpen)
645 .await?
646 {
647 Some(last_used_page) => last_used_page,
648 None => {
649 self.inner
654 .find_last_page(0, PageState::Closed)
655 .await?
656 .unwrap_or_default()
657 }
658 };
659
660 for page_index in self.inner.get_pages(self.inner.next_page(last_used_page)) {
662 if self
663 .inner
664 .get_page_state_cached(page_index)
665 .await?
666 .is_open()
667 {
668 continue;
670 }
671
672 let page_data_start_address =
673 calculate_page_address::<S>(self.flash_range(), page_index) + S::WORD_SIZE as u32;
674 let page_data_end_address =
675 calculate_page_end_address::<S>(self.flash_range(), page_index)
676 - S::WORD_SIZE as u32;
677
678 let mut item_headers =
680 ItemHeaderIter::new(page_data_start_address, page_data_end_address);
681
682 while let (Some(item_header), item_address) =
683 item_headers.next(&mut self.inner.flash).await?
684 {
685 let item = item_header
686 .read_item(
687 &mut self.inner.flash,
688 data_buffer,
689 item_address,
690 page_data_end_address,
691 )
692 .await?;
693
694 match item {
695 item::MaybeItem::Corrupted(_, _) | item::MaybeItem::Erased(_, _) => continue,
696 item::MaybeItem::Present(item) => {
697 let item_match = match search_key {
698 Some(search_key) => K::deserialize_from(item.data())?.0 == *search_key,
699 _ => true,
700 };
701 if item_match {
704 item.header
705 .erase_data(
706 &mut self.inner.flash,
707 self.inner.flash_range.clone(),
708 &mut self.inner.cache,
709 item_address,
710 )
711 .await?;
712 }
713 }
714 }
715 }
716 }
717
718 self.inner.cache.unmark_dirty();
720
721 Ok(())
722 }
723
724 pub async fn fetch_all_items(
785 &mut self,
786 data_buffer: &mut [u8],
787 ) -> Result<MapItemIter<'_, K, S, C>, Error<S::Error>> {
788 let first_page = run_with_auto_repair!(
791 function = {
792 match self
793 .inner
794 .find_first_page(0, PageState::PartialOpen)
795 .await?
796 {
797 Some(last_used_page) => {
798 Ok(self.inner.next_page(last_used_page))
800 }
801 None => {
802 if let Some(first_open_page) =
805 self.inner.find_first_page(0, PageState::Open).await?
806 {
807 let previous_page = self.inner.previous_page(first_open_page);
808 if self
809 .inner
810 .get_page_state_cached(previous_page)
811 .await?
812 .is_closed()
813 {
814 Ok(first_open_page)
816 } else {
817 self.inner.cache.unmark_dirty();
820 Ok(0)
821 }
822 } else {
823 Err(Error::Corrupted {
827 #[cfg(feature = "_test")]
828 backtrace: std::backtrace::Backtrace::capture(),
829 })
830 }
831 }
832 }
833 },
834 repair = self.try_repair(data_buffer).await?
835 )?;
836
837 let start_address =
838 calculate_page_address::<S>(self.flash_range(), first_page) + S::WORD_SIZE as u32;
839 let end_address =
840 calculate_page_end_address::<S>(self.flash_range(), first_page) - S::WORD_SIZE as u32;
841
842 Ok(MapItemIter {
843 storage: self,
844 first_page,
845 current_page_index: first_page,
846 current_iter: ItemIter::new(start_address, end_address),
847 _key: PhantomData,
848 })
849 }
850
851 async fn migrate_items(
852 &mut self,
853 data_buffer: &mut [u8],
854 source_page: usize,
855 target_page: usize,
856 ) -> Result<(), Error<S::Error>> {
857 let mut next_page_write_address =
861 calculate_page_address::<S>(self.flash_range(), target_page) + S::WORD_SIZE as u32;
862
863 let mut it = ItemIter::new(
864 calculate_page_address::<S>(self.flash_range(), source_page) + S::WORD_SIZE as u32,
865 calculate_page_end_address::<S>(self.flash_range(), source_page) - S::WORD_SIZE as u32,
866 );
867 while let Some((item, item_address)) = it.next(&mut self.inner.flash, data_buffer).await? {
868 let (key, _) = K::deserialize_from(item.data())?;
869
870 self.inner.cache.unmark_dirty();
872
873 let Some((found_item, found_address, _)) =
875 self.fetch_item_with_location(data_buffer, &key).await?
876 else {
877 return Err(Error::Corrupted {
879 #[cfg(feature = "_test")]
880 backtrace: std::backtrace::Backtrace::capture(),
881 });
882 };
883
884 let found_item = found_item
885 .reborrow(data_buffer)
886 .ok_or_else(|| Error::LogicBug {
887 #[cfg(feature = "_test")]
888 backtrace: std::backtrace::Backtrace::capture(),
889 })?;
890
891 if found_address == item_address {
892 self.inner
893 .cache
894 .notice_key_location(&key, next_page_write_address, true);
895 found_item
896 .write(
897 &mut self.inner.flash,
898 self.inner.flash_range.clone(),
899 &mut self.inner.cache,
900 next_page_write_address,
901 )
902 .await?;
903 next_page_write_address = found_item
904 .header
905 .next_item_address::<S>(next_page_write_address);
906 }
907 }
908
909 self.inner.open_page(source_page).await?;
910
911 Ok(())
912 }
913
914 async fn try_repair(&mut self, data_buffer: &mut [u8]) -> Result<(), Error<S::Error>> {
925 self.inner.cache.invalidate_cache_state();
926
927 self.inner.try_general_repair().await?;
928
929 if let Some(partial_open_page) = self
931 .inner
932 .find_first_page(0, PageState::PartialOpen)
933 .await?
934 {
935 let buffer_page = self.inner.next_page(partial_open_page);
936 if !self
937 .inner
938 .get_page_state_cached(buffer_page)
939 .await?
940 .is_open()
941 {
942 self.inner.open_page(partial_open_page).await?;
945
946 self.inner.partial_close_page(partial_open_page).await?;
948
949 self.migrate_items(data_buffer, buffer_page, partial_open_page)
950 .await?;
951 }
952 }
953
954 Ok(())
955 }
956
957 pub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>> {
961 self.inner.erase_all()
962 }
963
964 #[must_use]
969 pub const fn item_overhead_size() -> u32 {
970 GenericStorage::<S, C, K>::item_overhead_size()
971 }
972
973 pub fn destroy(self) -> (S, C) {
977 self.inner.destroy()
978 }
979
980 pub const fn flash(&mut self) -> &mut S {
982 self.inner.flash()
983 }
984
985 pub const fn flash_range(&self) -> Range<u32> {
987 self.inner.flash_range()
988 }
989
990 #[cfg(any(test, fuzzing))]
992 pub const fn cache(&mut self) -> &mut C {
993 &mut self.inner.cache
994 }
995
996 #[cfg(any(test, feature = "std", fuzzing))]
997 pub fn print_items(&mut self) -> impl Future<Output = String> {
1001 self.inner.print_items()
1002 }
1003
1004 #[cfg(test)]
1005 fn inner_mut(&mut self) -> &mut GenericStorage<S, C, K> {
1006 &mut self.inner
1007 }
1008}
1009
1010pub struct MapItemIter<'s, K: Key, S: NorFlash, C: CacheImpl<K>> {
1059 storage: &'s mut MapStorage<K, S, C>,
1060 first_page: usize,
1061 current_page_index: usize,
1062 pub(crate) current_iter: ItemIter,
1063 _key: PhantomData<K>,
1064}
1065
1066impl<K: Key, S: NorFlash, C: CacheImpl<K>> MapItemIter<'_, K, S, C> {
1067 pub async fn next<'a, V: Value<'a>>(
1069 &mut self,
1070 data_buffer: &'a mut [u8],
1071 ) -> Result<Option<(K, V)>, Error<S::Error>> {
1072 let item = loop {
1074 if let Some((item, _address)) = self
1075 .current_iter
1076 .next(&mut self.storage.inner.flash, data_buffer)
1077 .await?
1078 {
1079 break item;
1081 }
1082
1083 loop {
1086 self.current_page_index = self.storage.inner.next_page(self.current_page_index);
1087
1088 if self.current_page_index == self.first_page {
1090 return Ok(None);
1091 }
1092
1093 match self
1094 .storage
1095 .inner
1096 .get_page_state_cached(self.current_page_index)
1097 .await
1098 {
1099 Ok(PageState::Closed | PageState::PartialOpen) => {
1100 self.current_iter = ItemIter::new(
1101 calculate_page_address::<S>(
1102 self.storage.inner.flash_range.clone(),
1103 self.current_page_index,
1104 ) + S::WORD_SIZE as u32,
1105 calculate_page_end_address::<S>(
1106 self.storage.inner.flash_range.clone(),
1107 self.current_page_index,
1108 ) - S::WORD_SIZE as u32,
1109 );
1110 break;
1111 }
1112 _ => continue,
1113 }
1114 }
1115 };
1116
1117 let data_len = item.header.length as usize;
1118 let (key, key_len) = K::deserialize_from(item.data())?;
1119 let (value, _value_len) = V::deserialize_from(&data_buffer[..data_len][key_len..])
1120 .map_err(Error::SerializationError)?;
1121
1122 Ok(Some((key, value)))
1123 }
1124}
1125
1126pub trait Key: Eq + Clone + Sized + Debug {
1135 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError>;
1138 fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError>;
1141 fn get_len(buffer: &[u8]) -> Result<usize, SerializationError> {
1144 Self::deserialize_from(buffer).map(|(_, len)| len)
1145 }
1146}
1147
1148macro_rules! impl_key_num {
1149 ($int:ty) => {
1150 impl Key for $int {
1151 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1152 let self_bytes = self.to_le_bytes();
1153
1154 match buffer.get_mut(..self_bytes.len()) {
1155 Some(buffer) => {
1156 buffer.copy_from_slice(&self_bytes);
1157 Ok(buffer.len())
1158 }
1159 None => Err(SerializationError::BufferTooSmall),
1160 }
1161 }
1162
1163 fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1164 let value = Self::from_le_bytes(
1165 buffer
1166 .get(..size_of::<Self>())
1167 .ok_or(SerializationError::BufferTooSmall)?
1168 .try_into()
1169 .unwrap(),
1170 );
1171 Ok((value, size_of::<Self>()))
1172 }
1173
1174 fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
1175 Ok(size_of::<Self>())
1176 }
1177 }
1178 };
1179}
1180
1181impl_key_num!(u8);
1182impl_key_num!(u16);
1183impl_key_num!(u32);
1184impl_key_num!(u64);
1185impl_key_num!(u128);
1186impl_key_num!(i8);
1187impl_key_num!(i16);
1188impl_key_num!(i32);
1189impl_key_num!(i64);
1190impl_key_num!(i128);
1191
1192impl<const N: usize> Key for [u8; N] {
1193 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1194 buffer
1195 .get_mut(..N)
1196 .ok_or(SerializationError::BufferTooSmall)?
1197 .copy_from_slice(self);
1198 Ok(N)
1199 }
1200
1201 fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1202 Ok((
1203 buffer
1204 .get(..N)
1205 .ok_or(SerializationError::BufferTooSmall)?
1206 .try_into()
1207 .unwrap(),
1208 N,
1209 ))
1210 }
1211
1212 fn get_len(_buffer: &[u8]) -> Result<usize, SerializationError> {
1213 Ok(N)
1214 }
1215}
1216
1217impl Key for () {
1218 fn serialize_into(&self, _buffer: &mut [u8]) -> Result<usize, SerializationError> {
1219 Ok(0)
1220 }
1221
1222 fn deserialize_from(_buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1223 Ok(((), 0))
1224 }
1225}
1226
1227pub trait Value<'a> {
1232 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError>;
1235 fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1244 where
1245 Self: Sized;
1246}
1247
1248impl<'a> Value<'a> for bool {
1249 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1250 <u8 as Value>::serialize_into(&u8::from(*self), buffer)
1251 }
1252
1253 fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1254 where
1255 Self: Sized,
1256 {
1257 let (value, size) = <u8 as Value>::deserialize_from(buffer)?;
1258 Ok((value != 0, size))
1259 }
1260}
1261
1262impl<'a, T: Value<'a>> Value<'a> for Option<T> {
1263 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1264 if let Some(val) = self {
1265 let mut size = 0;
1266 size += <bool as Value>::serialize_into(&true, buffer)?;
1267 size += <T as Value>::serialize_into(
1268 val,
1269 buffer
1270 .get_mut(size..)
1271 .ok_or(SerializationError::BufferTooSmall)?,
1272 )?;
1273 Ok(size)
1274 } else {
1275 <bool as Value>::serialize_into(&false, buffer)
1276 }
1277 }
1278
1279 fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1280 where
1281 Self: Sized,
1282 {
1283 let (is_some, tag_size) = <bool as Value>::deserialize_from(buffer)?;
1284 if is_some {
1285 let (value, value_size) = <T as Value>::deserialize_from(
1286 buffer
1287 .get(tag_size..)
1288 .ok_or(SerializationError::BufferTooSmall)?,
1289 )?;
1290 Ok((Some(value), tag_size + value_size))
1291 } else {
1292 Ok((None, tag_size))
1293 }
1294 }
1295}
1296
1297impl<'a> Value<'a> for &'a [u8] {
1298 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1299 buffer
1300 .get_mut(..self.len())
1301 .ok_or(SerializationError::BufferTooSmall)?
1302 .copy_from_slice(self);
1303 Ok(self.len())
1304 }
1305
1306 fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1307 where
1308 Self: Sized,
1309 {
1310 Ok((buffer, buffer.len()))
1311 }
1312}
1313
1314#[cfg(feature = "postcard")]
1315pub trait PostcardValue<'a>: Serialize + Deserialize<'a> {}
1322
1323#[cfg(feature = "postcard")]
1324impl<'a, T> Value<'a> for T
1325where
1326 T: PostcardValue<'a>,
1327{
1328 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1329 Ok(postcard::to_slice(self, buffer).map(|s| s.len())?)
1330 }
1331
1332 fn deserialize_from(buffer: &'a [u8]) -> Result<(Self, usize), SerializationError>
1333 where
1334 Self: Sized,
1335 {
1336 Ok((postcard::from_bytes(buffer)?, buffer.len()))
1337 }
1338}
1339
1340#[cfg(feature = "postcard")]
1341impl From<postcard::Error> for SerializationError {
1342 fn from(error: postcard::Error) -> SerializationError {
1343 use postcard::Error::*;
1344 match error {
1345 SerializeBufferFull => SerializationError::BufferTooSmall,
1346 SerializeSeqLengthUnknown => SerializationError::InvalidData,
1347 DeserializeUnexpectedEnd
1348 | DeserializeBadVarint
1349 | DeserializeBadBool
1350 | DeserializeBadChar
1351 | DeserializeBadUtf8
1352 | DeserializeBadOption
1353 | DeserializeBadEnum
1354 | DeserializeBadEncoding
1355 | DeserializeBadCrc => SerializationError::InvalidFormat,
1356 _ => SerializationError::Custom(error as i32),
1357 }
1358 }
1359}
1360
1361macro_rules! impl_map_item_num {
1362 ($num:ty) => {
1363 impl<'a> Value<'a> for $num {
1364 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1365 let self_bytes = self.to_le_bytes();
1366
1367 match buffer.get_mut(..self_bytes.len()) {
1368 Some(buffer) => {
1369 buffer.copy_from_slice(&self_bytes);
1370 Ok(buffer.len())
1371 }
1372 None => Err(SerializationError::BufferTooSmall),
1373 }
1374 }
1375
1376 fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1377 let value = Self::from_le_bytes(
1378 buffer
1379 .get(..size_of::<Self>())
1380 .ok_or(SerializationError::BufferTooSmall)?
1381 .try_into()
1382 .unwrap(),
1383 );
1384 Ok((value, size_of::<Self>()))
1385 }
1386 }
1387
1388 impl<'a, const N: usize> Value<'a> for [$num; N] {
1390 fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
1391 let elem_size = size_of::<$num>();
1392
1393 let buffer = buffer
1394 .get_mut(0..elem_size * N)
1395 .ok_or(SerializationError::BufferTooSmall)?;
1396
1397 for (chunk, number) in buffer.chunks_exact_mut(elem_size).zip(self.iter()) {
1398 chunk.copy_from_slice(&number.to_le_bytes())
1399 }
1400 Ok(elem_size * N)
1401 }
1402
1403 fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
1404 let elem_size = size_of::<$num>();
1405 if buffer.len() < elem_size * N {
1406 return Err(SerializationError::BufferTooSmall);
1407 }
1408
1409 let mut array = [0 as $num; N];
1410 for (chunk, number) in buffer.chunks_exact(elem_size).zip(array.iter_mut()) {
1411 *number = <$num>::from_le_bytes(chunk.try_into().unwrap());
1412 }
1413 Ok((array, elem_size * N))
1414 }
1415 }
1416 };
1417}
1418
1419impl_map_item_num!(u8);
1420impl_map_item_num!(u16);
1421impl_map_item_num!(u32);
1422impl_map_item_num!(u64);
1423impl_map_item_num!(u128);
1424impl_map_item_num!(i8);
1425impl_map_item_num!(i16);
1426impl_map_item_num!(i32);
1427impl_map_item_num!(i64);
1428impl_map_item_num!(i128);
1429impl_map_item_num!(f32);
1430impl_map_item_num!(f64);
1431
1432#[non_exhaustive]
1436#[derive(Debug, PartialEq, Eq, Clone)]
1437#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1438pub enum SerializationError {
1439 BufferTooSmall,
1441 InvalidData,
1443 InvalidFormat,
1445 Custom(i32),
1448}
1449
1450impl core::fmt::Display for SerializationError {
1451 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1452 match self {
1453 SerializationError::BufferTooSmall => write!(f, "Buffer too small"),
1454 SerializationError::InvalidData => write!(f, "Invalid data"),
1455 SerializationError::InvalidFormat => write!(f, "Invalid format"),
1456 SerializationError::Custom(val) => write!(f, "Custom error: {val}"),
1457 }
1458 }
1459}
1460
1461#[cfg(test)]
1462mod tests {
1463 use crate::{AlignedBuf, cache::Cache, mock_flash};
1464
1465 use super::*;
1466 use futures_test::test;
1467
1468 type MockFlashBig = mock_flash::MockFlashBase<4, 4, 256>;
1469 type MockFlashTiny = mock_flash::MockFlashBase<2, 1, 32>;
1470
1471 #[test]
1472 async fn store_and_fetch() {
1473 let mut storage = MapStorage::<u8, _, _>::new(
1474 MockFlashBig::default(),
1475 MapConfig::new(0x000..0x1000),
1476 Cache::new_uncached(),
1477 );
1478
1479 let mut data_buffer = AlignedBuf([0; 128]);
1480
1481 let start_snapshot = storage.flash().stats_snapshot();
1482
1483 let item = storage
1484 .fetch_item::<&[u8]>(&mut data_buffer, &0)
1485 .await
1486 .unwrap();
1487 assert_eq!(item, None);
1488
1489 let item = storage
1490 .fetch_item::<&[u8]>(&mut data_buffer, &60)
1491 .await
1492 .unwrap();
1493 assert_eq!(item, None);
1494
1495 let item = storage
1496 .fetch_item::<&[u8]>(&mut data_buffer, &0xFF)
1497 .await
1498 .unwrap();
1499 assert_eq!(item, None);
1500
1501 storage
1502 .store_item(&mut data_buffer, &0u8, &[5u8])
1503 .await
1504 .unwrap();
1505 storage
1506 .store_item(&mut data_buffer, &0u8, &[5u8, 6])
1507 .await
1508 .unwrap();
1509
1510 let item = storage
1511 .fetch_item::<&[u8]>(&mut data_buffer, &0)
1512 .await
1513 .unwrap()
1514 .unwrap();
1515 assert_eq!(item, &[5, 6]);
1516
1517 storage
1518 .store_item(&mut data_buffer, &1u8, &[2u8, 2, 2, 2, 2, 2])
1519 .await
1520 .unwrap();
1521
1522 let item = storage
1523 .fetch_item::<&[u8]>(&mut data_buffer, &0)
1524 .await
1525 .unwrap()
1526 .unwrap();
1527 assert_eq!(item, &[5, 6]);
1528
1529 let item = storage
1530 .fetch_item::<&[u8]>(&mut data_buffer, &1)
1531 .await
1532 .unwrap()
1533 .unwrap();
1534 assert_eq!(item, &[2, 2, 2, 2, 2, 2]);
1535
1536 for index in 0..4000 {
1537 storage
1538 .store_item(
1539 &mut data_buffer,
1540 &((index % 10) as u8),
1541 &vec![(index % 10) as u8 * 2; index % 10].as_slice(),
1542 )
1543 .await
1544 .unwrap();
1545 }
1546
1547 for i in 0..10 {
1548 let item = storage
1549 .fetch_item::<&[u8]>(&mut data_buffer, &i)
1550 .await
1551 .unwrap()
1552 .unwrap();
1553 assert_eq!(item, &vec![(i % 10) * 2; (i % 10) as usize]);
1554 }
1555
1556 for _ in 0..4000 {
1557 storage
1558 .store_item(&mut data_buffer, &11u8, &[0; 10])
1559 .await
1560 .unwrap();
1561 }
1562
1563 for i in 0..10 {
1564 let item = storage
1565 .fetch_item::<&[u8]>(&mut data_buffer, &i)
1566 .await
1567 .unwrap()
1568 .unwrap();
1569 assert_eq!(item, &vec![(i % 10) * 2; (i % 10) as usize]);
1570 }
1571
1572 println!(
1573 "{:?}",
1574 start_snapshot.compare_to(storage.flash().stats_snapshot()),
1575 );
1576 }
1577
1578 #[test]
1579 async fn store_too_many_items() {
1580 const UPPER_BOUND: u8 = 3;
1581
1582 let mut storage = MapStorage::new(
1583 MockFlashTiny::default(),
1584 const { MapConfig::new(0x00..0x40) },
1585 Cache::new_uncached(),
1586 );
1587 let mut data_buffer = AlignedBuf([0; 128]);
1588
1589 for i in 0..UPPER_BOUND {
1590 println!("Storing {i:?}");
1591
1592 storage
1593 .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1594 .await
1595 .unwrap();
1596 }
1597
1598 assert_eq!(
1599 storage
1600 .store_item(
1601 &mut data_buffer,
1602 &UPPER_BOUND,
1603 &vec![0; UPPER_BOUND as usize].as_slice(),
1604 )
1605 .await,
1606 Err(Error::FullStorage)
1607 );
1608
1609 for i in 0..UPPER_BOUND {
1610 let item = storage
1611 .fetch_item::<&[u8]>(&mut data_buffer, &i)
1612 .await
1613 .unwrap()
1614 .unwrap();
1615
1616 println!("Fetched {item:?}");
1617
1618 assert_eq!(item, vec![i; i as usize]);
1619 }
1620 }
1621
1622 #[test]
1623 async fn store_too_many_items_big() {
1624 const UPPER_BOUND: u8 = 68;
1625
1626 let mut storage = MapStorage::new(
1627 MockFlashBig::default(),
1628 const { MapConfig::new(0x0000..0x1000) },
1629 Cache::new_uncached(),
1630 );
1631 let mut data_buffer = AlignedBuf([0; 128]);
1632
1633 for i in 0..UPPER_BOUND {
1634 println!("Storing {i:?}");
1635
1636 storage
1637 .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1638 .await
1639 .unwrap();
1640 }
1641
1642 assert_eq!(
1643 storage
1644 .store_item(
1645 &mut data_buffer,
1646 &UPPER_BOUND,
1647 &vec![0; UPPER_BOUND as usize].as_slice(),
1648 )
1649 .await,
1650 Err(Error::FullStorage)
1651 );
1652
1653 for i in 0..UPPER_BOUND {
1654 let item = storage
1655 .fetch_item::<&[u8]>(&mut data_buffer, &i)
1656 .await
1657 .unwrap()
1658 .unwrap();
1659
1660 println!("Fetched {item:?}");
1661
1662 assert_eq!(item, vec![i; i as usize]);
1663 }
1664 }
1665
1666 #[test]
1667 async fn store_many_items_big() {
1668 let mut storage = MapStorage::new(
1669 mock_flash::MockFlashBase::<4, 1, 4096>::default(),
1670 const { MapConfig::new(0x0000..0x4000) },
1671 Cache::new_uncached(),
1672 );
1673 let mut data_buffer = AlignedBuf([0; 128]);
1674
1675 const LENGHT_PER_KEY: [usize; 24] = [
1676 11, 13, 6, 13, 13, 10, 2, 3, 5, 36, 1, 65, 4, 6, 1, 15, 10, 7, 3, 15, 9, 3, 4, 5,
1677 ];
1678
1679 for _ in 0..100 {
1680 #[allow(clippy::needless_range_loop)]
1681 for i in 0..24 {
1682 storage
1683 .store_item(
1684 &mut data_buffer,
1685 &(i as u16),
1686 &vec![i as u8; LENGHT_PER_KEY[i]].as_slice(),
1687 )
1688 .await
1689 .unwrap();
1690 }
1691 }
1692
1693 #[allow(clippy::needless_range_loop)]
1694 for i in 0..24 {
1695 let item = storage
1696 .fetch_item::<&[u8]>(&mut data_buffer, &(i as u16))
1697 .await
1698 .unwrap()
1699 .unwrap();
1700
1701 println!("Fetched {item:?}");
1702
1703 assert_eq!(item, vec![i as u8; LENGHT_PER_KEY[i]]);
1704 }
1705 }
1706
1707 #[test]
1708 async fn remove_items() {
1709 let mut storage = MapStorage::new(
1710 mock_flash::MockFlashBase::<4, 1, 4096>::new(
1711 mock_flash::WriteCountCheck::Twice,
1712 None,
1713 true,
1714 ),
1715 const { MapConfig::new(0x0000..0x4000) },
1716 Cache::new_uncached(),
1717 );
1718 let mut data_buffer = AlignedBuf([0; 128]);
1719
1720 for j in 0..10 {
1722 for i in 0..24 {
1723 storage
1724 .store_item(
1725 &mut data_buffer,
1726 &(i as u8),
1727 &vec![i as u8; j + 2].as_slice(),
1728 )
1729 .await
1730 .unwrap();
1731 }
1732 }
1733
1734 for j in (0..24).rev() {
1735 for i in 0..=j {
1737 assert!(
1738 storage
1739 .fetch_item::<&[u8]>(&mut data_buffer, &i)
1740 .await
1741 .unwrap()
1742 .is_some()
1743 );
1744 }
1745
1746 storage.remove_item(&mut data_buffer, &j).await.unwrap();
1748
1749 for i in 0..j {
1751 assert!(
1752 storage
1753 .fetch_item::<&[u8]>(&mut data_buffer, &i)
1754 .await
1755 .unwrap()
1756 .is_some()
1757 );
1758 }
1759
1760 assert!(
1761 storage
1762 .fetch_item::<&[u8]>(&mut data_buffer, &j)
1763 .await
1764 .unwrap()
1765 .is_none()
1766 );
1767 }
1768 }
1769
1770 #[test]
1771 async fn remove_all() {
1772 let mut storage = MapStorage::new(
1773 mock_flash::MockFlashBase::<4, 1, 4096>::new(
1774 mock_flash::WriteCountCheck::Twice,
1775 None,
1776 true,
1777 ),
1778 const { MapConfig::new(0x0000..0x4000) },
1779 Cache::new_uncached(),
1780 );
1781 let mut data_buffer = AlignedBuf([0; 128]);
1782
1783 for value in 0..10 {
1785 for key in 0..24u8 {
1786 storage
1787 .store_item(&mut data_buffer, &key, &vec![key; value + 2].as_slice())
1788 .await
1789 .unwrap();
1790 }
1791 }
1792
1793 for key in 0..24u8 {
1795 assert!(
1796 storage
1797 .fetch_item::<&[u8]>(&mut data_buffer, &key)
1798 .await
1799 .unwrap()
1800 .is_some()
1801 );
1802 }
1803
1804 storage.remove_all_items(&mut data_buffer).await.unwrap();
1806
1807 for key in 0..24 {
1809 assert!(
1810 storage
1811 .fetch_item::<&[u8]>(&mut data_buffer, &key)
1812 .await
1813 .unwrap()
1814 .is_none()
1815 );
1816 }
1817 }
1818
1819 #[test]
1820 async fn store_too_big_item() {
1821 let mut storage = MapStorage::new(
1822 MockFlashBig::new(mock_flash::WriteCountCheck::Twice, None, true),
1823 const { MapConfig::new(0x000..0x1000) },
1824 Cache::new_uncached(),
1825 );
1826
1827 storage
1828 .store_item(&mut [0; 1024], &0u8, &[0u8; 1024 - 4 * 2 - 8 - 1])
1829 .await
1830 .unwrap();
1831
1832 assert_eq!(
1833 storage
1834 .store_item(&mut [0; 1024], &0u8, &[0u8; 1024 - 4 * 2 - 8 - 1 + 1],)
1835 .await,
1836 Err(Error::ItemTooBig)
1837 );
1838 }
1839
1840 #[test]
1841 async fn item_iterator() {
1842 const UPPER_BOUND: u8 = 64;
1843 let mut storage = MapStorage::new(
1844 MockFlashBig::default(),
1845 const { MapConfig::new(0x000..0x1000) },
1846 Cache::new_uncached(),
1847 );
1848
1849 let mut data_buffer = AlignedBuf([0; 128]);
1850
1851 for i in 0..UPPER_BOUND {
1852 storage
1853 .store_item(&mut data_buffer, &i, &vec![i; i as usize].as_slice())
1854 .await
1855 .unwrap();
1856 }
1857
1858 for i in 0..10 {
1860 storage
1861 .store_item(&mut data_buffer, &1u8, &vec![i; i as usize].as_slice())
1862 .await
1863 .unwrap();
1864 }
1865
1866 let mut map_iter = storage.fetch_all_items(&mut data_buffer).await.unwrap();
1867
1868 let mut count = 0;
1869 let mut last_value_buffer = [0u8; 64];
1870 let mut last_value_length = 0;
1871 while let Ok(Some((key, value))) = map_iter.next::<&[u8]>(&mut data_buffer).await {
1872 if key == 1 {
1873 last_value_length = value.len();
1875 last_value_buffer[..value.len()].copy_from_slice(value);
1876 } else {
1877 assert_eq!(value, vec![key; key as usize]);
1878 count += 1;
1879 }
1880 }
1881
1882 assert_eq!(last_value_length, 9);
1883 assert_eq!(
1884 &last_value_buffer[..last_value_length],
1885 vec![9u8; 9].as_slice()
1886 );
1887
1888 assert_eq!(count + 1, UPPER_BOUND);
1890 }
1891
1892 #[test]
1893 async fn issue_132() {
1894 let mut storage = MapStorage::new(
1899 MockFlashBig::new(mock_flash::WriteCountCheck::Disabled, Some(9168), false),
1900 const { MapConfig::new(0x000..0x1000) },
1901 Cache::new_uncached(),
1902 );
1903 let mut buf = [0; 32];
1904 for i in 0..=378u64 {
1905 let _ = storage.store_item(&mut buf, &(), &i).await;
1906 }
1907
1908 println!("{}", storage.print_items().await);
1909
1910 assert_eq!(
1912 storage.inner_mut().get_page_state(0).await.unwrap(),
1913 PageState::Closed
1914 );
1915 assert_eq!(
1916 storage.inner_mut().get_page_state(1).await.unwrap(),
1917 PageState::Closed
1918 );
1919 assert_eq!(
1920 storage.inner_mut().get_page_state(2).await.unwrap(),
1921 PageState::Open
1922 );
1923 assert_eq!(
1924 storage.inner_mut().get_page_state(3).await.unwrap(),
1925 PageState::Closed
1926 );
1927
1928 assert_eq!(
1930 storage.fetch_item::<u64>(&mut buf, &()).await.unwrap(),
1931 Some(377)
1932 );
1933
1934 storage.flash().bytes_until_shutoff = Some(1000);
1939
1940 std::assert_matches!(
1941 storage.remove_item(&mut buf, &()).await,
1942 Err(Error::Storage {
1943 value: mock_flash::MockFlashError::EarlyShutoff(_, mock_flash::Operation::Write)
1944 })
1945 );
1946
1947 println!("{}", storage.print_items().await);
1948
1949 std::assert_matches!(
1951 storage.fetch_item::<u64>(&mut buf, &()).await.unwrap(),
1952 Some(377) | None
1953 );
1954 }
1955
1956 #[test]
1957 async fn store_unit_key() {
1958 let mut storage = MapStorage::new(
1959 MockFlashBig::default(),
1960 const { MapConfig::new(0x000..0x1000) },
1961 Cache::new_uncached(),
1962 );
1963
1964 let mut data_buffer = AlignedBuf([0; 128]);
1965
1966 let item = storage
1967 .fetch_item::<&[u8]>(&mut data_buffer, &())
1968 .await
1969 .unwrap();
1970 assert_eq!(item, None);
1971
1972 storage
1973 .store_item(&mut data_buffer, &(), &[5u8])
1974 .await
1975 .unwrap();
1976 storage
1977 .store_item(&mut data_buffer, &(), &[5u8, 6])
1978 .await
1979 .unwrap();
1980
1981 let item = storage
1982 .fetch_item::<&[u8]>(&mut data_buffer, &())
1983 .await
1984 .unwrap()
1985 .unwrap();
1986 assert_eq!(item, &[5, 6]);
1987 }
1988
1989 #[test]
1990 async fn option_value() {
1991 let mut buffer = [0; 2];
1992
1993 assert_eq!(Some(42u8).serialize_into(&mut buffer), Ok(2));
1994 assert_eq!(Option::<u8>::deserialize_from(&buffer), Ok((Some(42u8), 2)));
1995 assert_eq!(buffer, [1, 42]);
1996
1997 let mut buffer = [0; 1];
1998
1999 assert_eq!(Option::<u8>::None.serialize_into(&mut buffer), Ok(1));
2000 assert_eq!(Option::<u8>::deserialize_from(&buffer), Ok((None, 1)));
2001 assert_eq!(buffer, [0]);
2002 }
2003
2004 #[test]
2005 async fn array_value() {
2006 let mut buffer = [0; 3];
2007 assert_eq!(Value::serialize_into(&[1u8, 2, 3], &mut buffer), Ok(3));
2008 assert_eq!(buffer, [1, 2, 3]);
2009 assert_eq!(
2010 <[u8; 3] as Value>::deserialize_from(&buffer),
2011 Ok(([1, 2, 3], 3))
2012 );
2013
2014 let mut buffer = [0; 4];
2015 assert_eq!(
2016 Value::serialize_into(&[0x1234u16, 0x5678], &mut buffer),
2017 Ok(4)
2018 );
2019 assert_eq!(buffer, [0x34, 0x12, 0x78, 0x56]);
2020 assert_eq!(
2021 <[u16; 2]>::deserialize_from(&buffer),
2022 Ok(([0x1234, 0x5678], 4))
2023 );
2024 }
2025
2026 #[test]
2027 async fn send_sync() {
2028 fn assert_sync<T: Sync + Send>(_: T) {}
2029
2030 let mut storage = MapStorage::new(
2031 MockFlashBig::default(),
2032 const { MapConfig::new(0x000..0x1000) },
2033 Cache::new_uncached(),
2034 );
2035
2036 let mut buffer = [0; 16];
2037
2038 assert_sync(storage.store_item_generic(&mut buffer, &0u8, &0u8));
2040 assert_sync(storage.store_item_generic::<dyn Value + Sync>(&mut buffer, &0u8, &0u8));
2042 assert_sync(storage.fetch_item::<u8>(&mut buffer, &0u8));
2043 }
2044
2045 #[cfg(feature = "postcard")]
2046 #[test]
2047 async fn postcard_value() {
2048 #[derive(PartialEq, Debug, serde::Serialize, serde::Deserialize)]
2049 struct Foo(u32);
2050 impl crate::map::PostcardValue<'_> for Foo {}
2051 let mut buffer = [0; 8];
2052 assert_eq!(Value::serialize_into(&Foo(123), &mut buffer), Ok(1));
2053 assert_eq!(
2054 <Foo as Value>::deserialize_from(&buffer[..1]),
2055 Ok((Foo(123), 1))
2056 );
2057 }
2058}