buffered_reader/
limitor.rs

1use std::io;
2use std::cmp;
3
4use super::*;
5
6/// Limits the amount of data that can be read from a
7/// `BufferedReader`.
8#[derive(Debug)]
9pub struct Limitor<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> {
10    limit: u64,
11    cookie: C,
12    reader: T,
13}
14
15assert_send_and_sync!(Limitor<T, C>
16                      where T: BufferedReader<C>,
17                            C: fmt::Debug);
18
19impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> fmt::Display for Limitor<T, C> {
20    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21        f.debug_struct("Limitor")
22            .field("limit", &self.limit)
23            .finish()
24    }
25}
26
27impl<T: BufferedReader<()>> Limitor<T, ()> {
28    /// Instantiates a new limitor.
29    ///
30    /// `reader` is the source to wrap.  `limit` is the maximum number
31    /// of bytes that can be read from the source.
32    pub fn new(reader: T, limit: u64) -> Self {
33        Self::with_cookie(reader, limit, ())
34    }
35}
36
37impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> Limitor<T, C> {
38    /// Like [`Self::new`], but sets a cookie.
39    ///
40    /// The cookie can be retrieved using the [`BufferedReader::cookie_ref`] and
41    /// [`BufferedReader::cookie_mut`] methods, and set using the [`BufferedReader::cookie_set`] method.
42    pub fn with_cookie(reader: T, limit: u64, cookie: C)
43            -> Limitor<T, C> {
44        Limitor {
45            reader,
46            limit,
47            cookie,
48        }
49    }
50}
51
52impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> io::Read for Limitor<T, C> {
53    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
54        let len = cmp::min(self.limit, buf.len() as u64) as usize;
55        let result = self.reader.read(&mut buf[0..len]);
56        if let Ok(amount) = result {
57            self.limit -= amount as u64;
58        }
59        result
60    }
61}
62
63impl<T: BufferedReader<C>, C: fmt::Debug + Sync + Send> BufferedReader<C> for Limitor<T, C> {
64    fn buffer(&self) -> &[u8] {
65        let buf = self.reader.buffer();
66        &buf[..cmp::min(buf.len(),
67                        cmp::min(std::usize::MAX as u64,
68                                 self.limit) as usize)]
69    }
70
71    /// Return the buffer.  Ensure that it contains at least `amount`
72    /// bytes.
73    fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
74        let amount = cmp::min(amount as u64, self.limit) as usize;
75        let result = self.reader.data(amount);
76        match result {
77            Ok(buffer) =>
78                if buffer.len() as u64 > self.limit {
79                    Ok(&buffer[0..self.limit as usize])
80                } else {
81                    Ok(buffer)
82                },
83            Err(err) => Err(err),
84        }
85    }
86
87    fn consume(&mut self, amount: usize) -> &[u8] {
88        assert!(amount as u64 <= self.limit);
89        self.limit -= amount as u64;
90        let data = self.reader.consume(amount);
91        &data[..cmp::min(self.limit + amount as u64, data.len() as u64) as usize]
92    }
93
94    fn data_consume(&mut self, amount: usize) -> Result<&[u8], io::Error> {
95        let amount = cmp::min(amount as u64, self.limit) as usize;
96        let result = self.reader.data_consume(amount);
97        if let Ok(buffer) = result {
98            let amount = cmp::min(amount, buffer.len());
99            self.limit -= amount as u64;
100            return Ok(&buffer[
101                ..cmp::min(buffer.len() as u64, self.limit + amount as u64) as usize]);
102        }
103        result
104    }
105
106    fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
107        if amount as u64 > self.limit {
108            return Err(Error::new(ErrorKind::UnexpectedEof, "EOF"));
109        }
110        let result = self.reader.data_consume_hard(amount);
111        if let Ok(buffer) = result {
112            let amount = cmp::min(amount, buffer.len());
113            self.limit -= amount as u64;
114            return Ok(&buffer[
115                ..cmp::min(buffer.len() as u64, self.limit + amount as u64) as usize]);
116        }
117        result
118    }
119
120    fn consummated(&mut self) -> bool {
121        self.limit == 0
122    }
123
124    fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
125        Some(&mut self.reader)
126    }
127
128    fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
129        Some(&self.reader)
130    }
131
132    fn into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>>
133        where Self: 'b {
134        Some(self.reader.into_boxed())
135    }
136
137    fn cookie_set(&mut self, cookie: C) -> C {
138        use std::mem;
139
140        mem::replace(&mut self.cookie, cookie)
141    }
142
143    fn cookie_ref(&self) -> &C {
144        &self.cookie
145    }
146
147    fn cookie_mut(&mut self) -> &mut C {
148        &mut self.cookie
149    }
150}
151
152#[cfg(test)]
153mod test {
154    use super::*;
155
156    #[test]
157    fn buffered_reader_limitor_test() {
158        let data : &[u8] = b"01234567890123456789";
159
160        /* Add a single limitor.  */
161        {
162            let mut bio : Box<dyn BufferedReader<()>>
163                = Box::new(Memory::new(data));
164
165            bio = {
166                let mut bio2 = Box::new(Limitor::new(bio, 5));
167                {
168                    let result = bio2.data(5).unwrap();
169                    assert_eq!(result.len(), 5);
170                    assert_eq!(result, &b"01234"[..]);
171                }
172                bio2.consume(5);
173                {
174                    let result = bio2.data(1).unwrap();
175                    assert_eq!(result.len(), 0);
176                    assert_eq!(result, &b""[..]);
177                }
178
179                bio2.into_inner().unwrap()
180            };
181
182            {
183                {
184                    let result = bio.data(15).unwrap();
185                    assert_eq!(result.len(), 15);
186                    assert_eq!(result, &b"567890123456789"[..]);
187                }
188                bio.consume(15);
189                {
190                    let result = bio.data(1).unwrap();
191                    assert_eq!(result.len(), 0);
192                    assert_eq!(result, &b""[..]);
193                }
194            }
195        }
196
197        /* Try with two limitors where the first one imposes the real
198         * limit.  */
199        {
200            let mut bio : Box<dyn BufferedReader<()>>
201                = Box::new(Memory::new(data));
202
203            bio = {
204                let bio2 : Box<dyn BufferedReader<()>>
205                    = Box::new(Limitor::new(bio, 5));
206                // We limit to 15 bytes, but bio2 will still limit us to 5
207                // bytes.
208                let mut bio3 : Box<dyn BufferedReader<()>>
209                    = Box::new(Limitor::new(bio2, 15));
210                {
211                    let result = bio3.data(100).unwrap();
212                    assert_eq!(result.len(), 5);
213                    assert_eq!(result, &b"01234"[..]);
214                }
215                bio3.consume(5);
216                {
217                    let result = bio3.data(1).unwrap();
218                    assert_eq!(result.len(), 0);
219                    assert_eq!(result, &b""[..]);
220                }
221
222                bio3.into_inner().unwrap().into_inner().unwrap()
223            };
224
225            {
226                {
227                    let result = bio.data(15).unwrap();
228                    assert_eq!(result.len(), 15);
229                    assert_eq!(result, &b"567890123456789"[..]);
230                }
231                bio.consume(15);
232                {
233                    let result = bio.data(1).unwrap();
234                    assert_eq!(result.len(), 0);
235                    assert_eq!(result, &b""[..]);
236                }
237            }
238        }
239    }
240
241    // Test that buffer() returns the same data as data().
242    #[test]
243    fn buffer_test() {
244        // Test vector.
245        let size = 10 * default_buf_size();
246        let mut input = Vec::with_capacity(size);
247        let mut v = 0u8;
248        for _ in 0..size {
249            input.push(v);
250            if v == std::u8::MAX {
251                v = 0;
252            } else {
253                v += 1;
254            }
255        }
256
257        let reader = Generic::new(&input[..], None);
258        let size = size / 2;
259        let input = &input[..size];
260        let mut reader = Limitor::new(reader, input.len() as u64);
261
262        // Gather some stats to make it easier to figure out whether
263        // this test is working.
264        let stats_count =  2 * default_buf_size();
265        let mut stats = vec![0usize; stats_count];
266
267        for i in 0..input.len() {
268            let data = reader.data(default_buf_size() + 1).unwrap().to_vec();
269            assert!(!data.is_empty());
270            assert_eq!(data, reader.buffer());
271            // And, we may as well check to make sure we read the
272            // right data.
273            assert_eq!(data, &input[i..i+data.len()]);
274
275            stats[cmp::min(data.len(), stats_count - 1)] += 1;
276
277            // Consume one byte and see what happens.
278            reader.consume(1);
279        }
280
281        if false {
282            for i in 0..stats.len() {
283                if stats[i] > 0 {
284                    if i == stats.len() - 1 {
285                        eprint!(">=");
286                    }
287                    eprintln!("{}: {}", i, stats[i]);
288                }
289            }
290        }
291    }
292
293    #[test]
294    fn consummated() {
295        let data = b"0123456789";
296
297        let mut l = Limitor::new(Memory::new(data), 10);
298        l.drop_eof().unwrap();
299        assert!(l.consummated());
300
301        let mut l = Limitor::new(Memory::new(data), 20);
302        l.drop_eof().unwrap();
303        eprintln!("{:?}", l);
304        assert!(! l.consummated());
305    }
306}