1 use std
::{io, io::BufRead}
;
3 use crate::{BandRef, PacketLineRef, StreamingPeekableIter, TextRef, U16_HEX_BYTES}
;
5 /// An implementor of [`BufRead`][io::BufRead] yielding packet lines on each call to [`read_line()`][io::BufRead::read_line()].
6 /// It's also possible to hide the underlying packet lines using the [`Read`][io::Read] implementation which is useful
7 /// if they represent binary data, like the one of a pack file.
8 pub struct WithSidebands
<'a
, T
, F
>
12 parent
: &'a
mut StreamingPeekableIter
<T
>,
13 handle_progress
: Option
<F
>,
18 impl<'a
, T
, F
> Drop
for WithSidebands
<'a
, T
, F
>
27 impl<'a
, T
> WithSidebands
<'a
, T
, fn(bool
, &[u8])>
31 /// Create a new instance with the given provider as `parent`.
32 pub fn new(parent
: &'a
mut StreamingPeekableIter
<T
>) -> Self {
35 handle_progress
: None
,
42 impl<'a
, T
, F
> WithSidebands
<'a
, T
, F
>
45 F
: FnMut(bool
, &[u8]),
47 /// Create a new instance with the given `parent` provider and the `handle_progress` function.
49 /// Progress or error information will be passed to the given `handle_progress(is_error, text)` function, with `is_error: bool`
50 /// being true in case the `text` is to be interpreted as error.
51 pub fn with_progress_handler(parent
: &'a
mut StreamingPeekableIter
<T
>, handle_progress
: F
) -> Self {
54 handle_progress
: Some(handle_progress
),
60 /// Create a new instance without a progress handler.
61 pub fn without_progress_handler(parent
: &'a
mut StreamingPeekableIter
<T
>) -> Self {
64 handle_progress
: None
,
70 /// Forwards to the parent [StreamingPeekableIter::reset_with()]
71 pub fn reset_with(&mut self, delimiters
: &'
static [PacketLineRef
<'
static>]) {
72 self.parent
.reset_with(delimiters
)
75 /// Forwards to the parent [StreamingPeekableIter::stopped_at()]
76 pub fn stopped_at(&self) -> Option
<PacketLineRef
<'
static>> {
77 self.parent
.stopped_at
80 /// Set or unset the progress handler.
81 pub fn set_progress_handler(&mut self, handle_progress
: Option
<F
>) {
82 self.handle_progress
= handle_progress
;
85 /// Effectively forwards to the parent [StreamingPeekableIter::peek_line()], allowing to see what would be returned
86 /// next on a call to [`read_line()`][io::BufRead::read_line()].
90 /// This skips all sideband handling and may return an unprocessed line with sidebands still contained in it.
91 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
)),
100 /// Read a whole packetline from the underlying reader, with empty lines indicating a stop packetline.
104 /// This skips all sideband handling and may return an unprocessed line with sidebands still contained in it.
105 pub fn read_data_line(&mut self) -> Option
<io
::Result
<Result
<PacketLineRef
<'_
>, crate::decode
::Error
>>> {
108 "we don't support partial buffers right now - read-line must be used consistently"
110 self.parent
.read_line()
114 impl<'a
, T
, F
> BufRead
for WithSidebands
<'a
, T
, F
>
117 F
: FnMut(bool
, &[u8]),
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),
126 match self.handle_progress
.as_mut() {
127 Some(handle_progress
) => {
130 .map_err(|err
| io
::Error
::new(io
::ErrorKind
::Other
, err
))?
;
131 const ENCODED_BAND
: usize = 1;
133 BandRef
::Data(d
) => {
137 break (U16_HEX_BYTES
+ ENCODED_BAND
, d
.len());
139 BandRef
::Progress(d
) => {
140 let text
= TextRef
::from(d
).0;
141 handle_progress(false, text
);
143 BandRef
::Error(d
) => {
144 let text
= TextRef
::from(d
).0;
145 handle_progress(true, text
);
150 break match line
.as_slice() {
151 Some(d
) => (U16_HEX_BYTES
, d
.len()),
153 return Err(io
::Error
::new(
154 io
::ErrorKind
::UnexpectedEof
,
155 "encountered non-data line in a data-line only context",
162 self.cap
= cap
+ ofs
;
165 Ok(&self.parent
.buf
[self.pos
..self.cap
])
168 fn consume(&mut self, amt
: usize) {
169 self.pos
= std
::cmp
::min(self.pos
+ amt
, self.cap
);
172 fn read_line(&mut self, buf
: &mut String
) -> io
::Result
<usize> {
175 "we don't support partial buffers right now - read-line must be used consistently"
177 let line
= std
::str::from_utf8(self.fill_buf()?
).map_err(|err
| io
::Error
::new(io
::ErrorKind
::Other
, err
))?
;
179 let bytes
= line
.len();
185 impl<'a
, T
, F
> io
::Read
for WithSidebands
<'a
, T
, F
>
188 F
: FnMut(bool
, &[u8]),
190 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
192 let mut rem
= self.fill_buf()?
;