doc
This commit is contained in:
parent
c0da68f48c
commit
57758cdc9a
|
@ -0,0 +1,26 @@
|
|||
# Simple Flash Key Value store
|
||||
|
||||
Tries to keep flash wear low by continuously appending data,
|
||||
automatically erasing and rewriting when full.
|
||||
|
||||
## Store requirements
|
||||
|
||||
* Reading must be possible by memory-mapping a `&[u8]` slice
|
||||
* Must support `erase()` for compaction,
|
||||
* Writing must support `program()` with an offset and `&[u8]` payload
|
||||
|
||||
For details see `trait StoreBackend`.
|
||||
|
||||
## TODO
|
||||
|
||||
* NoFlash backend
|
||||
* read_int()
|
||||
* write_str()
|
||||
* automatic value coercion
|
||||
* support for floats
|
||||
|
||||
### Ideas
|
||||
|
||||
* iterator (quadratic)
|
||||
* compaction to a second backend instead on stack
|
||||
* StoreBackend-configurable erased data detection
|
|
@ -18,10 +18,14 @@ impl<B> From<WriteError<B>> for Error<B> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Errors decoding the store
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ReadError {
|
||||
/// invalid record size
|
||||
InvalidSize { offset: usize, size: usize },
|
||||
/// missing separator
|
||||
MissingSeparator { offset: usize },
|
||||
/// `str::from_utf8` error
|
||||
Utf8Error(str::Utf8Error),
|
||||
}
|
||||
|
||||
|
@ -38,9 +42,13 @@ impl fmt::Display for ReadError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Errors when writing to the store
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WriteError<B> {
|
||||
/// store is full even after automatic compaction
|
||||
SpaceExhausted,
|
||||
/// error passed from the StoreBackend's `erase()` and `program()`
|
||||
/// methods
|
||||
Backend(B),
|
||||
}
|
||||
|
||||
|
|
15
src/lib.rs
15
src/lib.rs
|
@ -20,26 +20,25 @@ pub trait StoreBackend {
|
|||
size_of::<Self::Data>()
|
||||
}
|
||||
|
||||
/// utility for compaction, requires compile-time knowledge of the data length
|
||||
|
||||
type Error;
|
||||
fn erase(&mut self) -> Result<(), Self::Error>;
|
||||
fn program(&mut self, offset: usize, payload: &[u8]) -> Result<(), Self::Error>;
|
||||
/// called after many `program()` invocations to allow for eg. cache flushing
|
||||
/// called after repeated `program()` invocations to allow for eg. cache flushing
|
||||
fn program_done(&mut self) {}
|
||||
}
|
||||
|
||||
// TODO: NoFlash
|
||||
|
||||
/// Simple Flash Key Value Store
|
||||
pub struct Store<B: StoreBackend> {
|
||||
backend: B,
|
||||
}
|
||||
|
||||
impl<B: StoreBackend> Store<B> {
|
||||
/// wrap a `StoreBackend` into a store
|
||||
pub fn new(backend: B) -> Self {
|
||||
Store { backend }
|
||||
}
|
||||
|
||||
/// read from `key`
|
||||
pub fn read(&self, key: &str) -> Result<Option<&[u8]>, ReadError> {
|
||||
let mut iter = Iter::new(self.backend.data().as_ref());
|
||||
let mut value = None;
|
||||
|
@ -53,6 +52,7 @@ impl<B: StoreBackend> Store<B> {
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
/// read from `key`, decode UTF-8
|
||||
pub fn read_str(&self, key: &str) -> Result<Option<&str>, ReadError> {
|
||||
self.read(key)
|
||||
.and_then(|value| value
|
||||
|
@ -134,6 +134,7 @@ impl<B: StoreBackend> Store<B> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// store a buffer `value` at `key`
|
||||
pub fn write(&mut self, key: &str, value: &[u8]) -> Result<(), Error<B::Error>> {
|
||||
match self.append(key, value) {
|
||||
Err(Error::Write(WriteError::SpaceExhausted)) => {
|
||||
|
@ -144,6 +145,7 @@ impl<B: StoreBackend> Store<B> {
|
|||
}
|
||||
}
|
||||
|
||||
/// serialize 32-bit as ASCII, store at `key`
|
||||
pub fn write_int(&mut self, key: &str, value: u32) -> Result<(), Error<B::Error>> {
|
||||
let mut buf = [0; 16];
|
||||
let mut wrapper = FmtWrapper::new(&mut buf);
|
||||
|
@ -151,6 +153,7 @@ impl<B: StoreBackend> Store<B> {
|
|||
self.write(key, wrapper.contents())
|
||||
}
|
||||
|
||||
/// store a 0-byte tombstone value at `key`
|
||||
pub fn remove(&mut self, key: &str) -> Result<(), Error<B::Error>> {
|
||||
self.write(key, &[])
|
||||
}
|
||||
|
@ -162,5 +165,3 @@ impl<B: StoreBackend> Store<B> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: quadratic iterator
|
||||
|
|
Loading…
Reference in New Issue