1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! Buffered Reader wrapper, for efficient data reading
//! and integrated .gz decompression.
#[cfg(feature = "flate2")]
use flate2::read::GzDecoder;
use std::fs::File;
use std::io::BufReader; // Seek, SeekFrom};

#[derive(Debug)]
pub enum BufferedReader {
    /// Readable (plain) file
    PlainFile(BufReader<File>),
    /// gzip compressed RINEX
    #[cfg(feature = "flate2")]
    GzFile(BufReader<GzDecoder<File>>),
}

impl BufferedReader {
    /// Builds a new BufferedReader for efficient file interation,
    /// with possible .gz decompression
    pub fn new(path: &str) -> std::io::Result<Self> {
        let f = File::open(path)?;
        if path.ends_with(".gz") {
            // --> gzip encoded
            #[cfg(feature = "flate2")]
            {
                Ok(Self::GzFile(BufReader::new(GzDecoder::new(f))))
            }
            #[cfg(not(feature = "flate2"))]
            {
                panic!(".gz data requires --flate2 feature")
            }
        } else if path.ends_with(".Z") {
            panic!(".z decompresion is not supported: uncompress manually")
        } else {
            // Assumes no extra compression
            Ok(Self::PlainFile(BufReader::new(f)))
        }
    }
}

impl std::io::Read for BufferedReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
        match self {
            Self::PlainFile(ref mut h) => h.read(buf),
            #[cfg(feature = "flate2")]
            Self::GzFile(ref mut h) => h.read(buf),
        }
    }
}

impl std::io::BufRead for BufferedReader {
    fn fill_buf(&mut self) -> Result<&[u8], std::io::Error> {
        match self {
            Self::PlainFile(ref mut bufreader) => bufreader.fill_buf(),
            #[cfg(feature = "flate2")]
            Self::GzFile(ref mut bufreader) => bufreader.fill_buf(),
        }
    }
    fn consume(&mut self, s: usize) {
        match self {
            Self::PlainFile(ref mut bufreader) => bufreader.consume(s),
            #[cfg(feature = "flate2")]
            Self::GzFile(ref mut bufreader) => bufreader.consume(s),
        }
    }
}