Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement std::io::Read for an Iterator<Item = String>?

Tags:

iterator

io

rust

More specifically, I'm taking standard in, filtering out certain rows with .lines().filter_map() and I want to use the result of that with a csv::Reader.

like image 355
Shepmaster Avatar asked Feb 01 '26 02:02

Shepmaster


1 Answers

The standard library provides the type std::io::Cursor which wraps a buffer together with a position in the buffer. This can be used to further simplify the code given in Veedrac's answer:

use std::io::{self, Cursor, Read};

struct IteratorAsRead<I>
where
    I: Iterator,
{
    iter: I,
    cursor: Option<Cursor<I::Item>>,
}

impl<I> IteratorAsRead<I>
where
    I: Iterator,
{
    pub fn new<T>(iter: T) -> Self
    where
        T: IntoIterator<IntoIter = I, Item = I::Item>,
    {
        let mut iter = iter.into_iter();
        let cursor = iter.next().map(Cursor::new);
        IteratorAsRead { iter, cursor }
    }
}

impl<I> Read for IteratorAsRead<I>
where
    I: Iterator,
    Cursor<I::Item>: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        while let Some(ref mut cursor) = self.cursor {
            let read = cursor.read(buf)?;
            if read > 0 {
                return Ok(read);
            }
            self.cursor = self.iter.next().map(Cursor::new);
        }
        Ok(0)
    }
}

#[test]
fn small_pieces_are_combined() {
    let iterable = ["h", "e", "l", "l", "o"];
    let mut reader = IteratorAsRead::new(&iterable);

    let mut buf = vec![];
    let bytes = reader.read_to_end(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"hello");
}

#[test]
fn partial_reads() {
    let iterable = ["hello"];
    let mut reader = IteratorAsRead::new(&iterable);

    let mut buf = [0; 2];

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"he");

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"ll");

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"o");
}

Playground

like image 199
Sven Marnach Avatar answered Feb 03 '26 19:02

Sven Marnach



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!