From 57758cdc9a0ab7725bb50aa90e3a15d174526fef Mon Sep 17 00:00:00 2001 From: Astro Date: Fri, 11 Dec 2020 01:06:20 +0100 Subject: [PATCH] doc --- README.md | 26 ++++++++++++++++++++++++++ src/error.rs | 8 ++++++++ src/lib.rs | 15 ++++++++------- 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..db270bf --- /dev/null +++ b/README.md @@ -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 diff --git a/src/error.rs b/src/error.rs index dbfa19b..6eb1418 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,10 +18,14 @@ impl From> for Error { } } +/// 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 { + /// store is full even after automatic compaction SpaceExhausted, + /// error passed from the StoreBackend's `erase()` and `program()` + /// methods Backend(B), } diff --git a/src/lib.rs b/src/lib.rs index 5cae793..0f2a6f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,26 +20,25 @@ pub trait StoreBackend { size_of::() } - /// 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 { backend: B, } impl Store { + /// wrap a `StoreBackend` into a store pub fn new(backend: B) -> Self { Store { backend } } + /// read from `key` pub fn read(&self, key: &str) -> Result, ReadError> { let mut iter = Iter::new(self.backend.data().as_ref()); let mut value = None; @@ -53,6 +52,7 @@ impl Store { Ok(value) } + /// read from `key`, decode UTF-8 pub fn read_str(&self, key: &str) -> Result, ReadError> { self.read(key) .and_then(|value| value @@ -134,6 +134,7 @@ impl Store { Ok(()) } + /// store a buffer `value` at `key` pub fn write(&mut self, key: &str, value: &[u8]) -> Result<(), Error> { match self.append(key, value) { Err(Error::Write(WriteError::SpaceExhausted)) => { @@ -144,6 +145,7 @@ impl Store { } } + /// serialize 32-bit as ASCII, store at `key` pub fn write_int(&mut self, key: &str, value: u32) -> Result<(), Error> { let mut buf = [0; 16]; let mut wrapper = FmtWrapper::new(&mut buf); @@ -151,6 +153,7 @@ impl Store { self.write(key, wrapper.contents()) } + /// store a 0-byte tombstone value at `key` pub fn remove(&mut self, key: &str) -> Result<(), Error> { self.write(key, &[]) } @@ -162,5 +165,3 @@ impl Store { Ok(()) } } - -// TODO: quadratic iterator