lakers_shared/
buffer.rs

1use core::ops::Index;
2
3// NOTE: This constant is only here for now because it is only ever used in instances of EdhocBuffer.
4// TODO: move to lib.rs, once EdhocMessageBuffer is replaced by EdhocBuffer.
5pub const MAX_SUITES_LEN: usize = 9;
6
7#[derive(PartialEq, Debug)]
8#[repr(C)]
9pub enum EdhocBufferError {
10    BufferAlreadyFull,
11    SliceTooLong,
12}
13
14/// A fixed-size (but parameterized) buffer for EDHOC messages.
15///
16/// Trying to have an API as similar as possible to `heapless::Vec`,
17/// so that in the future it can be hot-swappable by the application.
18// TODO: replace EdhocMessageBuffer with EdhocBuffer all over the library
19// NOTE: how would this const generic thing work across the C and Python bindings?
20#[derive(PartialEq, Debug, Copy, Clone)]
21#[repr(C)]
22pub struct EdhocBuffer<const N: usize> {
23    pub content: [u8; N],
24    pub len: usize,
25}
26
27impl<const N: usize> Default for EdhocBuffer<N> {
28    fn default() -> Self {
29        EdhocBuffer {
30            content: [0; N],
31            len: 0,
32        }
33    }
34}
35
36impl<const N: usize> EdhocBuffer<N> {
37    pub const fn new() -> Self {
38        EdhocBuffer {
39            content: [0u8; N],
40            len: 0,
41        }
42    }
43
44    pub fn len(&self) -> usize {
45        self.len
46    }
47
48    pub fn capacity(&self) -> usize {
49        N
50    }
51
52    pub fn new_from_slice(slice: &[u8]) -> Result<Self, EdhocBufferError> {
53        let mut buffer = Self::new();
54        if buffer.fill_with_slice(slice).is_ok() {
55            Ok(buffer)
56        } else {
57            Err(EdhocBufferError::SliceTooLong)
58        }
59    }
60
61    pub fn get(self, index: usize) -> Option<u8> {
62        self.content.get(index).copied()
63    }
64
65    pub fn contains(&self, item: &u8) -> bool {
66        self.content.contains(item)
67    }
68
69    pub fn push(&mut self, item: u8) -> Result<(), EdhocBufferError> {
70        if self.len < self.content.len() {
71            self.content[self.len] = item;
72            self.len += 1;
73            Ok(())
74        } else {
75            Err(EdhocBufferError::BufferAlreadyFull)
76        }
77    }
78
79    pub fn get_slice(&self, start: usize, len: usize) -> Option<&[u8]> {
80        self.content.get(start..start + len)
81    }
82
83    pub fn as_slice(&self) -> &[u8] {
84        &self.content[0..self.len]
85    }
86
87    pub fn fill_with_slice(&mut self, slice: &[u8]) -> Result<(), EdhocBufferError> {
88        if slice.len() <= self.content.len() {
89            self.len = slice.len();
90            self.content[..self.len].copy_from_slice(slice);
91            Ok(())
92        } else {
93            Err(EdhocBufferError::SliceTooLong)
94        }
95    }
96
97    pub fn extend_from_slice(&mut self, slice: &[u8]) -> Result<(), EdhocBufferError> {
98        if self.len + slice.len() <= self.content.len() {
99            self.content[self.len..self.len + slice.len()].copy_from_slice(slice);
100            self.len += slice.len();
101            Ok(())
102        } else {
103            Err(EdhocBufferError::SliceTooLong)
104        }
105    }
106
107    // so far only used in test contexts
108    pub fn from_hex(hex: &str) -> Self {
109        let mut buffer = EdhocBuffer::new();
110        buffer.len = hex.len() / 2;
111        for (i, chunk) in hex.as_bytes().chunks(2).enumerate() {
112            let chunk_str = core::str::from_utf8(chunk).unwrap();
113            buffer.content[i] = u8::from_str_radix(chunk_str, 16).unwrap();
114        }
115        buffer
116    }
117}
118
119impl<const N: usize> Index<usize> for EdhocBuffer<N> {
120    type Output = u8;
121    fn index(&self, item: usize) -> &Self::Output {
122        &self.content[item]
123    }
124}
125
126impl<const N: usize> TryInto<EdhocBuffer<N>> for &[u8] {
127    type Error = ();
128
129    fn try_into(self) -> Result<EdhocBuffer<N>, Self::Error> {
130        let mut buffer = [0u8; N];
131        if self.len() <= buffer.len() {
132            buffer[..self.len()].copy_from_slice(self);
133
134            Ok(EdhocBuffer {
135                content: buffer,
136                len: self.len(),
137            })
138        } else {
139            Err(())
140        }
141    }
142}
143
144mod test {
145
146    #[test]
147    fn test_edhoc_buffer() {
148        let mut buffer = crate::EdhocBuffer::<5>::new();
149        assert_eq!(buffer.len, 0);
150        assert_eq!(buffer.content, [0; 5]);
151
152        buffer.push(1).unwrap();
153        assert_eq!(buffer.len, 1);
154        assert_eq!(buffer.content, [1, 0, 0, 0, 0]);
155    }
156
157    #[test]
158    fn test_new_from_slice() {
159        let buffer = crate::EdhocBuffer::<5>::new_from_slice(&[1, 2, 3]).unwrap();
160        assert_eq!(buffer.len, 3);
161        assert_eq!(buffer.content, [1, 2, 3, 0, 0]);
162    }
163}