use crate::{Headers, Row, RowStream, error};
pub struct MapCol<I, F> {
iter: I,
f: F,
colname: String,
headers: Headers,
}
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
}
}