git_packetline/read/
mod.rs

1#[cfg(any(feature = "blocking-io", feature = "async-io"))]
2use crate::MAX_LINE_LEN;
3use crate::{PacketLineRef, StreamingPeekableIter, U16_HEX_BYTES};
4
5#[cfg(any(feature = "blocking-io", feature = "async-io"))]
6type ExhaustiveOutcome<'a> = (
7    bool,                                                                     // is_done
8    Option<PacketLineRef<'static>>,                                           // stopped_at
9    Option<std::io::Result<Result<PacketLineRef<'a>, crate::decode::Error>>>, // actual method result
10);
11
12mod error {
13    use std::fmt::{Debug, Display, Formatter};
14
15    use bstr::BString;
16
17    /// The error representing an ERR packet line, as possibly wrapped into an `std::io::Error` in
18    /// [`read_line(…)`][super::StreamingPeekableIter::read_line()].
19    #[derive(Debug)]
20    pub struct Error {
21        /// The contents of the ERR line, with `ERR` portion stripped.
22        pub message: BString,
23    }
24
25    impl Display for Error {
26        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27            Display::fmt(&self.message, f)
28        }
29    }
30
31    impl std::error::Error for Error {}
32}
33pub use error::Error;
34
35impl<T> StreamingPeekableIter<T> {
36    /// Return a new instance from `read` which will stop decoding packet lines when receiving one of the given `delimiters`.
37    pub fn new(read: T, delimiters: &'static [PacketLineRef<'static>]) -> Self {
38        StreamingPeekableIter {
39            read,
40            #[cfg(any(feature = "blocking-io", feature = "async-io"))]
41            buf: vec![0; MAX_LINE_LEN],
42            peek_buf: Vec::new(),
43            delimiters,
44            fail_on_err_lines: false,
45            is_done: false,
46            stopped_at: None,
47        }
48    }
49
50    /// Modify the peek buffer, overwriting the byte at `position` with the given byte to `replace_with` while truncating
51    /// it to contain only bytes until the newly replaced `position`.
52    ///
53    /// This is useful if you would want to remove 'special bytes' hidden behind, say a NULL byte to disappear and allow
54    /// standard line readers to read the next line as usual.
55    ///
56    /// **Note** that `position` does not include the 4 bytes prefix (they are invisible outside the reader)
57    pub fn peek_buffer_replace_and_truncate(&mut self, position: usize, replace_with: u8) {
58        let position = position + U16_HEX_BYTES;
59        self.peek_buf[position] = replace_with;
60
61        let new_len = position + 1;
62        self.peek_buf.truncate(new_len);
63        self.peek_buf[..4].copy_from_slice(&crate::encode::u16_to_hex((new_len) as u16));
64    }
65
66    /// Returns the packet line that stopped the iteration, or
67    /// `None` if the end wasn't reached yet, on EOF, or if [`fail_on_err_lines()`][StreamingPeekableIter::fail_on_err_lines()] was true.
68    pub fn stopped_at(&self) -> Option<PacketLineRef<'static>> {
69        self.stopped_at
70    }
71
72    /// Reset all iteration state allowing to continue a stopped iteration that is not yet at EOF.
73    ///
74    /// This can happen once a delimiter is reached.
75    pub fn reset(&mut self) {
76        let delimiters = std::mem::take(&mut self.delimiters);
77        self.reset_with(delimiters);
78    }
79
80    /// Similar to [`reset()`][StreamingPeekableIter::reset()] with support to changing the `delimiters`.
81    pub fn reset_with(&mut self, delimiters: &'static [PacketLineRef<'static>]) {
82        self.delimiters = delimiters;
83        self.is_done = false;
84        self.stopped_at = None;
85    }
86
87    /// If `value` is `true` the provider will check for special `ERR` packet lines and stop iteration when one is encountered.
88    ///
89    /// Use [`stopped_at()]`[StreamingPeekableIter::stopped_at()] to inspect the cause of the end of the iteration.
90    /// ne
91    pub fn fail_on_err_lines(&mut self, value: bool) {
92        self.fail_on_err_lines = value;
93    }
94
95    /// Replace the reader used with the given `read`, resetting all other iteration state as well.
96    pub fn replace(&mut self, read: T) -> T {
97        let prev = std::mem::replace(&mut self.read, read);
98        self.reset();
99        self.fail_on_err_lines = false;
100        prev
101    }
102
103    /// Return the inner read
104    pub fn into_inner(self) -> T {
105        self.read
106    }
107}
108
109#[cfg(feature = "blocking-io")]
110mod blocking_io;
111
112#[cfg(all(not(feature = "blocking-io"), feature = "async-io"))]
113mod async_io;
114
115mod sidebands;
116#[cfg(any(feature = "blocking-io", feature = "async-io"))]
117pub use sidebands::WithSidebands;