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