Module sequential_storage::map

source ·
Expand description

A module for storing key-value pairs in flash with minimal erase cycles.

When a key-value is stored, it overwrites the any old items with the same key.

Make sure to use the same StorageItem type on a given range in flash. In theory you could use multiple types if you’re careful, but they must at least have the same key definition and format.

§Basic API:

// We create the type we want to store in this part of flash.
// It itself must contain the key and the value.
// On this part of flash, we must only call the functions using this type.
// If you start to mix, bad things will happen.

#[derive(Debug, PartialEq)]
struct MyCustomType {
    key: u8,
    data: u32,
}

// We implement StorageItem for our type. This lets the crate
// know how to serialize and deserialize the data and get its key for comparison.

impl StorageItem for MyCustomType {
    type Key = u8;
    type Error = Error;
     
    fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
        if buffer.len() < 5 {
            return Err(Error::BufferTooSmall);
        }

        buffer[0] = self.key;
        buffer[1..5].copy_from_slice(&self.data.to_le_bytes());

        Ok(5)
    }
    fn deserialize_from(buffer: &[u8]) -> Result<Self, Self::Error> {
        // We don't have to check the length. This buffer has the same length
        // as what we serialized, so in this case it's always 5.
         
        Ok(Self {
            key: buffer[0],
            data: u32::from_le_bytes(buffer[1..5].try_into().unwrap()),
        })
    }
    fn key(&self) -> Self::Key { self.key }
}

#[derive(Debug)]
enum Error {
    BufferTooSmall
}

// Initialize the flash. This can be internal or external
let mut flash = init_flash();
// These are the flash addresses in which the crate will operate.
// The crate will not read, write or erase outside of this range.
let flash_range = 0x1000..0x3000;
// 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 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.
// Nothing is stored in it yet, so it will return None.

assert_eq!(
    fetch_item::<MyCustomType, _>(
        &mut flash,
        flash_range.clone(),
        NoCache::new(),
        &mut data_buffer,
        42,
    ).await.unwrap(),
    None
);

// Now we store an item the flash with key 42

store_item::<MyCustomType, _>(
    &mut flash,
    flash_range.clone(),
    NoCache::new(),
    &mut data_buffer,
    &MyCustomType { key: 42, data: 104729 },
).await.unwrap();

// When we ask for key 42, we not get back a Some with the correct value

assert_eq!(
    fetch_item::<MyCustomType, _>(
        &mut flash,
        flash_range.clone(),
        NoCache::new(),
        &mut data_buffer,
        42,
    ).await.unwrap(),
    Some(MyCustomType { key: 42, data: 104729 })
);

Enums§

  • The error type for map operations

Traits§

  • A way of serializing and deserializing items in the storage.

Functions§

  • Get a storage item from the flash. Only the last stored item of the given key is returned.
  • Store an item into flash memory. It will overwrite the last value that has the same key. The flash needs to be at least 2 pages long.
  • Try to repair the state of the flash to hopefull get back everything in working order. Care is taken that no data is lost, but this depends on correctly repairing the state and so is only best effort.