1use crate::{Error, Result, io::Write};
2
3pub const MAX_LENGTH: usize = 65520;
4
5pub fn write(output: &mut impl Write, data: &[u8]) -> Result<()> {
6 write_parts(output, &[data])
7}
8
9pub fn write_parts(output: &mut impl Write, parts: &[&[u8]]) -> Result<()> {
11 let length = parts
12 .iter()
13 .try_fold(4_usize, |length, part| length.checked_add(part.len()))
14 .filter(|&n| n <= MAX_LENGTH)
15 .ok_or(Error::InvalidPacket)?;
16 let digits = b"0123456789abcdef";
17 output.write_all(&[
18 digits[(length >> 12) & 15],
19 digits[(length >> 8) & 15],
20 digits[(length >> 4) & 15],
21 digits[length & 15],
22 ])?;
23 for part in parts {
24 output.write_all(part)?;
25 }
26 Ok(())
27}
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
30pub enum Packet<'a> {
31 Data(&'a [u8]),
32 Flush,
33}
34
35pub fn length(prefix: &[u8]) -> Result<usize> {
38 if prefix.len() != 4 || !prefix.iter().all(u8::is_ascii_hexdigit) {
39 return Err(Error::InvalidPacket);
40 }
41 let prefix = core::str::from_utf8(prefix).map_err(|_| Error::InvalidPacket)?;
42 let length = usize::from_str_radix(prefix, 16).map_err(|_| Error::InvalidPacket)?;
43 if length != 0 && !(4..=MAX_LENGTH).contains(&length) {
44 return Err(Error::InvalidPacket);
45 }
46 Ok(length)
47}
48
49pub fn read<'a>(input: &mut &'a [u8]) -> Result<Option<Packet<'a>>> {
50 if input.is_empty() {
51 return Ok(None);
52 }
53 let prefix = input.get(..4).ok_or(Error::InvalidPacket)?;
54 let length = length(prefix)?;
55 if length == 0 {
56 *input = &input[4..];
57 return Ok(Some(Packet::Flush));
58 }
59 let bytes = input.get(4..length).ok_or(Error::InvalidPacket)?;
60 *input = &input[length..];
61 Ok(Some(Packet::Data(bytes)))
62}