1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
/// Trait for output buffers that can accept encoded data.
///
/// Message builders accept an argumenet of this type and will output their data in to the buffer.
///
/// The buffer must support simple seeking to a previously retrieved position. This is used when
/// calculating checksums.
pub trait OutputBuffer {
/// The cursor type
type Cursor: Copy;
/// Append bytes to the buffer
fn output(&mut self, buf: &[u8]);
/// Retrieve the cursor representing the position of the last appended byte
fn cur_position(&self) -> Self::Cursor;
/// Replace the byte at the cursor position with a new value
fn update(&mut self, cursor: Self::Cursor, value: u8);
/// Retrieve a reference to all data pushed after the cursor
fn data_since(&self, cursor: Self::Cursor) -> &[u8];
}
/// A scratch pad based `OutputBuffer`.
///
/// Uses a statically sized inlined buffer. For serializing multiple messages in a row, the buffer
/// can be reset if needed.
pub struct ScratchOutput<const MAX_SIZE: usize = 64> {
buffer: [u8; MAX_SIZE],
idx: usize,
}
impl<const MAX_SIZE: usize> ScratchOutput<MAX_SIZE> {
/// Retrieve the currently built buffer
pub fn result(&self) -> &[u8] {
&self.buffer[..self.idx]
}
/// Reset the buffer, clearing it
pub fn reset(&mut self) {
self.idx = 0;
}
/// Create a new buffer
pub const fn new() -> Self {
Self {
buffer: [0u8; MAX_SIZE],
idx: 0,
}
}
}
impl<const MAX_SIZE: usize> OutputBuffer for ScratchOutput<MAX_SIZE> {
type Cursor = usize;
fn output(&mut self, buf: &[u8]) {
let area = &mut self.buffer[self.idx..];
let len = buf.len().clamp(0, area.len());
area[..len].copy_from_slice(buf);
self.idx += len;
}
fn cur_position(&self) -> Self::Cursor {
self.idx
}
fn update(&mut self, cursor: Self::Cursor, value: u8) {
if cursor < self.idx {
if let Some(b) = self.buffer.get_mut(cursor) {
*b = value;
}
}
}
fn data_since(&self, cursor: Self::Cursor) -> &[u8] {
if cursor >= self.idx {
&[]
} else {
&self.buffer[cursor..self.idx]
}
}
}
#[cfg(feature = "std")]
impl OutputBuffer for Vec<u8> {
type Cursor = usize;
fn output(&mut self, buf: &[u8]) {
self.extend(buf)
}
fn cur_position(&self) -> Self::Cursor {
self.len().saturating_sub(1)
}
fn update(&mut self, cursor: Self::Cursor, value: u8) {
self[cursor] = value;
}
fn data_since(&self, cursor: Self::Cursor) -> &[u8] {
&self[cursor..]
}
}