csvsc 2.2.1

Build processing chains for CSV files
Documentation
use crate::{Headers, Row, RowStream, error};

pub struct MapCol<I, F> {
    iter: I,
    f: F,
    colname: String,
    headers: Headers,
}

/// Allows you to build a custom transformation of the current row
impl<I, F> MapCol<I, F>
where
    I: RowStream,
    F: Fn(&str) -> error::Result<String>,
{
    pub fn new(
        iter: I,
        colname: String,
        f: F,
    ) -> MapCol<I, F> {
        let headers = iter.headers().clone();

        MapCol {
            iter,
            f,
            colname,
            headers,
        }
    }
}

pub struct IntoIter<I, F> {
    iter: I,
    f: F,
    colname: String,
    headers: Headers,
}

impl<I, F> Iterator for IntoIter<I, F>
where
    I: Iterator<Item = error::RowResult>,
    F: Fn(&str) -> error::Result<String>,
{
    type Item = error::RowResult;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|result| {
            result.and_then(|val| {
                let mut new_row = Row::with_capacity(val.as_slice().len(), val.len());

                for col in self.headers.iter().zip(val.iter()).map(|(header, col)| {
                    if header == self.colname {
                        (self.f)(col)
                    } else {
                        Ok(col.into())
                    }
                }) {
                    match col {
                        Ok(s) => new_row.push_field(&s),
                        Err(e) => return Err(e),
                    }
                }

                Ok(new_row)
            })
        })
    }
}

impl<I, F> IntoIterator for MapCol<I, F>
where
    I: RowStream,
    F: Fn(&str) -> error::Result<String>,
{
    type Item = error::RowResult;

    type IntoIter = IntoIter<I::IntoIter, F>;

    fn into_iter(self) -> Self::IntoIter {
        Self::IntoIter {
            iter: self.iter.into_iter(),
            f: self.f,
            colname: self.colname,
            headers: self.headers,
        }
    }
}

impl<I, F> RowStream for MapCol<I, F>
where
    I: RowStream,
    F: Fn(&str) -> error::Result<String>,
{
    fn headers(&self) -> &Headers {
        &self.headers
    }
}