aoc_utils/
bufwrap.rs

1use std::fs::File;
2use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Stdin};
3use std::path::Path;
4
5pub type FileReader = BufReader<File>;
6pub type StdinReader = BufReader<Stdin>;
7
8/// Buffered input that can be either STDIN or a file.
9pub enum BufferedInput {
10    File(FileReader),
11    Stdin(StdinReader),
12}
13
14pub fn file_reader<P: AsRef<Path>>(path: P) -> std::io::Result<FileReader> {
15    let file = File::open(path)?;
16    let meta = file.metadata()?;
17
18    if meta.is_dir() {
19        return Err(Error::new(ErrorKind::Other, "Is a directory"));
20    }
21
22    let returned_reader = BufReader::new(file);
23
24    Ok(returned_reader)
25}
26
27pub fn stdin_reader() -> StdinReader {
28    BufReader::new(std::io::stdin())
29}
30
31impl BufferedInput {
32    /// Returns an iterator over the lines of the input
33    /// that panics when an error occurs.
34    pub fn unwrapped_lines(self) -> impl Iterator<Item = String> {
35        self.lines().map(Result::unwrap)
36    }
37}
38
39impl Read for BufferedInput {
40    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
41        match self {
42            Self::File(file_reader) => file_reader.read(buf),
43            Self::Stdin(stdin_reader) => stdin_reader.read(buf),
44        }
45    }
46}
47
48impl BufRead for BufferedInput {
49    fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
50        match self {
51            Self::File(file_reader) => file_reader.fill_buf(),
52            Self::Stdin(stdin_reader) => stdin_reader.fill_buf(),
53        }
54    }
55
56    fn consume(&mut self, amt: usize) {
57        match self {
58            Self::File(file_reader) => file_reader.consume(amt),
59            Self::Stdin(stdin_reader) => stdin_reader.consume(amt),
60        };
61    }
62}