pub struct MapStorage<K: Key, S: NorFlash, C: KeyCacheImpl<K>> { /* private fields */ }Expand description
A map-like storage
When a key-value is stored, it overwrites the any old items with the same key.
§Basic API
// Initialize the flash. This can be internal or external
let mut flash = init_flash();
// Create the storage instance
// We provide the flash addresses in which it will operate.
// The storage will not read, write or erase outside of this range.
// We also put the config in a const block so if the config is bad we'll get a compile time error
// With the generics we specify that this is a map with `u8` as the key
let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, NoCache::new());
// We need to give the crate a buffer to work with.
// It must be big enough to serialize the biggest value of your storage type in,
// rounded up to to word alignment of the flash. Some kinds of internal flash may require
// this buffer to be aligned in RAM as well.
let mut data_buffer = [0; 128];
// We can fetch an item from the flash. We're using `u8` as our key type and `u32` as our value type.
// Nothing is stored in it yet, so it will return None.
assert_eq!(
storage.fetch_item::<u32>(
&mut data_buffer,
&42,
).await.unwrap(),
None
);
// Now we store an item the flash with key 42.
// Again we make sure we pass the correct key and value types, u8 and u32.
// It is important to do this consistently.
storage.store_item(
&mut data_buffer,
&42u8,
&104729u32,
).await.unwrap();
// When we ask for key 42, we now get back a Some with the correct value
assert_eq!(
storage.fetch_item::<u32>(
&mut data_buffer,
&42,
).await.unwrap(),
Some(104729)
);For your convenience there are premade implementations for the Key and Value traits.
Implementations§
Source§impl<S: NorFlash, C: KeyCacheImpl<K>, K: Key> MapStorage<K, S, C>
impl<S: NorFlash, C: KeyCacheImpl<K>, K: Key> MapStorage<K, S, C>
Sourcepub const fn new(storage: S, config: MapConfig<S>, cache: C) -> Self
pub const fn new(storage: S, config: MapConfig<S>, cache: C) -> Self
Create a new map instance
The provided cache instance must be new or must be in the exact correct state for the current flash contents.
If the cache is bad, undesirable things will happen.
So, it’s ok to reuse the cache gotten from the Self::destroy method when the flash hasn’t changed since calling destroy.
Sourcepub async fn fetch_item<'d, V: Value<'d>>(
&mut self,
data_buffer: &'d mut [u8],
search_key: &K,
) -> Result<Option<V>, Error<S::Error>>
pub async fn fetch_item<'d, V: Value<'d>>( &mut self, data_buffer: &'d mut [u8], search_key: &K, ) -> Result<Option<V>, Error<S::Error>>
Get the last stored value from the flash that is associated with the given key. If no value with the key is found, None is returned.
You must make sure the used type as Value is correct for the key used. If not, there can be wrong values or deserialization errors.
The data buffer must be long enough to hold the longest serialized data of your Key + Value types combined, rounded up to flash word alignment.
Sourcepub async fn store_item<'d, V: Value<'d>>(
&mut self,
data_buffer: &mut [u8],
key: &K,
item: &V,
) -> Result<(), Error<S::Error>>
pub async fn store_item<'d, V: Value<'d>>( &mut self, data_buffer: &mut [u8], key: &K, item: &V, ) -> Result<(), Error<S::Error>>
Sourcepub async fn remove_item(
&mut self,
data_buffer: &mut [u8],
search_key: &K,
) -> Result<(), Error<S::Error>>where
S: MultiwriteNorFlash,
pub async fn remove_item(
&mut self,
data_buffer: &mut [u8],
search_key: &K,
) -> Result<(), Error<S::Error>>where
S: MultiwriteNorFlash,
Fully remove an item. Additional calls to fetch with the same key will return None until a new one is stored again.
All items in flash have to be read and deserialized to find the items with the key. This is unlikely to be cached well.
Alternatively, e.g. when you don’t have a MultiwriteNorFlash flash, you could store your value inside an Option
and store the value None to mark it as erased.
Sourcepub async fn remove_all_items(
&mut self,
data_buffer: &mut [u8],
) -> Result<(), Error<S::Error>>where
S: MultiwriteNorFlash,
pub async fn remove_all_items(
&mut self,
data_buffer: &mut [u8],
) -> Result<(), Error<S::Error>>where
S: MultiwriteNorFlash,
Fully remove all stored items. Additional calls to fetch with any key will return None until new items are stored again.
You might want to simply erase the flash range, e.g. if your flash does not implement MultiwriteNorFlash.
Consider using the helper method for that: Self::erase_all.
Sourcepub async fn fetch_all_items(
&mut self,
data_buffer: &mut [u8],
) -> Result<MapItemIter<'_, K, S, C>, Error<S::Error>>
pub async fn fetch_all_items( &mut self, data_buffer: &mut [u8], ) -> Result<MapItemIter<'_, K, S, C>, Error<S::Error>>
Get an iterator that iterates over all non-erased & non-corrupted items in the map.
- Because map doesn't erase the items when you insert a new one with the same key, so it's expected that the iterator returns items with the same key multiple times. Only the last returned one is the `active` one.
- The iterator requires ALL items in the storage have the SAME Value type. If you have different types of items in your map, the iterator might return incorrect data or error.
The following is a simple example of how to use the iterator:
let mut flash = init_flash();
let mut storage = MapStorage::<u8, _, _>::new(flash, const { MapConfig::new(0x1000..0x3000) }, NoCache::new());
let mut data_buffer = [0; 128];
// Create the iterator of map items
let mut iterator = storage.fetch_all_items(
&mut data_buffer
)
.await
.unwrap();
let mut all_items = HashMap::new();
// Iterate through all items, suppose the Key and Value types are u8, u32
while let Some((key, value)) = iterator
.next::<u32>(&mut data_buffer)
.await
.unwrap()
{
// Do something with the item.
// Please note that for the same key there might be multiple items returned,
// the last one is the current active one.
all_items.insert(key, value);
}Sourcepub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>>
pub fn erase_all(&mut self) -> impl Future<Output = Result<(), Error<S::Error>>>
Resets the flash in the entire given flash range.
This is just a thin helper function as it just calls the flash’s erase function.
Sourcepub const fn item_overhead_size() -> u32
pub const fn item_overhead_size() -> u32
Get the minimal overhead size per stored item for the given flash type.
The associated data of each item is additionally padded to a full flash word size, but that’s not part of this number.
This means the full item length is returned number + (data length).next_multiple_of(S::WORD_SIZE).
Sourcepub fn destroy(self) -> (S, C)
pub fn destroy(self) -> (S, C)
Destroy the instance to get back the flash and the cache.
The cache can be passed to a new storage instance, but only for the same flash region and if nothing has changed in flash.
Sourcepub const fn flash(&mut self) -> &mut S
pub const fn flash(&mut self) -> &mut S
Get a reference to the flash. Mutating the memory is at your own risk.
Sourcepub const fn flash_range(&self) -> Range<u32>
pub const fn flash_range(&self) -> Range<u32>
Get the flash range being used