Skip to content

Commit 661cbb3

Browse files
committed
Merge branch 'master' of github.com:tweedegolf/sequential-storage into feature/remove-all-items
2 parents 654d7b6 + 5f4fa19 commit 661cbb3

File tree

7 files changed

+235
-71
lines changed

7 files changed

+235
-71
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
steps:
2121
- uses: actions/checkout@v3
2222
- uses: dtolnay/rust-toolchain@stable
23-
- run: cargo test
23+
- run: cargo test --features arrayvec
2424

2525
clippy:
2626
runs-on: ubuntu-latest

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"rust-analyzer.cargo.allTargets": false,
23
"rust-analyzer.linkedProjects": [
34
"Cargo.toml",
45
"fuzz/Cargo.toml",

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
The API before would lead to a lot of extra unncesessary binary size.
99
- *Breaking:* Removed the `StorageItem` trait in favor of two separate `Key` and `Value` traits. This helps cut
1010
binary size and is closer to what users of the map APIs were expecting.
11-
- *Breaking:* The error type is no longer generic over the Item error. That error variant has been renamed `MapValueError`
11+
- *Breaking:* The error type is no longer generic over the Item error. That error variant has been renamed `SerializationError`
1212
and carries a predefined error subtype.
1313
- Added `erase_all` function as a helper to erase the flash in a region.
1414
- *Breaking:* Changed the way that queue iteration works. Now there's an `iter` function instead of two separate `peek_many` and `pop_many` functions. The new iter returns an entry from which you can get the data that was just peeked. If you want to pop it, then call the pop function on the entry.
15+
- Added `arrayvec` feature that when activated impls the `Key` trait for `ArrayVec` and `ArrayString`.
1516

1617
## 1.0.0 01-03-24
1718

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ embedded-storage-async = "0.4.1"
1616
defmt = { version = "0.3", optional = true }
1717
futures = { version = "0.3.30", features = ["executor"], optional = true }
1818
approx = { version = "0.5.1", optional = true }
19+
arrayvec = { version = "0.7.4", default-features = false, optional = true }
1920

2021
[dev-dependencies]
2122
approx = "0.5.1"
@@ -25,4 +26,6 @@ futures-test = "0.3.30"
2526
[features]
2627
defmt-03 = ["dep:defmt"]
2728
std = []
28-
_test = ["dep:futures", "dep:approx", "std"]
29+
# Enable the implementation of the map Key trait for ArrayVec and ArrayString
30+
arrayvec = ["dep:arrayvec"]
31+
_test = ["dep:futures", "dep:approx", "std", "arrayvec"]

src/arrayvec_impl.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use arrayvec::{ArrayString, ArrayVec};
2+
3+
use crate::map::{Key, SerializationError};
4+
5+
impl<const CAP: usize> Key for ArrayVec<u8, CAP> {
6+
fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
7+
if buffer.len() < self.len() + 2 {
8+
return Err(SerializationError::BufferTooSmall);
9+
}
10+
11+
if self.len() > u16::MAX as usize {
12+
return Err(SerializationError::InvalidData);
13+
}
14+
15+
buffer[..2].copy_from_slice(&(self.len() as u16).to_le_bytes());
16+
buffer[2..][..self.len()].copy_from_slice(self);
17+
18+
Ok(self.len() + 2)
19+
}
20+
21+
fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
22+
let total_len = Self::get_len(buffer)?;
23+
24+
if buffer.len() < total_len {
25+
return Err(SerializationError::BufferTooSmall);
26+
}
27+
28+
let data_len = total_len - 2;
29+
30+
let mut output = ArrayVec::new();
31+
output
32+
.try_extend_from_slice(&buffer[2..][..data_len])
33+
.map_err(|_| SerializationError::InvalidFormat)?;
34+
35+
Ok((output, total_len))
36+
}
37+
38+
fn get_len(buffer: &[u8]) -> Result<usize, SerializationError> {
39+
if buffer.len() < 2 {
40+
return Err(SerializationError::BufferTooSmall);
41+
}
42+
43+
let len = u16::from_le_bytes(buffer[..2].try_into().unwrap());
44+
45+
Ok(len as usize + 2)
46+
}
47+
}
48+
49+
impl<const CAP: usize> Key for ArrayString<CAP> {
50+
fn serialize_into(&self, buffer: &mut [u8]) -> Result<usize, SerializationError> {
51+
if buffer.len() < self.len() + 2 {
52+
return Err(SerializationError::BufferTooSmall);
53+
}
54+
55+
if self.len() > u16::MAX as usize {
56+
return Err(SerializationError::InvalidData);
57+
}
58+
59+
buffer[..2].copy_from_slice(&(self.len() as u16).to_le_bytes());
60+
buffer[2..][..self.len()].copy_from_slice(self.as_bytes());
61+
62+
Ok(self.len() + 2)
63+
}
64+
65+
fn deserialize_from(buffer: &[u8]) -> Result<(Self, usize), SerializationError> {
66+
let total_len = Self::get_len(buffer)?;
67+
68+
if buffer.len() < total_len {
69+
return Err(SerializationError::BufferTooSmall);
70+
}
71+
72+
let data_len = total_len - 2;
73+
74+
let mut output = ArrayString::new();
75+
output
76+
.try_push_str(
77+
core::str::from_utf8(&buffer[2..][..data_len])
78+
.map_err(|_| SerializationError::InvalidFormat)?,
79+
)
80+
.map_err(|_| SerializationError::InvalidFormat)?;
81+
82+
Ok((output, total_len))
83+
}
84+
85+
fn get_len(buffer: &[u8]) -> Result<usize, SerializationError> {
86+
if buffer.len() < 2 {
87+
return Err(SerializationError::BufferTooSmall);
88+
}
89+
90+
let len = u16::from_le_bytes(buffer[..2].try_into().unwrap());
91+
92+
Ok(len as usize + 2)
93+
}
94+
}
95+
96+
#[cfg(test)]
97+
mod tests {
98+
use core::str::FromStr;
99+
100+
use super::*;
101+
102+
#[test]
103+
fn serde_arrayvec() {
104+
let mut buffer = [0; 128];
105+
106+
let val = ArrayVec::<u8, 12>::from_iter([0xAA; 12]);
107+
val.serialize_into(&mut buffer).unwrap();
108+
let new_val = ArrayVec::<u8, 12>::deserialize_from(&buffer).unwrap();
109+
110+
assert_eq!((val, 14), new_val);
111+
}
112+
113+
#[test]
114+
fn serde_arraystring() {
115+
let mut buffer = [0; 128];
116+
117+
let val = ArrayString::<45>::from_str("Hello world!").unwrap();
118+
val.serialize_into(&mut buffer).unwrap();
119+
let new_val = ArrayString::<45>::deserialize_from(&buffer).unwrap();
120+
121+
assert_eq!((val, 14), new_val);
122+
}
123+
}

src/lib.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ use core::{
1313
ops::{Deref, DerefMut, Range},
1414
};
1515
use embedded_storage_async::nor_flash::NorFlash;
16-
use map::MapValueError;
16+
use map::SerializationError;
1717

18+
#[cfg(feature = "arrayvec")]
19+
mod arrayvec_impl;
1820
pub mod cache;
1921
mod item;
2022
pub mod map;
@@ -377,8 +379,14 @@ pub enum Error<S> {
377379
BufferTooBig,
378380
/// A provided buffer was to small to be used (usize is size needed)
379381
BufferTooSmall(usize),
380-
/// A map value error
381-
MapValueError(MapValueError),
382+
/// A serialization error (from the key or value)
383+
SerializationError(SerializationError),
384+
}
385+
386+
impl<S> From<SerializationError> for Error<S> {
387+
fn from(v: SerializationError) -> Self {
388+
Self::SerializationError(v)
389+
}
382390
}
383391

384392
impl<S: PartialEq> PartialEq for Error<S> {
@@ -407,7 +415,7 @@ where
407415
f,
408416
"A provided buffer was to small to be used. Needed was {needed}"
409417
),
410-
Error::MapValueError(value) => write!(f, "Map value error: {value}"),
418+
Error::SerializationError(value) => write!(f, "Map value error: {value}"),
411419
}
412420
}
413421
}

0 commit comments

Comments
 (0)