MapStorage

Struct MapStorage 

Source
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>

Source

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.

Source

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.

Source

pub async fn store_item<'d, V: Value<'d>>( &mut self, data_buffer: &mut [u8], key: &K, item: &V, ) -> Result<(), Error<S::Error>>

Store a key-value pair into flash memory. It will (logically) overwrite the last value that has the same key.

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.

Source

pub async fn remove_item( &mut self, data_buffer: &mut [u8], search_key: &K, ) -> Result<(), Error<S::Error>>

Fully remove an item. Additional calls to fetch with the same key will return None until a new one is stored again.

This is really slow!

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.

Source

pub async fn remove_all_items( &mut self, data_buffer: &mut [u8], ) -> Result<(), Error<S::Error>>

Fully remove all stored items. Additional calls to fetch with any key will return None until new items are stored again.

This might be really slow! This doesn't simply erase flash, but goes through all items and marks them as deleted. This is better for flash endurance.

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.

Source

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.

You should be very careful when using the map item iterator:
  • 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);
}
Source

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.

Source

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).

Source

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.

Source

pub const fn flash(&mut self) -> &mut S

Get a reference to the flash. Mutating the memory is at your own risk.

Source

pub const fn flash_range(&self) -> Range<u32>

Get the flash range being used

Auto Trait Implementations§

§

impl<K, S, C> Freeze for MapStorage<K, S, C>
where S: Freeze, C: Freeze,

§

impl<K, S, C> RefUnwindSafe for MapStorage<K, S, C>

§

impl<K, S, C> Send for MapStorage<K, S, C>
where S: Send, C: Send, K: Send,

§

impl<K, S, C> Sync for MapStorage<K, S, C>
where S: Sync, C: Sync, K: Sync,

§

impl<K, S, C> Unpin for MapStorage<K, S, C>
where S: Unpin, C: Unpin, K: Unpin,

§

impl<K, S, C> UnwindSafe for MapStorage<K, S, C>
where S: UnwindSafe, C: UnwindSafe, K: UnwindSafe,

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.