Skip to content

Commit 2ae4b04

Browse files
committed
Builtin codec for heapless::Vec
1 parent 3bc3615 commit 2ae4b04

2 files changed

Lines changed: 137 additions & 20 deletions

File tree

byten/src/lib.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,27 @@
1313
//! - `derive`: Enables procedural macros for deriving self-coded trait implementations for structs and enums (enabled by default).
1414
//!
1515
//! # Built-in Codecs
16-
//! | Codec Type | Default for | #[byten(...)] | Codes |
17-
//! |-----------------------|-------------|-----------------------------|---------------------------------------------------------------|
18-
//! | [`U8Codec`] | `u8` | `u8` | `u8` type |
19-
//! | [`I8Codec`] | `i8` | `i8` | `i8` type |
20-
//! | [`U8ArrayCodec`] | `[u8; N]` | `[u8; N]` | fixed-size arrays of `u8` of size `N` |
21-
//! | [`U8ArrayRefCodec`] | `&[u8; N]` | `&[u8; N]` | references to fixed-size arrays of `u8` of size `N` |
22-
//! | [`BoolCodec`] | `bool` | `bool` | `bool` type |
23-
//! | [`BoxCodec`] | `Box<T>` | `Box<T>` or `... box` | `Box<T>` where `t_codec` is the codec for `T` |
24-
//! | [`ArrayCodec`] | | `... $arr` | fixed-size arrays, `[Item; N]` |
25-
//! | [`EndianCodec`] | | `... $be` or `... $le` | primitive types with little/big endian byte orders |
26-
//! | [`SelfCoded`] | | `{SelfCoded::<T>::new()}` | derived type `T` |
27-
//! | [`UTF8Codec`] | | `$utf8` | `&str` type using the provided bytes codec |
28-
//! | [`CStrCodec`] | `CStr` | `CStr` or `&CStr` | C-style strings (`CStr` and `&CStr`) |
29-
//! | [`OwnedCodec`] | | `... $own` | owned data by cloning from borrowed data |
30-
//! | [`VecCodec`] | | `... $vec[len]` | `Vec<Item>` using the provided item and length codecs |
31-
//! | [`RemainingCodec`] | | `..` | all remaining bytes in the input |
32-
//! | [`UVarBECodec`] | | `... $uvarbe` | unsigned variable-length big-endian integers |
33-
//! | [`OptionCodec`] | `Option<T>` | `... $opt` | `Option<T>` using the provided codec for `T` |
34-
//! | [`BytesCodec`] | | `$bytes[len]` | byte slices with length prefixed by the provided codec |
35-
//! | [`PhantomCodec`] | | `= expr` | phantom codec with 0 size, codes the given constant value |
16+
//! | Codec Type | Default for | #[byten(...)] | Codes |
17+
//! |-----------------------|-------------|-----------------------------------------|-----------------------------------------------------------------------|
18+
//! | [`U8Codec`] | `u8` | `u8` | `u8` type |
19+
//! | [`I8Codec`] | `i8` | `i8` | `i8` type |
20+
//! | [`U8ArrayCodec`] | `[u8; N]` | `[u8; N]` | fixed-size arrays of `u8` of size `N` |
21+
//! | [`U8ArrayRefCodec`] | `&[u8; N]` | `&[u8; N]` | references to fixed-size arrays of `u8` of size `N` |
22+
//! | [`BoolCodec`] | `bool` | `bool` | `bool` type |
23+
//! | [`BoxCodec`] | `Box<T>` | `Box<T>` or `... box` | `Box<T>` where `t_codec` is the codec for `T` |
24+
//! | [`ArrayCodec`] | | `... $arr` | fixed-size arrays, `[Item; N]` |
25+
//! | [`EndianCodec`] | | `... $be` or `... $le` | primitive types with little/big endian byte orders |
26+
//! | [`SelfCoded`] | | `{SelfCoded::<T>::new()}` | derived type `T` |
27+
//! | [`UTF8Codec`] | | `$utf8` | `&str` type using the provided bytes codec |
28+
//! | [`CStrCodec`] | `CStr` | `CStr` or `&CStr` | C-style strings (`CStr` and `&CStr`) |
29+
//! | [`OwnedCodec`] | | `... $own` | owned data by cloning from borrowed data |
30+
//! | [`VecCodec`] | | `... $vec[len]` | `Vec<Item>` using the provided item and length codecs |
31+
//! | [`HeaplessVecCodec`] | | `{HeaplessVecCodec::new(len, item)}` | `heapless::Vec<Item, N>` using the provided item and length codecs |
32+
//! | [`RemainingCodec`] | | `..` | all remaining bytes in the input |
33+
//! | [`UVarBECodec`] | | `... $uvarbe` | unsigned variable-length big-endian integers |
34+
//! | [`OptionCodec`] | `Option<T>` | `... $opt` | `Option<T>` using the provided codec for `T` |
35+
//! | [`BytesCodec`] | | `$bytes[len]` | byte slices with length prefixed by the provided codec |
36+
//! | [`PhantomCodec`] | | `= expr` | phantom codec with 0 size, codes the given constant value |
3637
//!
3738
//! # Usage in `no_std` Environments
3839
//!

byten/src/var.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,122 @@ where
118118
}
119119
}
120120

121+
/// A codec for heapless vectors of fixed/dynamic sized elements.
122+
/// The length of the vector is encoded/decoded as a prefix using the provided length codec.
123+
/// The maximum size of the vector is determined by the const generic parameter N.
124+
///
125+
/// # Examples
126+
/// ```rust
127+
/// use byten::{HeaplessVecCodec, Encoder, Decoder, Measurer, EncoderToVec as _, EndianCodec};
128+
///
129+
/// let length_codec = EndianCodec::<u16>::le();
130+
/// let item_codec = EndianCodec::<u32>::le();
131+
/// let codec = HeaplessVecCodec::<_, _, 10>::new(item_codec, length_codec);
132+
///
133+
/// let vec: heapless::Vec<u32, 10> = heapless::Vec::from_slice(&[1, 2, 3, 4]).unwrap();
134+
///
135+
/// let encoded = codec.encode_to_heapless_vec::<20>(&vec).unwrap();
136+
/// assert_eq!(encoded.len(), 2 + 4 * 4);
137+
///
138+
/// let mut decode_offset = 0;
139+
/// let decoded: heapless::Vec<u32, 10> = codec.decode(&encoded, &mut decode_offset).unwrap();
140+
/// assert_eq!(decoded, vec);
141+
///
142+
/// let size = codec.measure(&vec).unwrap();
143+
/// assert_eq!(size, 2 + 4 * 4);
144+
/// ```
145+
pub struct HeaplessVecCodec<Item, Length, const N: usize> {
146+
pub item: Item,
147+
pub length: Length,
148+
}
149+
150+
impl<Item, Length, const N: usize> HeaplessVecCodec<Item, Length, N> {
151+
pub const fn new(item: Item, length: Length) -> Self {
152+
Self { item, length }
153+
}
154+
}
155+
156+
impl<'encoded, 'decoded, 'length, Item, Length, const N: usize> crate::Decoder<'encoded, 'decoded>
157+
for HeaplessVecCodec<Item, Length, N>
158+
where
159+
Item: crate::Decoder<'encoded, 'decoded>,
160+
Length: crate::Decoder<'encoded, 'length>,
161+
Length::Decoded: TryInto<usize>,
162+
<Length::Decoded as TryInto<usize>>::Error: Into<crate::DecodeError>,
163+
'encoded: 'decoded,
164+
{
165+
type Decoded = heapless::Vec<Item::Decoded, N>;
166+
167+
fn decode(
168+
&self,
169+
encoded: &'encoded [u8],
170+
offset: &mut usize,
171+
) -> Result<Self::Decoded, crate::DecodeError> {
172+
let size = self
173+
.length
174+
.decode(encoded, offset)?
175+
.try_into()
176+
.map_err(Into::into)?;
177+
if size > N {
178+
return Err(crate::DecodeError::InvalidData);
179+
}
180+
let mut vec: heapless::Vec<Item::Decoded, N> = heapless::Vec::new();
181+
for _ in 0..size {
182+
let item = self.item.decode(encoded, offset)?;
183+
vec.push(item)
184+
.unwrap_or_else(|_| panic!("unexpected heapless vec overflow"));
185+
}
186+
Ok(vec)
187+
}
188+
}
189+
190+
impl<Item, Length, const N: usize> crate::Encoder for HeaplessVecCodec<Item, Length, N>
191+
where
192+
Length: crate::Encoder,
193+
Length::Decoded: TryFrom<usize>,
194+
<Length::Decoded as TryFrom<usize>>::Error: Into<crate::EncodeError>,
195+
Item: crate::Encoder,
196+
Item::Decoded: Sized,
197+
{
198+
type Decoded = heapless::Vec<Item::Decoded, N>;
199+
200+
fn encode(
201+
&self,
202+
decoded: &Self::Decoded,
203+
encoded: &mut [u8],
204+
offset: &mut usize,
205+
) -> Result<(), crate::EncodeError> {
206+
let size = decoded.len();
207+
self.length
208+
.encode(&size.try_into().map_err(Into::into)?, encoded, offset)?;
209+
for item in decoded.iter() {
210+
self.item.encode(item, encoded, offset)?;
211+
}
212+
Ok(())
213+
}
214+
}
215+
216+
impl<Item, Length, const N: usize> crate::Measurer for HeaplessVecCodec<Item, Length, N>
217+
where
218+
Length: crate::Measurer,
219+
Length::Decoded: TryFrom<usize>,
220+
<Length::Decoded as TryFrom<usize>>::Error: Into<crate::error::EncodeError>,
221+
Item: crate::Measurer,
222+
Item::Decoded: Sized,
223+
{
224+
type Decoded = heapless::Vec<Item::Decoded, N>;
225+
226+
fn measure(&self, decoded: &Self::Decoded) -> Result<usize, crate::error::EncodeError> {
227+
let size = decoded.len();
228+
let size_measure = self.length.measure(&size.try_into().map_err(Into::into)?)?;
229+
let mut items_measure = 0;
230+
for item in decoded.iter() {
231+
items_measure += self.item.measure(item)?;
232+
}
233+
Ok(size_measure + items_measure)
234+
}
235+
}
236+
121237
/// A codec that draws all remaining bytes from the input during decoding,
122238
/// and writes all bytes during encoding.
123239
///

0 commit comments

Comments
 (0)