thin_fetch/parcel/
decoder.rs1use crate::error::{Error, WithError as _, error};
2
3use super::{MARKER_END, MARKER_SEP};
4
5#[derive(Debug, PartialEq, Eq)]
6pub enum ParcelItem {
7 Data(Vec<u8>),
8 Separator,
9 End,
10}
11
12pub struct ParcelDecoder<R: std::io::Read> {
13 pub(crate) reader: R,
14 finished: bool,
15 pub(crate) ignore_end: bool,
16}
17
18impl<R: std::io::Read> ParcelDecoder<R> {
19 pub fn new(reader: R) -> Self {
20 Self {
21 reader,
22 finished: false,
23 ignore_end: false,
24 }
25 }
26
27 pub fn get_one(&mut self) -> Result<ParcelItem, Error> {
33 let mut len_buf: [u8; 4] = [0; 4];
34
35 self.reader
36 .read_exact(&mut len_buf)
37 .with_err_msg("could not read length")?;
38
39 if len_buf == MARKER_END {
40 return Ok(ParcelItem::End);
41 }
42
43 if len_buf == MARKER_SEP {
44 return Ok(ParcelItem::Separator);
45 }
46
47 let length_raw_str = str::from_utf8(&len_buf).with_err_msg("length is not valid utf-8")?;
48
49 let length = usize::from_str_radix(length_raw_str, 16)
50 .with_err(|| error!("length is not a valid number: {length_raw_str}"))?;
51
52 let mut data = vec![0; length - 4];
53 self.reader
54 .read_exact(&mut data)
55 .with_err_msg("could not read data")?;
56
57 Ok(ParcelItem::Data(data))
58 }
59}
60
61impl<R: std::io::Read> Iterator for ParcelDecoder<R> {
62 type Item = Result<ParcelItem, Error>;
63
64 fn next(&mut self) -> Option<Self::Item> {
65 if self.finished {
66 return None;
67 }
68
69 let item = self.get_one().with_err_msg("get next item");
70
71 match item {
72 Ok(ParcelItem::End) if !self.ignore_end => {
73 self.finished = true;
74 None
75 }
76 Err(err) if self.ignore_end && err.message.contains("failed to fill whole buffer") => {
77 self.finished = true;
78 None
79 }
80 res => Some(res),
81 }
82 }
83}