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}