1use bstr::BString;
2
3use crate::{PacketLineRef, DELIMITER_LINE, FLUSH_LINE, MAX_DATA_LEN, MAX_LINE_LEN, RESPONSE_END_LINE, U16_HEX_BYTES};
4
5#[derive(Debug, thiserror::Error)]
7#[allow(missing_docs)]
8pub enum Error {
9 #[error("Failed to decode the first four hex bytes indicating the line length: {err}")]
10 HexDecode { err: String },
11 #[error("The data received claims to be larger than than the maximum allowed size: got {length_in_bytes}, exceeds {MAX_DATA_LEN}")]
12 DataLengthLimitExceeded { length_in_bytes: usize },
13 #[error("Received an invalid empty line")]
14 DataIsEmpty,
15 #[error("Received an invalid line of length 3")]
16 InvalidLineLength,
17 #[error("{data:?} - consumed {bytes_consumed} bytes")]
18 Line { data: BString, bytes_consumed: usize },
19 #[error("Needing {bytes_needed} additional bytes to decode the line successfully")]
20 NotEnoughData { bytes_needed: usize },
21}
22
23pub mod band {
25 #[derive(Debug, thiserror::Error)]
27 #[allow(missing_docs)]
28 pub enum Error {
29 #[error("attempt to decode a non-side channel line or input was malformed: {band_id}")]
30 InvalidSideBand { band_id: u8 },
31 #[error("attempt to decode a non-data line into a side-channel band")]
32 NonDataLine,
33 }
34}
35
36#[derive(Debug, Clone)]
38pub enum Stream<'a> {
39 Complete {
41 line: PacketLineRef<'a>,
43 bytes_consumed: usize,
45 },
46 Incomplete {
48 bytes_needed: usize,
50 },
51}
52
53pub enum PacketLineOrWantedSize<'a> {
55 Line(PacketLineRef<'a>),
57 Wanted(u16),
59}
60
61pub fn hex_prefix(four_bytes: &[u8]) -> Result<PacketLineOrWantedSize<'_>, Error> {
63 debug_assert_eq!(four_bytes.len(), 4, "need four hex bytes");
64 for (line_bytes, line_type) in &[
65 (FLUSH_LINE, PacketLineRef::Flush),
66 (DELIMITER_LINE, PacketLineRef::Delimiter),
67 (RESPONSE_END_LINE, PacketLineRef::ResponseEnd),
68 ] {
69 if four_bytes == *line_bytes {
70 return Ok(PacketLineOrWantedSize::Line(*line_type));
71 }
72 }
73
74 let mut buf = [0u8; U16_HEX_BYTES / 2];
75 hex::decode_to_slice(four_bytes, &mut buf).map_err(|err| Error::HexDecode { err: err.to_string() })?;
76 let wanted_bytes = u16::from_be_bytes(buf);
77
78 if wanted_bytes == 3 {
79 return Err(Error::InvalidLineLength);
80 }
81 if wanted_bytes == 4 {
82 return Err(Error::DataIsEmpty);
83 }
84 debug_assert!(
85 wanted_bytes as usize > U16_HEX_BYTES,
86 "by now there should be more wanted bytes than prefix bytes"
87 );
88 Ok(PacketLineOrWantedSize::Wanted(wanted_bytes - U16_HEX_BYTES as u16))
89}
90
91pub fn to_data_line(data: &[u8]) -> Result<PacketLineRef<'_>, Error> {
93 if data.len() > MAX_LINE_LEN {
94 return Err(Error::DataLengthLimitExceeded {
95 length_in_bytes: data.len(),
96 });
97 }
98
99 Ok(PacketLineRef::Data(data))
100}
101
102pub fn streaming(data: &[u8]) -> Result<Stream<'_>, Error> {
104 let data_len = data.len();
105 if data_len < U16_HEX_BYTES {
106 return Ok(Stream::Incomplete {
107 bytes_needed: U16_HEX_BYTES - data_len,
108 });
109 }
110 let wanted_bytes = match hex_prefix(&data[..U16_HEX_BYTES])? {
111 PacketLineOrWantedSize::Wanted(s) => s as usize,
112 PacketLineOrWantedSize::Line(line) => {
113 return Ok(Stream::Complete {
114 line,
115 bytes_consumed: 4,
116 })
117 }
118 } + U16_HEX_BYTES;
119 if wanted_bytes > MAX_LINE_LEN {
120 return Err(Error::DataLengthLimitExceeded {
121 length_in_bytes: wanted_bytes,
122 });
123 }
124 if data_len < wanted_bytes {
125 return Ok(Stream::Incomplete {
126 bytes_needed: wanted_bytes - data_len,
127 });
128 }
129
130 Ok(Stream::Complete {
131 line: to_data_line(&data[U16_HEX_BYTES..wanted_bytes])?,
132 bytes_consumed: wanted_bytes,
133 })
134}
135
136pub fn all_at_once(data: &[u8]) -> Result<PacketLineRef<'_>, Error> {
141 match streaming(data)? {
142 Stream::Complete { line, .. } => Ok(line),
143 Stream::Incomplete { bytes_needed } => Err(Error::NotEnoughData { bytes_needed }),
144 }
145}