Skip to main content

sfkv/
lib.rs

1#![no_std]
2
3use core::str;
4use byteorder::{ByteOrder, BigEndian};
5#[cfg(feature = "postcard-values")]
6use serde::{Deserialize, Serialize};
7
8mod error;
9pub use error::{Error, ReadError, WriteError};
10mod iter;
11use iter::Iter;
12pub mod no_flash;
13mod test;
14
15/// Backend interface for `Store`
16pub trait StoreBackend {
17    /// type returned by `data()` for reading the flash
18    type Data: ?Sized + AsRef<[u8]>;
19
20    /// memory-mapped
21    fn data(&self) -> &Self::Data;
22    /// size of flash page
23    fn len(&self) -> usize {
24        self.data().as_ref().len()
25    }
26
27    /// error type returned by `erase()`/`flash()` operations
28    type Error;
29    /// erase flash page
30    fn erase(&mut self) -> Result<(), Self::Error>;
31    /// program flash with offset into flash page
32    fn program(&mut self, offset: usize, payload: &[u8]) -> Result<(), Self::Error>;
33    /// called after repeated `program()` invocations to allow for eg. cache flushing
34    fn program_done(&mut self) {}
35
36    /// need for automatic compaction
37    ///
38    /// leaves memory management to the implementer
39    fn backup_space(&self) -> &'static mut [u8];
40}
41
42/// Simple Flash Key Value Store
43pub struct Store<B: StoreBackend> {
44    backend: B,
45}
46
47impl<B: StoreBackend> Store<B> {
48    /// wrap a `StoreBackend` into a store
49    pub fn new(backend: B) -> Self {
50        Store { backend }
51    }
52
53    /// read from `key`
54    pub fn read(&self, key: &str) -> Result<Option<&[u8]>, ReadError> {
55        let mut iter = Iter::new(self.backend.data().as_ref());
56        let mut value = None;
57        while let Some(result) = iter.next() {
58            let (record_key, record_value) = result?;
59            if key.as_bytes() == record_key {
60                // last write wins
61                value = Some(record_value)
62            }
63        }
64        Ok(value)
65    }
66
67    /// read from `key`, decode UTF-8
68    pub fn read_str(&self, key: &str) -> Result<Option<&str>, ReadError> {
69        self.read(key)
70            .and_then(|value| value
71                      .map(|value| str::from_utf8(value)
72                           .map_err(ReadError::Utf8Error)
73                      )
74                      .transpose()
75            )
76    }
77
78    /// read from `key`, decode with `postcard`
79    #[cfg(feature = "postcard-values")]
80    pub fn read_value<'a, T: Deserialize<'a>>(&'a self, key: &str) -> Result<Option<T>, Error<B::Error>> {
81        self.read(key)?
82            .map(
83                |data| postcard::from_bytes(data)
84                    .map_err(Error::Decode)
85            ).transpose()
86    }
87
88    /// how many bytes are currently used
89    ///
90    /// equally, offset of free space
91    pub fn get_bytes_used(&self) -> Result<usize, ReadError> {
92        let mut iter = Iter::new(self.backend.data().as_ref());
93        while let Some(result) = iter.next() {
94            let _ = result?;
95        }
96        Ok(iter.offset)
97    }
98
99    unsafe fn append_at(&mut self, mut offset: usize,
100                        key: &[u8], value: &[u8]) -> Result<usize, WriteError<B::Error>> {
101        let record_size = 4 + key.len() + 1 + value.len();
102        if offset + record_size > self.backend.len() {
103            return Err(WriteError::SpaceExhausted)
104        }
105
106        let mut record_size_bytes = [0u8; 4];
107        BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32);
108
109        {
110            let mut write = |payload| -> Result<(), WriteError<B::Error>> {
111                self.backend.program(offset, payload)
112                    .map_err(WriteError::Backend)?;
113                offset += payload.len();
114                Ok(())
115            };
116
117            write(&record_size_bytes[..])?;
118            write(key)?;
119            write(&[0])?;
120            write(value)?;
121        }
122        self.backend.program_done();
123
124        Ok(offset)
125    }
126
127    fn compact(&mut self) -> Result<(), Error<B::Error>> {
128        let old_data = self.backend.backup_space();
129        old_data.copy_from_slice(self.backend.data().as_ref());
130
131        self.erase()?;
132
133        // This is worst-case quadratic, but we're limited by a small SPI flash sector size,
134        // so it does not really matter.
135        let mut offset = 0;
136        let mut iter = Iter::new(old_data.as_ref());
137        'iter: while let Some(result) = iter.next() {
138            let (key, value) = result?;
139            if value.is_empty() {
140                // This is a removed entry, ignore it.
141                continue
142            }
143
144            let mut next_iter = iter.clone();
145            while let Some(next_result) = next_iter.next() {
146                let (next_key, _) = next_result?;
147                if key == next_key {
148                    // There's another entry that overwrites this one, ignore this one.
149                    continue 'iter
150                }
151            }
152            offset = unsafe { self.append_at(offset, key, value)? };
153        }
154
155        Ok(())
156    }
157
158    fn append(&mut self, key: &str, value: &[u8]) -> Result<(), Error<B::Error>> {
159        let free_offset = {
160            let mut iter = Iter::new(self.backend.data().as_ref());
161            let mut not_modified = false;
162            while let Some(result) = iter.next() {
163                let (record_key, record_value) = result?;
164                if key.as_bytes() == record_key {
165                    not_modified = value == record_value;
166                }
167            }
168            if not_modified {
169                return Ok(())
170            }
171            iter.offset
172        };
173
174        unsafe { self.append_at(free_offset, key.as_bytes(), value)? };
175        Ok(())
176    }
177
178    /// store a buffer `value` at `key`
179    pub fn write<V: AsRef<[u8]>>(&mut self, key: &str, value: V) -> Result<(), Error<B::Error>> {
180        let value = value.as_ref();
181        match self.append(key, value) {
182            Err(Error::Write(WriteError::SpaceExhausted)) => {
183                self.compact()?;
184                self.append(key, value)
185            }
186            res => res
187        }
188    }
189
190    /// encode with `postcard`, write at `key`
191    #[cfg(feature = "postcard-values")]
192    pub fn write_value<T, V>(&mut self, key: &str, value: &T, mut value_buf: V) -> Result<(), Error<B::Error>>
193    where
194        T: Serialize,
195        V: AsMut<[u8]>,
196    {
197        let data = postcard::to_slice(value, value_buf.as_mut())
198            .map_err(Error::Encode)?;
199        self.write(key, data)
200    }
201
202    /// store a 0-byte tombstone value at `key`
203    pub fn remove(&mut self, key: &str) -> Result<(), Error<B::Error>> {
204        self.write(key, &[])
205    }
206
207    /// invokes erase on the backend (this is no compaction!)
208    pub fn erase(&mut self) -> Result<(), WriteError<B::Error>> {
209        self.backend.erase()
210            .map_err(WriteError::Backend)?;
211
212        Ok(())
213    }
214}