buffered_reader/
reserve.rs

1use std::io;
2
3use super::*;
4
5/// A `Reserve` allows a reader to read everything
6/// except for the last N bytes (the reserve) from the underlying
7/// `BufferedReader`.
8///
9/// Note: because the `Reserve` doesn't generally know
10/// how much data can be read from the underlying `BufferedReader`,
11/// it causes at least N bytes to by buffered.
12#[derive(Debug)]
13pub struct Reserve<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> {
14    reserve: usize,
15    cookie: C,
16    reader: T,
17}
18
19assert_send_and_sync!(Reserve<T, C>
20                      where T: BufferedReader<C>,
21                            C: fmt::Debug);
22
23impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> fmt::Display for Reserve<T, C> {
24    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25        f.debug_struct("Reserve")
26            .field("reserve", &self.reserve)
27            .finish()
28    }
29}
30
31impl<T: BufferedReader<()>> Reserve<T, ()> {
32    /// Instantiates a new `Reserve`.
33    ///
34    /// `reader` is the source to wrap.  `reserve` is the number of
35    /// bytes that will not be returned to the reader.
36    pub fn new(reader: T, reserve: usize) -> Self {
37        Self::with_cookie(reader, reserve, ())
38    }
39}
40
41impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> Reserve<T, C> {
42    /// Like [`Self::new`], but sets a cookie.
43    ///
44    /// The cookie can be retrieved using the [`BufferedReader::cookie_ref`] and
45    /// [`BufferedReader::cookie_mut`] methods, and set using the [`BufferedReader::cookie_set`] method.
46    pub fn with_cookie(reader: T, reserve: usize, cookie: C)
47            -> Reserve<T, C> {
48        Reserve {
49            reader,
50            reserve,
51            cookie,
52        }
53    }
54}
55
56impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> io::Read for Reserve<T, C> {
57    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
58        let to_read = {
59            let data = self.reader.data(buf.len() + self.reserve)?;
60            if data.len() > self.reserve {
61                data.len() - self.reserve
62            } else {
63                return Ok(0);
64            }
65        };
66
67        let to_read = cmp::min(buf.len(), to_read);
68
69        self.reader.read(&mut buf[..to_read])
70    }
71}
72
73impl<T: BufferedReader<C>, C: fmt::Debug + Send + Sync> BufferedReader<C> for Reserve<T, C> {
74    fn buffer(&self) -> &[u8] {
75        let buf = self.reader.buffer();
76        if buf.len() > self.reserve {
77            &buf[..buf.len() - self.reserve]
78        } else {
79            b""
80        }
81    }
82
83    /// Return the buffer.  Ensure that it contains at least `amount`
84    /// bytes.
85    fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
86        let data = self.reader.data(amount + self.reserve)?;
87        if data.len() <= self.reserve {
88            // EOF.
89            Ok(b"")
90        } else {
91            // More than enough.
92            Ok(&data[..data.len() - self.reserve])
93        }
94    }
95
96    fn consume(&mut self, amount: usize) -> &[u8] {
97        assert!(amount <= self.buffer().len());
98
99        // consume may return more than amount.  If it does, make sure
100        // it doesn't return any of the reserve.
101        let data = self.reader.consume(amount);
102        assert!(data.len() >= amount);
103
104        if data.len() > amount {
105            // We got more than `amount`.  We need to be careful to
106            // not return data from the reserve.  But, we also know
107            // that `amount` does not include data from the reserve.
108            if data.len() > amount + self.reserve {
109                return &data[..data.len() - self.reserve];
110            }
111        }
112        &data[..amount]
113    }
114
115    fn data_consume(&mut self, amount: usize) -> Result<&[u8], io::Error> {
116        let amount = cmp::min(amount, self.data(amount)?.len());
117        Ok(self.consume(amount))
118    }
119
120    fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
121        self.data_hard(amount)?;
122        Ok(self.consume(amount))
123    }
124
125    fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
126        Some(&mut self.reader)
127    }
128
129    fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
130        Some(&self.reader)
131    }
132
133    fn into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>>
134        where Self: 'b {
135        Some(self.reader.into_boxed())
136    }
137
138    fn cookie_set(&mut self, cookie: C) -> C {
139        use std::mem;
140
141        mem::replace(&mut self.cookie, cookie)
142    }
143
144    fn cookie_ref(&self) -> &C {
145        &self.cookie
146    }
147
148    fn cookie_mut(&mut self) -> &mut C {
149        &mut self.cookie
150    }
151}
152
153#[cfg(test)]
154mod test {
155    use super::*;
156
157    #[test]
158    fn data() {
159        use crate::Memory;
160
161        // orig is the original buffer
162        //
163        // cursor is the Reserve's position in orig.
164        //
165        // to_read is how much to read.
166        //
167        // total is the total to_read that be read from orig.
168        //
169        //           cursor                    /  reserve  \
170        // orig: [      | to_read  |          |             ]
171        //        \          total           /
172        //
173        fn read_chunk<'a, R: BufferedReader<C>, C: fmt::Debug + Sync + Send>(
174            orig: &[u8], r: &mut R, to_read: usize, cursor: usize, total: usize,
175            mode: usize)
176        {
177            // Use data.
178            let data_len = {
179                let data = r.data(to_read).unwrap();
180                assert_eq!(data, &orig[cursor..cursor + data.len()]);
181                data.len()
182            };
183            assert!(data_len <= total - cursor);
184            assert_eq!(r.buffer().len(), data_len);
185
186            // Use data_hard.
187            let data_hard_len = {
188                let data_hard = r.data_hard(to_read).unwrap();
189                assert_eq!(data_hard, &orig[cursor..cursor + data_hard.len()]);
190                data_hard.len()
191            };
192            assert!(data_len <= data_hard_len);
193            assert!(data_hard_len <= total - cursor);
194            assert_eq!(r.buffer().len(), data_hard_len);
195
196
197
198            // Make sure data_hard fails when requesting too much
199            // data.
200            assert!(r.data_hard(total - cursor + 1).is_err());
201
202            // And that a failing data_hard does not move the cursor.
203            let data_len = {
204                let data = r.data(to_read).unwrap();
205                assert_eq!(data, &orig[cursor..cursor + data.len()]);
206                data.len()
207            };
208            assert!(data_len <= total - cursor);
209            assert_eq!(r.buffer().len(), data_len);
210
211
212            // Likewise for data_consume_hard.
213            assert!(r.data_consume_hard(total - cursor + 1).is_err());
214
215            // And that a failing data_hard does not move the cursor.
216            let data_len = {
217                let data = r.data(to_read).unwrap();
218                assert_eq!(data, &orig[cursor..cursor + data.len()]);
219                data.len()
220            };
221            assert!(data_len <= total - cursor);
222            assert_eq!(r.buffer().len(), data_len);
223
224
225
226            // Consume the chunk.
227            match mode {
228                0 => {
229                    // Use consume.
230                    let l = r.consume(to_read).len();
231                    assert!(to_read <= l);
232                    assert!(l <= total - cursor);
233                }
234                1 => {
235                    // Use data_consume.
236                    let data_len = {
237                        let data = r.data_consume(to_read).unwrap();
238                        assert_eq!(data, &orig[cursor..cursor + data.len()]);
239                        data.len()
240                    };
241                    assert!(data_len <= total - cursor);
242                    assert!(r.buffer().len() <= total - cursor - to_read);
243                }
244                2 => {
245                    // Use data_consume_hard.
246                    let data_len = {
247                        let data = r.data_consume_hard(to_read).unwrap();
248                        assert_eq!(data, &orig[cursor..cursor + data.len()]);
249                        data.len()
250                    };
251                    assert!(data_len <= total - cursor);
252                    assert!(r.buffer().len() <= total - cursor - to_read);
253                }
254                _ => panic!("Invalid mode"),
255            }
256        }
257
258        fn test(orig: &[u8], mode: usize, reserve: usize,
259                mid1: usize, mid2: usize) {
260            let total = orig.len() - reserve;
261
262            let mut r = Reserve::new(
263                Memory::new(orig), reserve);
264
265            // Read the first chunk.
266            read_chunk(orig, &mut r, mid1, 0, total, mode);
267
268            // Read the second chunk.
269            read_chunk(orig, &mut r, mid2 - mid1, mid1, total, mode);
270
271            // Read the remaining bit.
272            read_chunk(orig, &mut r, total - mid2, mid2, total, mode);
273
274            // And, we should be at EOF.
275            assert_eq!(r.data(100).unwrap().len(), 0);
276            assert_eq!(r.buffer().len(), 0);
277            assert!(r.data_hard(100).is_err());
278            assert_eq!(r.data_hard(0).unwrap().len(), 0);
279
280            let mut g = Box::new(r).into_inner().unwrap();
281            read_chunk(orig, &mut g,
282                       orig.len() - total, total, orig.len(),
283                       mode);
284        }
285
286        // 26 letters.
287        let orig : &[u8] = b"abcdefghijklmnopqrstuvwxyz";
288
289        // We break up the above into four pieces: three chunks, and
290        // the reserved area.
291        for mode in 0..3 {
292            for reserve in 0..orig.len() {
293                let total = orig.len() - reserve;
294
295                for mid1 in 0..total {
296                    for mid2 in mid1..total {
297                        test(orig, mode, reserve, mid1, mid2);
298                    }
299                }
300            }
301        }
302    }
303}