gix_packetline/read/
blocking_io.rs1use std::io;
2
3use bstr::ByteSlice;
4
5use crate::{
6 decode,
7 read::{ExhaustiveOutcome, ProgressAction, WithSidebands},
8 PacketLineRef, StreamingPeekableIter, MAX_LINE_LEN, U16_HEX_BYTES,
9};
10
11impl<T> StreamingPeekableIter<T>
13where
14 T: io::Read,
15{
16 fn read_line_inner<'a>(reader: &mut T, buf: &'a mut [u8]) -> io::Result<Result<PacketLineRef<'a>, decode::Error>> {
17 let (hex_bytes, data_bytes) = buf.split_at_mut(4);
18 reader.read_exact(hex_bytes)?;
19 let num_data_bytes = match decode::hex_prefix(hex_bytes) {
20 Ok(decode::PacketLineOrWantedSize::Line(line)) => return Ok(Ok(line)),
21 Ok(decode::PacketLineOrWantedSize::Wanted(additional_bytes)) => additional_bytes as usize,
22 Err(err) => return Ok(Err(err)),
23 };
24
25 let (data_bytes, _) = data_bytes.split_at_mut(num_data_bytes);
26 reader.read_exact(data_bytes)?;
27 match decode::to_data_line(data_bytes) {
28 Ok(line) => Ok(Ok(line)),
29 Err(err) => Ok(Err(err)),
30 }
31 }
32
33 fn read_line_inner_exhaustive<'a>(
36 reader: &mut T,
37 buf: &'a mut Vec<u8>,
38 delimiters: &[PacketLineRef<'static>],
39 fail_on_err_lines: bool,
40 buf_resize: bool,
41 trace: bool,
42 ) -> ExhaustiveOutcome<'a> {
43 (
44 false,
45 None,
46 Some(match Self::read_line_inner(reader, buf) {
47 Ok(Ok(line)) => {
48 if trace {
49 match line {
50 #[allow(unused_variables)]
51 PacketLineRef::Data(d) => {
52 gix_trace::trace!("<< {}", d.as_bstr().trim().as_bstr());
53 }
54 PacketLineRef::Flush => {
55 gix_trace::trace!("<< FLUSH");
56 }
57 PacketLineRef::Delimiter => {
58 gix_trace::trace!("<< DELIM");
59 }
60 PacketLineRef::ResponseEnd => {
61 gix_trace::trace!("<< RESPONSE_END");
62 }
63 }
64 }
65 if delimiters.contains(&line) {
66 let stopped_at = delimiters.iter().find(|l| **l == line).copied();
67 buf.clear();
68 return (true, stopped_at, None);
69 } else if fail_on_err_lines {
70 if let Some(err) = line.check_error() {
71 let err = err.0.as_bstr().to_owned();
72 buf.clear();
73 return (
74 true,
75 None,
76 Some(Err(io::Error::new(
77 io::ErrorKind::Other,
78 crate::read::Error { message: err },
79 ))),
80 );
81 }
82 }
83 let len = line.as_slice().map_or(U16_HEX_BYTES, |s| s.len() + U16_HEX_BYTES);
84 if buf_resize {
85 buf.resize(len, 0);
86 }
87 Ok(Ok(crate::decode(buf).expect("only valid data here")))
89 }
90 Ok(Err(err)) => {
91 buf.clear();
92 Ok(Err(err))
93 }
94 Err(err) => {
95 buf.clear();
96 Err(err)
97 }
98 }),
99 )
100 }
101
102 pub fn read_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, decode::Error>>> {
110 if self.is_done {
111 return None;
112 }
113 if !self.peek_buf.is_empty() {
114 std::mem::swap(&mut self.peek_buf, &mut self.buf);
115 self.peek_buf.clear();
116 Some(Ok(Ok(crate::decode(&self.buf).expect("only valid data in peek buf"))))
117 } else {
118 if self.buf.len() != MAX_LINE_LEN {
119 self.buf.resize(MAX_LINE_LEN, 0);
120 }
121 let (is_done, stopped_at, res) = Self::read_line_inner_exhaustive(
122 &mut self.read,
123 &mut self.buf,
124 self.delimiters,
125 self.fail_on_err_lines,
126 false,
127 self.trace,
128 );
129 self.is_done = is_done;
130 self.stopped_at = stopped_at;
131 res
132 }
133 }
134
135 pub fn peek_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, decode::Error>>> {
140 if self.is_done {
141 return None;
142 }
143 if self.peek_buf.is_empty() {
144 self.peek_buf.resize(MAX_LINE_LEN, 0);
145 let (is_done, stopped_at, res) = Self::read_line_inner_exhaustive(
146 &mut self.read,
147 &mut self.peek_buf,
148 self.delimiters,
149 self.fail_on_err_lines,
150 true,
151 self.trace,
152 );
153 self.is_done = is_done;
154 self.stopped_at = stopped_at;
155 res
156 } else {
157 Some(Ok(Ok(crate::decode(&self.peek_buf).expect("only valid data here"))))
158 }
159 }
160
161 pub fn as_read_with_sidebands<F: FnMut(bool, &[u8]) -> ProgressAction>(
169 &mut self,
170 handle_progress: F,
171 ) -> WithSidebands<'_, T, F> {
172 WithSidebands::with_progress_handler(self, handle_progress)
173 }
174
175 pub fn as_read_without_sidebands<F: FnMut(bool, &[u8]) -> ProgressAction>(&mut self) -> WithSidebands<'_, T, F> {
180 WithSidebands::without_progress_handler(self)
181 }
182
183 #[allow(clippy::type_complexity)]
187 pub fn as_read(&mut self) -> WithSidebands<'_, T, fn(bool, &[u8]) -> ProgressAction> {
188 WithSidebands::new(self)
189 }
190}