1 use std::io;
2 use std::fmt;
3 use std::cmp;
4 use std::io::{Error, ErrorKind};
5 
6 use super::*;
7 
8 /// Wraps a `Read`er.
9 ///
10 /// This is useful when reading from a file, and it even works with a
11 /// `&[u8]` (but `Memory` is more efficient).
12 pub struct Generic<T: io::Read, C> {
13     buffer: Option<Box<[u8]>>,
14     // The next byte to read in the buffer.
15     cursor: usize,
16     // The preferred chunk size.  This is just a hint.
17     preferred_chunk_size: usize,
18     // XXX: This is pub for the decompressors.  It would be better to
19     // change this to some accessor method.
20     pub reader: Box<T>,
21 
22     // The user settable cookie.
23     cookie: C,
24 }
25 
26 impl<T: io::Read, C> fmt::Display for Generic<T, C> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result27     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28         write!(f, "Generic")
29     }
30 }
31 
32 impl<T: io::Read, C> fmt::Debug for Generic<T, C> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result33     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34         let buffered_data = if let Some(ref buffer) = self.buffer {
35             buffer.len() - self.cursor
36         } else {
37             0
38         };
39 
40         f.debug_struct("Generic")
41             .field("preferred_chunk_size", &self.preferred_chunk_size)
42             .field("buffer data", &buffered_data)
43             .finish()
44     }
45 }
46 
47 impl<T: io::Read> Generic<T, ()> {
48     /// Instantiate a new generic reader.  `reader` is the source to
49     /// wrap.  `preferred_chuck_size` is the preferred chuck size.  If
50     /// None, then the default will be used, which is usually what you
51     /// want.
new(reader: T, preferred_chunk_size: Option<usize>) -> Self52     pub fn new(reader: T, preferred_chunk_size: Option<usize>) -> Self {
53         Self::with_cookie(reader, preferred_chunk_size, ())
54     }
55 }
56 
57 impl<T: io::Read, C> Generic<T, C> {
58     /// Like `new()`, but sets a cookie, which can be retrieved using
59     /// the `cookie_ref` and `cookie_mut` methods, and set using
60     /// the `cookie_set` method.
with_cookie( reader: T, preferred_chunk_size: Option<usize>, cookie: C) -> Self61     pub fn with_cookie(
62            reader: T, preferred_chunk_size: Option<usize>, cookie: C)
63            -> Self {
64         Generic {
65             buffer: None,
66             cursor: 0,
67             preferred_chunk_size:
68                 if let Some(s) = preferred_chunk_size { s }
69                 else { DEFAULT_BUF_SIZE },
70             reader: Box::new(reader),
71             cookie,
72         }
73     }
74 
75     /// Return the buffer.  Ensure that it contains at least `amount`
76     /// bytes.
data_helper(&mut self, amount: usize, hard: bool, and_consume: bool) -> Result<&[u8], io::Error>77     fn data_helper(&mut self, amount: usize, hard: bool, and_consume: bool)
78                    -> Result<&[u8], io::Error> {
79         // println!("Generic.data_helper(\
80         //           amount: {}, hard: {}, and_consume: {} (cursor: {}, buffer: {:?})",
81         //          amount, hard, and_consume,
82         //          self.cursor,
83         //          if let Some(ref buffer) = self.buffer { Some(buffer.len()) }
84         //          else { None });
85 
86 
87         if let Some(ref buffer) = self.buffer {
88             // We have a buffer.  Make sure `cursor` is sane.
89             assert!(self.cursor <= buffer.len());
90         } else {
91             // We don't have a buffer.  Make sure cursor is 0.
92             assert_eq!(self.cursor, 0);
93         }
94 
95         let mut error = None;
96 
97         let amount_buffered
98             = self.buffer.as_ref().map(|b| b.len() - self.cursor).unwrap_or(0);
99         if amount > amount_buffered {
100             // The caller wants more data than we have readily
101             // available.  Read some more.
102 
103             let capacity : usize = cmp::max(cmp::max(
104                 DEFAULT_BUF_SIZE,
105                 2 * self.preferred_chunk_size), amount);
106 
107             let mut buffer_new : Vec<u8> = vec![0u8; capacity];
108 
109             let mut amount_read = 0;
110             while amount_buffered + amount_read < amount {
111                 match self.reader.read(&mut buffer_new
112                                        [amount_buffered + amount_read..]) {
113                     Ok(read) => {
114                         if read == 0 {
115                             break;
116                         } else {
117                             amount_read += read;
118                             continue;
119                         }
120                     },
121                     Err(ref err) if err.kind() == ErrorKind::Interrupted =>
122                         continue,
123                     Err(err) => {
124                         // Don't return yet, because we may have
125                         // actually read something.
126                         error = Some(err);
127                         break;
128                     },
129                 }
130             }
131 
132             if amount_read > 0 {
133                 // We read something.
134                 if let Some(ref buffer) = self.buffer {
135                     // We need to copy in the old data.
136                     buffer_new[0..amount_buffered]
137                         .copy_from_slice(
138                             &buffer[self.cursor..self.cursor + amount_buffered]);
139                 }
140 
141                 vec_truncate(&mut buffer_new, amount_buffered + amount_read);
142                 buffer_new.shrink_to_fit();
143 
144                 self.buffer = Some(buffer_new.into_boxed_slice());
145                 self.cursor = 0;
146             }
147         }
148 
149         let amount_buffered
150             = self.buffer.as_ref().map(|b| b.len() - self.cursor).unwrap_or(0);
151 
152         if let Some(error) = error {
153             // An error occurred.  If we have enough data to fulfill
154             // the caller's request, then don't return the error.
155             if hard && amount > amount_buffered {
156                 return Err(error);
157             }
158             if !hard && amount_buffered == 0 {
159                 return Err(error);
160             }
161         }
162 
163         if hard && amount_buffered < amount {
164             Err(Error::new(ErrorKind::UnexpectedEof, "EOF"))
165         } else if amount == 0 || amount_buffered == 0 {
166             Ok(&b""[..])
167         } else {
168             let buffer = self.buffer.as_ref().unwrap();
169             if and_consume {
170                 let amount_consumed = cmp::min(amount_buffered, amount);
171                 self.cursor += amount_consumed;
172                 assert!(self.cursor <= buffer.len());
173                 Ok(&buffer[self.cursor-amount_consumed..])
174             } else {
175                 Ok(&buffer[self.cursor..])
176             }
177         }
178     }
179 }
180 
181 impl<T: io::Read, C> io::Read for Generic<T, C> {
read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error>182     fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
183         return buffered_reader_generic_read_impl(self, buf);
184     }
185 }
186 
187 impl<T: io::Read, C> BufferedReader<C> for Generic<T, C> {
buffer(&self) -> &[u8]188     fn buffer(&self) -> &[u8] {
189         if let Some(ref buffer) = self.buffer {
190             &buffer[self.cursor..]
191         } else {
192             &b""[..]
193         }
194     }
195 
data(&mut self, amount: usize) -> Result<&[u8], io::Error>196     fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
197         return self.data_helper(amount, false, false);
198     }
199 
data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error>200     fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
201         return self.data_helper(amount, true, false);
202     }
203 
consume(&mut self, amount: usize) -> &[u8]204     fn consume(&mut self, amount: usize) -> &[u8] {
205         // println!("Generic.consume({}) \
206         //           (cursor: {}, buffer: {:?})",
207         //          amount, self.cursor,
208         //          if let Some(ref buffer) = self.buffer { Some(buffer.len()) }
209         //          else { None });
210 
211         // The caller can't consume more than is buffered!
212         if let Some(ref buffer) = self.buffer {
213             assert!(self.cursor <= buffer.len());
214             assert!(amount <= buffer.len() - self.cursor,
215                     "buffer contains just {} bytes, but you are trying to \
216                     consume {} bytes.  Did you forget to call data()?",
217                     buffer.len() - self.cursor, amount);
218 
219             self.cursor += amount;
220             return &self.buffer.as_ref().unwrap()[self.cursor - amount..];
221         } else {
222             assert_eq!(amount, 0);
223             return &b""[..];
224         }
225     }
226 
data_consume(&mut self, amount: usize) -> Result<&[u8], io::Error>227     fn data_consume(&mut self, amount: usize) -> Result<&[u8], io::Error> {
228         return self.data_helper(amount, false, true);
229     }
230 
data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error>231     fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
232         return self.data_helper(amount, true, true);
233     }
234 
get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>>235     fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
236         None
237     }
238 
get_ref(&self) -> Option<&dyn BufferedReader<C>>239     fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
240         None
241     }
242 
into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>> where Self: 'b243     fn into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>>
244         where Self: 'b {
245         None
246     }
247 
cookie_set(&mut self, cookie: C) -> C248     fn cookie_set(&mut self, cookie: C) -> C {
249         use std::mem;
250 
251         mem::replace(&mut self.cookie, cookie)
252     }
253 
cookie_ref(&self) -> &C254     fn cookie_ref(&self) -> &C {
255         &self.cookie
256     }
257 
cookie_mut(&mut self) -> &mut C258     fn cookie_mut(&mut self) -> &mut C {
259         &mut self.cookie
260     }
261 }
262 
263 #[cfg(test)]
264 mod test {
265     use super::*;
266 
267     #[test]
buffered_reader_generic_test()268     fn buffered_reader_generic_test() {
269         // Test reading from a file.
270         {
271             use std::path::PathBuf;
272             use std::fs::File;
273 
274             let path : PathBuf = [env!("CARGO_MANIFEST_DIR"),
275                                   "src", "buffered-reader-test.txt"]
276                 .iter().collect();
277             let mut f = File::open(&path).expect(&path.to_string_lossy());
278             let mut bio = Generic::new(&mut f, None);
279 
280             buffered_reader_test_data_check(&mut bio);
281         }
282 
283         // Same test, but as a slice.
284         {
285             let mut data : &[u8] = include_bytes!("buffered-reader-test.txt");
286             let mut bio = Generic::new(&mut data, None);
287 
288             buffered_reader_test_data_check(&mut bio);
289         }
290     }
291 
292     // Test that buffer() returns the same data as data().
293     #[test]
buffer_test()294     fn buffer_test() {
295         // Test vector.
296         let size = 10 * DEFAULT_BUF_SIZE;
297         let mut input = Vec::with_capacity(size);
298         let mut v = 0u8;
299         for _ in 0..size {
300             input.push(v);
301             if v == std::u8::MAX {
302                 v = 0;
303             } else {
304                 v += 1;
305             }
306         }
307 
308         let mut reader = Generic::new(&input[..], None);
309 
310         // Gather some stats to make it easier to figure out whether
311         // this test is working.
312         let stats_count =  2 * DEFAULT_BUF_SIZE;
313         let mut stats = vec![0usize; stats_count];
314 
315         for i in 0..input.len() {
316             let data = reader.data(DEFAULT_BUF_SIZE + 1).unwrap().to_vec();
317             assert!(data.len() > 0);
318             assert_eq!(data, reader.buffer());
319             // And, we may as well check to make sure we read the
320             // right data.
321             assert_eq!(data, &input[i..i+data.len()]);
322 
323             stats[cmp::min(data.len(), stats_count - 1)] += 1;
324 
325             // Consume one byte and see what happens.
326             reader.consume(1);
327         }
328 
329         if false {
330             for i in 0..stats.len() {
331                 if stats[i] > 0 {
332                     if i == stats.len() - 1 {
333                         eprint!(">=");
334                     }
335                     eprintln!("{}: {}", i, stats[i]);
336                 }
337             }
338         }
339     }
340 }
341