1use crate::{EncodeSize, Error, Read, ReadExt, Write};
4use bytes::{Buf, BufMut};
5
6const CONTINUATION_BIT: u8 = 1 << 7;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
11#[error("mode value must fit in seven bits")]
12pub struct InvalidMode;
13
14#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
28pub struct Mode(u8);
29
30impl Mode {
31 pub const fn new(value: u8) -> Option<Self> {
33 if value < CONTINUATION_BIT {
34 Some(Self(value))
35 } else {
36 None
37 }
38 }
39}
40
41impl TryFrom<u8> for Mode {
42 type Error = InvalidMode;
43
44 fn try_from(value: u8) -> Result<Self, Self::Error> {
45 Self::new(value).ok_or(InvalidMode)
46 }
47}
48
49impl From<Mode> for u8 {
50 fn from(mode: Mode) -> Self {
51 mode.0
52 }
53}
54
55#[cfg(feature = "arbitrary")]
56impl<'a> arbitrary::Arbitrary<'a> for Mode {
57 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
58 Ok(Self(u.int_in_range(0..=(CONTINUATION_BIT - 1))?))
59 }
60}
61
62#[cfg(not(any(
86 commonware_stability_GAMMA,
87 commonware_stability_DELTA,
88 commonware_stability_EPSILON,
89 commonware_stability_RESERVED
90)))] #[macro_export]
92macro_rules! mode {
93 ($value:literal) => {
94 const { $crate::Mode::new($value).expect("mode value must fit in seven bits") }
95 };
96 ($value:expr) => {
97 $crate::Mode::new($value).expect("mode value must fit in seven bits")
98 };
99}
100
101#[cfg(not(any(
121 commonware_stability_GAMMA,
122 commonware_stability_DELTA,
123 commonware_stability_EPSILON,
124 commonware_stability_RESERVED
125)))] #[macro_export]
127macro_rules! modes {
128 ($($mode:expr),* $(,)?) => {
129 $crate::Modes::new([
130 $(::core::convert::Into::<$crate::Mode>::into($mode)),*
131 ])
132 };
133}
134
135#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
161pub struct Modes<const N: usize> {
162 encoded: [u8; N],
163 len: usize,
164}
165
166impl<const N: usize> Modes<N> {
167 pub fn new(modes: [Mode; N]) -> Option<Self> {
173 const {
174 assert!(N > 0, "N must be greater than 0");
175 }
176
177 let mut encoded = modes.map(u8::from);
178 let last = encoded.iter().rposition(|&mode| mode != 0)?;
179 for mode in &mut encoded[..last] {
180 *mode |= CONTINUATION_BIT;
181 }
182 Some(Self {
183 encoded,
184 len: last + 1,
185 })
186 }
187}
188
189impl<const N: usize> Write for Modes<N> {
190 fn write(&self, buf: &mut impl BufMut) {
191 buf.put_slice(&self.encoded[..self.len]);
192 }
193}
194
195impl<const N: usize> EncodeSize for Modes<N> {
196 fn encode_size(&self) -> usize {
197 self.len
198 }
199}
200
201impl<const N: usize> Read for Modes<N> {
202 type Cfg = ();
203
204 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, Error> {
205 const {
206 assert!(N > 0, "N must be greater than 0");
207 }
208
209 let mut encoded = [0; N];
212 for index in 0..N {
213 let byte = u8::read(buf)?;
214 encoded[index] = byte;
215 if byte & CONTINUATION_BIT == 0 {
216 if byte == 0 {
217 return Err(Error::Invalid("Modes", "trailing mode must be non-zero"));
218 }
219 return Ok(Self {
220 encoded,
221 len: index + 1,
222 });
223 }
224 }
225
226 Err(Error::Invalid("Modes", "too many mode values"))
227 }
228}
229
230#[cfg(feature = "arbitrary")]
231impl<'a, const N: usize> arbitrary::Arbitrary<'a> for Modes<N> {
232 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
233 const {
234 assert!(N > 0, "N must be greater than 0");
235 }
236
237 let len = u.int_in_range(1..=N)?;
238 let mut modes = [Mode(0); N];
239 for mode in &mut modes[..len - 1] {
240 *mode = u.arbitrary()?;
241 }
242 modes[len - 1] = Mode(u.int_in_range(1..=(CONTINUATION_BIT - 1))?);
243 Self::new(modes).ok_or(arbitrary::Error::IncorrectFormat)
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250 use crate::{DecodeExt, Encode};
251
252 fn assert_encoding<const N: usize>(modes: [u8; N], expected: &[u8]) {
253 let modes = Modes::new(modes.map(|value| mode!(value))).unwrap();
254 assert_eq!(modes.encode_size(), expected.len());
255 let encoded = modes.encode();
256 assert_eq!(encoded.as_ref(), expected);
257 assert_eq!(Modes::<N>::decode(encoded).unwrap(), modes);
258 }
259
260 #[test]
261 fn encodes_continuations() {
262 assert!(Modes::new([mode!(0), mode!(0)]).is_none());
264
265 assert_encoding([1, 0], &[0x01]);
267
268 assert_encoding([0, 1], &[0x80, 0x01]);
270 assert_encoding([1, 0, 1], &[0x81, 0x80, 0x01]);
271
272 assert_encoding([0x7f, 0x7f], &[0xff, 0x7f]);
274 }
275
276 #[test]
277 fn macro_converts_heterogeneous_values() {
278 struct Enabled;
279
280 impl From<Enabled> for Mode {
281 fn from(_: Enabled) -> Self {
282 mode!(1)
283 }
284 }
285
286 let modes = modes![Enabled, mode!(0), Enabled].unwrap();
287 assert_eq!(modes.encode().as_ref(), &[0x81, 0x80, 0x01]);
288 }
289
290 #[test]
291 fn mode_enforces_seven_bit_values() {
292 for value in [0, 0x7f] {
293 let mode = Mode::new(value).unwrap();
294 assert_eq!(u8::from(mode), value);
295 assert_eq!(Mode::try_from(value), Ok(mode));
296 }
297
298 for value in [0x80, 0xff] {
299 assert_eq!(Mode::new(value), None);
300 assert_eq!(Mode::try_from(value), Err(InvalidMode));
301 }
302 }
303
304 #[test]
305 fn mode_macro_constructs_literals_and_expressions() {
306 const MAX: Mode = mode!(0x7f);
307 let value = 1u8;
308
309 assert_eq!(u8::from(MAX), 0x7f);
310 assert_eq!(mode!(value), mode!(1));
311 }
312
313 #[test]
314 #[should_panic(expected = "mode value must fit in seven bits")]
315 fn mode_macro_rejects_invalid_expressions() {
316 let value = 0x80u8;
317 let _ = mode!(value);
318 }
319
320 #[test]
321 fn rejects_truncated_and_oversized_packets() {
322 assert!(matches!(
323 Modes::<2>::decode(&[][..]),
324 Err(Error::EndOfBuffer)
325 ));
326 assert!(matches!(
327 Modes::<2>::decode(&[0x80][..]),
328 Err(Error::EndOfBuffer)
329 ));
330 assert!(matches!(
331 Modes::<1>::decode(&[0x80][..]),
332 Err(Error::Invalid("Modes", _))
333 ));
334 assert!(matches!(
335 Modes::<2>::decode(&[0x80, 0x80][..]),
336 Err(Error::Invalid("Modes", _))
337 ));
338 assert!(matches!(
339 Modes::<2>::decode(&[0x80, 0x80, 0x01][..]),
340 Err(Error::Invalid("Modes", _))
341 ));
342 }
343
344 #[test]
345 fn rejects_non_canonical_packets() {
346 assert!(matches!(
347 Modes::<1>::decode(&[0x00][..]),
348 Err(Error::Invalid("Modes", _))
349 ));
350 assert!(matches!(
351 Modes::<2>::decode(&[0x80, 0x00][..]),
352 Err(Error::Invalid("Modes", _))
353 ));
354 assert!(matches!(
355 Modes::<2>::decode(&[0x81, 0x00][..]),
356 Err(Error::Invalid("Modes", _))
357 ));
358 }
359
360 #[test]
361 fn read_stops_at_packet_boundary() {
362 let mut encoded = &[0x01, 0x02][..];
363 let modes = Modes::<2>::read(&mut encoded).unwrap();
364 assert_eq!(modes.encode().as_ref(), &[0x01]);
365 assert_eq!(encoded, &[0x02]);
366 assert!(matches!(
367 Modes::<2>::decode(&[0x01, 0x02][..]),
368 Err(Error::ExtraData(1))
369 ));
370 }
371
372 #[cfg(feature = "arbitrary")]
373 mod conformance {
374 use super::*;
375 use crate::conformance::CodecConformance;
376
377 commonware_conformance::conformance_tests! {
378 CodecConformance<Modes<1>>,
379 CodecConformance<Modes<2>>,
380 }
381 }
382}