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
#[macro_use]
#[allow(unused_imports)]
extern crate easy_csv_derive;
extern crate csv;

#[derive(Debug)]
pub enum Error {
    CSVError(csv::Error),
    MissingColumnError(String),
    ParseError(String)
}

impl std::convert::From<csv::Error> for Error {
    fn from(e: csv::Error) -> Error {
        Error::CSVError(e)
    }
}

pub trait CSVParsable<T> {
    fn parse_header<R: std::io::Read>(
        reader: &mut csv::Reader<R>) -> Result<Vec<usize>, ::Error>;
    fn parse_row<R: std::io::Read>(
        reader: &mut std::iter::Enumerate<csv::StringRecords<R>>,
        col_indices: &Vec<usize>) -> Option<Result<T, ::Error>>;
}

pub struct CSVIterator<'a, T, R> where T: CSVParsable<T>, R: 'a, R: std::io::Read {
    records: std::iter::Enumerate<csv::StringRecords<'a, R>>,
    col_indices: Vec<usize>,
    _marker: std::marker::PhantomData<T>
}

impl<'a, T, R> CSVIterator<'a, T, R> where T: CSVParsable<T>, R: 'a, R: std::io::Read {
    pub fn new(mut reader: &'a mut csv::Reader<R>) -> Result<Self, ::Error> {
        let col_indices = try!(T::parse_header(&mut reader));
        Ok(CSVIterator {
            records: reader.records::<'a>().into_iter().enumerate(),
            col_indices: col_indices,
            _marker: std::marker::PhantomData::<T> {}
        })
    }
}

impl<'a, T, R> Iterator for CSVIterator<'a, T, R> where T: CSVParsable<T>, R: std::io::Read {
    type Item=Result<T, ::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        T::parse_row(&mut self.records, &self.col_indices)
    }
}