read_to_timeout/
lib.rs

1/// The [std::io::Read](std::io::Read) trait implements many read operations,
2/// but it doesn't contain a simple read method where timeout is the expected
3/// behaviour
4///
5/// This trait is implemented for all types that implements
6/// [std::io::Read](std::io::Read), provides
7/// [read_to_timeout](ReadToTimeout::read_to_timeout),
8/// [read_to_timeout_or_bytes](ReadToTimeout::read_to_timeout_or_bytes), and
9/// [read_to_timeout_or_pattern](ReadToTimeout::read_to_timeout_or_pattern)
10pub trait ReadToTimeout {
11    /// Similar to [read_to_end](std::io::Read::read_to_end)
12    ///
13    /// But when timeout, instead of returning error, this function returns
14    /// `Ok(bytes_read)`
15    fn read_to_timeout(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize>;
16
17    /// Similar to [read_to_timeout](ReadToTimeout::read_to_timeout)
18    ///
19    /// But when the received byte count reaches `max_byte`, this function
20    /// returns `Ok(bytes_read)` immediately
21    fn read_to_timeout_or_bytes(
22        &mut self,
23        buf: &mut Vec<u8>,
24        max_byte: usize,
25    ) -> std::io::Result<usize>;
26
27    /// Similar to [read_to_timeout](ReadToTimeout::read_to_timeout)
28    ///
29    /// But when a specified pattern is reached, this function return
30    /// `Ok(bytes_read)` immediately
31    ///
32    /// # Note
33    /// If the provided buffer is non-empty, while **at least one byte** must be
34    /// read before any pattern match, it is possible for pattern to match on
35    /// old bytes.
36    fn read_to_timeout_or_pattern(
37        &mut self,
38        buf: &mut Vec<u8>,
39        pattern: &[u8],
40    ) -> std::io::Result<usize>;
41
42    /// **DEPRECATED**
43    ///
44    /// Use [read_to_timeout_or_pattern](ReadToTimeout::read_to_timeout_or_pattern)
45    /// instead
46    #[deprecated]
47    fn read_to_pattern_or_timeout(
48        &mut self,
49        buf: &mut Vec<u8>,
50        pattern: &[u8],
51    ) -> std::io::Result<usize>;
52}
53
54// impl ReadTimeout for all T that impl Read
55impl<T: std::io::Read + ?Sized> ReadToTimeout for T {
56    fn read_to_timeout(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
57        let old_len = buf.len();
58
59        loop {
60            let mut read_buf = [0];
61            match self.read_exact(&mut read_buf) {
62                Ok(_) => {
63                    buf.push(read_buf[0]);
64                }
65                Err(e) => {
66                    return match e.kind() {
67                        std::io::ErrorKind::TimedOut => Ok(buf.len() - old_len),
68                        _ => Err(e),
69                    }
70                }
71            }
72        }
73    }
74
75    fn read_to_timeout_or_bytes(
76        &mut self,
77        buf: &mut Vec<u8>,
78        max_byte: usize,
79    ) -> std::io::Result<usize> {
80        let old_len = buf.len();
81
82        loop {
83            let mut read_buf = [0];
84            match self.read_exact(&mut read_buf) {
85                Ok(_) => {
86                    buf.push(read_buf[0]);
87
88                    if (buf.len() - old_len) == max_byte {
89                        return Ok(buf.len() - old_len);
90                    }
91                }
92                Err(e) => {
93                    return match e.kind() {
94                        std::io::ErrorKind::TimedOut => Ok(buf.len() - old_len),
95                        _ => Err(e),
96                    }
97                }
98            }
99        }
100    }
101
102    fn read_to_timeout_or_pattern(
103        &mut self,
104        buf: &mut Vec<u8>,
105        pattern: &[u8],
106    ) -> std::io::Result<usize> {
107        let old_len = buf.len();
108
109        loop {
110            let mut byte = [0];
111            match self.read_exact(&mut byte) {
112                Ok(_) => {
113                    buf.push(byte[0]);
114                    if buf.len() >= pattern.len()
115                        && &buf[(buf.len() - pattern.len())..] == pattern
116                    {
117                        break Ok(buf.len() - old_len);
118                    }
119                }
120                Err(err) => match err.kind() {
121                    std::io::ErrorKind::TimedOut => {
122                        break Ok(buf.len() - old_len);
123                    }
124                    _ => {
125                        break Err(err);
126                    }
127                },
128            }
129        }
130    }
131
132    fn read_to_pattern_or_timeout(
133        &mut self,
134        buf: &mut Vec<u8>,
135        pattern: &[u8],
136    ) -> std::io::Result<usize> {
137        self.read_to_timeout_or_pattern(buf, pattern)
138    }
139}
140
141#[cfg(test)]
142mod test {
143    use crate::ReadToTimeout;
144
145    #[test]
146    fn read_pattern() {
147        let mut bytes: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1];
148
149        let mut buffer = Vec::new();
150        assert_eq!(
151            bytes.read_to_timeout_or_pattern(&mut buffer, &[7, 6]).unwrap(),
152            8
153        );
154        assert_eq!(buffer, &[1, 2, 3, 4, 5, 6, 7, 6]);
155        
156        assert_eq!(bytes.read_to_timeout_or_bytes(&mut buffer, 4).unwrap(), 4);
157        assert_eq!(buffer, &[1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2]);
158    }
159}