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
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
//! A collection of convenience methods around loading files into various containers.
//!
//! This crate contains a few small wrapper methods around common operations in the standard
//! library for loading files. The `Read` trait is a little cumbersome if you don't want to bother
//! keeping up with a buffer, or if you're only loading one file. Here, you can wrap up all that
//! boilerplate into little one-off functions!
//!
//! To read a file into a string:
//!
//! ```no_run
//! let my_file = slurp::read_all_to_string("myfile.txt").unwrap();
//! ```
//!
//! To read a file into a byte vector:
//!
//! ```no_run
//! let my_file = slurp::read_all_bytes("myfile.txt").unwrap();
//! ```
//!
//! Or, to read a file into a Vec where each element is a different line:
//!
//! ```no_run
//! let my_file: Vec<String> = slurp::read_all_lines("myfile.txt").unwrap();
//! ```
//!
//! There's also an iterator to lazily load the lines, though it's mainly a wrapper over
//! `io::BufReader`:
//!
//! ```no_run
//! for line in slurp::iterate_all_lines("myfile.txt") {
//!     let line = line.unwrap();
//! }
//! ```

#![deny(warnings, missing_docs)]

use std::io::{self, Read, BufRead};
use std::fs::File;
use std::path::{Path, PathBuf};

/// Reads the file at the given filename into a new String.
pub fn read_all_to_string<P: AsRef<Path>>(filename: P) -> io::Result<String> {
    let mut out = String::new();
    let mut file = File::open(filename)?;

    file.read_to_string(&mut out)?;

    Ok(out)
}

/// Reads the file at the given filename into a new byte vector.
pub fn read_all_bytes<P: AsRef<Path>>(filename: P) -> io::Result<Vec<u8>> {
    let mut out = Vec::new();
    let mut file = File::open(filename)?;

    file.read_to_end(&mut out)?;

    Ok(out)
}

/// Returns an iterator over the lines in the file at the given filename.
///
/// Note that this iterator lazily opens the file - it won't touch the filesystem until you start
/// iterating.
pub fn iterate_all_lines<P: AsRef<Path>>(filename: P) -> Lines {
    Lines {
        filename: filename.as_ref().to_path_buf(),
        iter: None,
    }
}

/// Reads the lines of the file at the given filename into a new collection of Strings.
pub fn read_all_lines<P: AsRef<Path>>(filename: P) -> io::Result<Vec<String>> {
    iterate_all_lines(filename).collect()
}

/// Iterator over the lines of a file.
///
/// See [`iterate_all_lines`] for details.
///
/// [`iterate_all_lines`]: fn.iterate_all_lines.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Lines {
    filename: PathBuf,
    iter: Option<io::Lines<io::BufReader<File>>>,
}

impl Iterator for Lines {
    type Item = io::Result<String>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.iter.is_none() {
            match File::open(&self.filename) {
                Ok(f) => self.iter = Some(io::BufReader::new(f).lines()),
                Err(e) => return Some(Err(e)),
            }
        }

        self.iter.as_mut().and_then(|i| i.next())
    }
}