git_packetline/read/sidebands/
blocking_io.rs1use std::{io, io::BufRead};
2
3use crate::{BandRef, PacketLineRef, StreamingPeekableIter, TextRef, U16_HEX_BYTES};
4
5pub struct WithSidebands<'a, T, F>
9where
10 T: io::Read,
11{
12 parent: &'a mut StreamingPeekableIter<T>,
13 handle_progress: Option<F>,
14 pos: usize,
15 cap: usize,
16}
17
18impl<'a, T, F> Drop for WithSidebands<'a, T, F>
19where
20 T: io::Read,
21{
22 fn drop(&mut self) {
23 self.parent.reset();
24 }
25}
26
27impl<'a, T> WithSidebands<'a, T, fn(bool, &[u8])>
28where
29 T: io::Read,
30{
31 pub fn new(parent: &'a mut StreamingPeekableIter<T>) -> Self {
33 WithSidebands {
34 parent,
35 handle_progress: None,
36 pos: 0,
37 cap: 0,
38 }
39 }
40}
41
42impl<'a, T, F> WithSidebands<'a, T, F>
43where
44 T: io::Read,
45 F: FnMut(bool, &[u8]),
46{
47 pub fn with_progress_handler(parent: &'a mut StreamingPeekableIter<T>, handle_progress: F) -> Self {
52 WithSidebands {
53 parent,
54 handle_progress: Some(handle_progress),
55 pos: 0,
56 cap: 0,
57 }
58 }
59
60 pub fn without_progress_handler(parent: &'a mut StreamingPeekableIter<T>) -> Self {
62 WithSidebands {
63 parent,
64 handle_progress: None,
65 pos: 0,
66 cap: 0,
67 }
68 }
69
70 pub fn reset_with(&mut self, delimiters: &'static [PacketLineRef<'static>]) {
72 self.parent.reset_with(delimiters)
73 }
74
75 pub fn stopped_at(&self) -> Option<PacketLineRef<'static>> {
77 self.parent.stopped_at
78 }
79
80 pub fn set_progress_handler(&mut self, handle_progress: Option<F>) {
82 self.handle_progress = handle_progress;
83 }
84
85 pub fn peek_data_line(&mut self) -> Option<io::Result<Result<&[u8], crate::decode::Error>>> {
92 match self.parent.peek_line() {
93 Some(Ok(Ok(PacketLineRef::Data(line)))) => Some(Ok(Ok(line))),
94 Some(Ok(Err(err))) => Some(Ok(Err(err))),
95 Some(Err(err)) => Some(Err(err)),
96 _ => None,
97 }
98 }
99
100 pub fn read_data_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, crate::decode::Error>>> {
106 assert_eq!(
107 self.cap, 0,
108 "we don't support partial buffers right now - read-line must be used consistently"
109 );
110 self.parent.read_line()
111 }
112}
113
114impl<'a, T, F> BufRead for WithSidebands<'a, T, F>
115where
116 T: io::Read,
117 F: FnMut(bool, &[u8]),
118{
119 fn fill_buf(&mut self) -> io::Result<&[u8]> {
120 if self.pos >= self.cap {
121 let (ofs, cap) = loop {
122 let line = match self.parent.read_line() {
123 Some(line) => line?.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?,
124 None => break (0, 0),
125 };
126 match self.handle_progress.as_mut() {
127 Some(handle_progress) => {
128 let band = line
129 .decode_band()
130 .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
131 const ENCODED_BAND: usize = 1;
132 match band {
133 BandRef::Data(d) => {
134 if d.is_empty() {
135 continue;
136 }
137 break (U16_HEX_BYTES + ENCODED_BAND, d.len());
138 }
139 BandRef::Progress(d) => {
140 let text = TextRef::from(d).0;
141 handle_progress(false, text);
142 }
143 BandRef::Error(d) => {
144 let text = TextRef::from(d).0;
145 handle_progress(true, text);
146 }
147 };
148 }
149 None => {
150 break match line.as_slice() {
151 Some(d) => (U16_HEX_BYTES, d.len()),
152 None => {
153 return Err(io::Error::new(
154 io::ErrorKind::UnexpectedEof,
155 "encountered non-data line in a data-line only context",
156 ))
157 }
158 }
159 }
160 }
161 };
162 self.cap = cap + ofs;
163 self.pos = ofs;
164 }
165 Ok(&self.parent.buf[self.pos..self.cap])
166 }
167
168 fn consume(&mut self, amt: usize) {
169 self.pos = std::cmp::min(self.pos + amt, self.cap);
170 }
171
172 fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
173 assert_eq!(
174 self.cap, 0,
175 "we don't support partial buffers right now - read-line must be used consistently"
176 );
177 let line = std::str::from_utf8(self.fill_buf()?).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
178 buf.push_str(line);
179 let bytes = line.len();
180 self.cap = 0;
181 Ok(bytes)
182 }
183}
184
185impl<'a, T, F> io::Read for WithSidebands<'a, T, F>
186where
187 T: io::Read,
188 F: FnMut(bool, &[u8]),
189{
190 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
191 let nread = {
192 let mut rem = self.fill_buf()?;
193 rem.read(buf)?
194 };
195 self.consume(nread);
196 Ok(nread)
197 }
198}