pgs_files/
entries.rs

1/// Generic `Iterator` over implementor's of
2/// [`Entry`](trait.Entry.html)'s.
3///
4/// # Examples
5///
6/// #### Iterate over /etc/passwd printing usernames
7///
8/// ```
9/// use std::path::Path;
10/// use pgs_files::passwd::PasswdEntry;
11/// use pgs_files::Entries;
12///
13/// for entry in Entries::<PasswdEntry>::new(&Path::new("/etc/passwd")) {
14///     println!("{}", entry.name);
15/// }
16/// ```
17
18use std::io::{BufRead,BufReader};
19use std::fs::File;
20use std::path::Path;
21use std::marker::PhantomData;
22use std::num::ParseIntError;
23
24
25pub struct Entries<T> {
26    cursor: BufReader<File>,
27    marker: PhantomData<T>,
28}
29
30impl<T> Entries<T> {
31    pub fn new(file: &Path) -> Entries<T> {
32        let reader = BufReader::new(File::open(file).ok().unwrap());
33        Entries {
34            cursor: reader,
35            marker: PhantomData,
36        }
37    }
38}
39
40
41impl<T: Entry> Iterator for Entries<T> {
42
43    type Item = T;
44
45    fn next(&mut self) -> Option<T> {
46        let mut line = String::new();
47        loop {
48            // We might need to make multiple loops to drain off
49            // comment lines. Start with an empty string per loop.
50            line.clear();
51            match self.cursor.read_line(&mut line){
52                Ok(0) => return None,
53                Ok(_) => (),
54                _     => return None,
55            }
56
57            if line.starts_with("#") {
58                continue;
59            }
60
61            match T::from_line(&line) {
62                Ok(entry) => return Some(entry),
63                // Parse Error. Just ignore this entry.
64                _         => (),
65            }
66        }
67    }
68
69}
70
71/// A Trait to represent an entry of data from an
72/// /etc/{`passwd`,`group`,`shadow`} file.
73pub trait Entry: Sized {
74    fn from_line(line: &str) -> Result<Self, ParseIntError>;
75}