bookdata/io/
ext.rs

1use std::fs::File;
2use std::io;
3use std::io::Read;
4use zip::read::ZipFile;
5
6use log::*;
7
8/// Trait for read types that can report their size.
9pub trait LengthRead: Read {
10    fn input_size(&self) -> io::Result<u64>;
11
12    /// Read all bytes from a file, using its size to pre-allocate capacity.
13    fn read_all_sized(&mut self) -> io::Result<Vec<u8>> {
14        let mut cap = self.input_size()? as usize;
15        let mut out = vec![0; cap + 1];
16        let mut pos = 0;
17        loop {
18            trace!("requesting {} bytes", cap - pos);
19            let ls = self.read(&mut out[pos..])?;
20            pos += ls;
21            if pos >= cap {
22                // the size hint was wrong
23                warn!("size was wrong, expanding");
24                cap += 16 * 1024;
25                out.resize(cap, 0);
26            }
27            if ls == 0 {
28                out.truncate(pos);
29                return Ok(out);
30            }
31        }
32    }
33}
34
35impl LengthRead for File {
36    fn input_size(&self) -> io::Result<u64> {
37        let meta = self.metadata()?;
38        Ok(meta.len())
39    }
40}
41
42impl<'a> LengthRead for ZipFile<'a> {
43    fn input_size(&self) -> io::Result<u64> {
44        Ok(self.size())
45    }
46}