Krolyxon
Commit 90075f3

Branches

Refs →

budctlcratesbudctl-coresrcreader.rs

89 lines · 2.5 KB · Rust

1//! A cursor over bytes from the buds. Every read returns a `Result`, so a short or malformed
2//! message becomes an [`Error::Protocol`] instead of a panic.
3
4use crate::error::{Error, Result};
5
6pub(crate) struct Reader<'a> {
7 bytes: &'a [u8],
8 /// What is being parsed, for error messages ("battery reply", "SDP response"…).
9 what: &'static str,
10}
11
12impl<'a> Reader<'a> {
13 pub(crate) fn new(bytes: &'a [u8], what: &'static str) -> Self {
14 Self { bytes, what }
15 }
16
17 pub(crate) fn u8(&mut self) -> Result<u8> {
18 let [byte] = self.array::<1>()?;
19 Ok(byte)
20 }
21
22 pub(crate) fn i8(&mut self) -> Result<i8> {
23 let [byte] = self.array::<1>()?;
24 Ok(i8::from_le_bytes([byte]))
25 }
26
27 pub(crate) fn u16_le(&mut self) -> Result<u16> {
28 Ok(u16::from_le_bytes(self.array()?))
29 }
30
31 pub(crate) fn u16_be(&mut self) -> Result<u16> {
32 Ok(u16::from_be_bytes(self.array()?))
33 }
34
35 pub(crate) fn u32_be(&mut self) -> Result<u32> {
36 Ok(u32::from_be_bytes(self.array()?))
37 }
38
39 /// The next `n` bytes.
40 pub(crate) fn take(&mut self, n: usize) -> Result<&'a [u8]> {
41 let (head, tail) = self.bytes.split_at_checked(n).ok_or_else(|| self.too_short())?;
42 self.bytes = tail;
43 Ok(head)
44 }
45
46 /// Everything not read yet.
47 pub(crate) fn rest(&mut self) -> &'a [u8] {
48 std::mem::take(&mut self.bytes)
49 }
50
51 pub(crate) fn is_empty(&self) -> bool {
52 self.bytes.is_empty()
53 }
54
55 fn array<const N: usize>(&mut self) -> Result<[u8; N]> {
56 let (head, tail) = self.bytes.split_first_chunk::<N>().ok_or_else(|| self.too_short())?;
57 self.bytes = tail;
58 Ok(*head)
59 }
60
61 fn too_short(&self) -> Error {
62 Error::Protocol(format!("{} is too short", self.what))
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn reads_in_order_and_reports_short_input() {
72 let mut r = Reader::new(&[0x01, 0x34, 0x12, 0x12, 0x34, 0xFF], "test");
73 assert_eq!(r.u8().unwrap(), 0x01);
74 assert_eq!(r.u16_le().unwrap(), 0x1234);
75 assert_eq!(r.u16_be().unwrap(), 0x1234);
76 assert_eq!(r.i8().unwrap(), -1);
77 assert!(r.is_empty());
78 assert!(matches!(r.u8(), Err(Error::Protocol(_))));
79 }
80
81 #[test]
82 fn take_and_rest() {
83 let mut r = Reader::new(&[1, 2, 3, 4], "test");
84 assert_eq!(r.take(2).unwrap(), &[1, 2]);
85 assert!(r.take(3).is_err());
86 assert_eq!(r.rest(), &[3, 4]);
87 assert_eq!(r.rest(), &[] as &[u8]);
88 }
89}