sfackler/streaming-iterator

Allow an iterator of borrowed values to be used instead of a streaming iterator

Closed this issue · 3 comments

Sometimes when using rust-postgres-binary-copy, which takes values as a streaming iterator, I want to use a slice of borrowed ToSql values. I might not own these values, so I can't give ownership to a streaming iterator in the normal way.

However, since a streaming iterator yields references to the iterator's item anyway, it should be possible to use these APIs without having to provide ownership to the iterator. I've been working around this by implementing the StreamingIterator trait on top of an existing Iterator of references:

use streaming_iterator::StreamingIterator;

pub struct FakeStreamingIterator<'a, I, T>
    where I: Iterator<Item=&'a &'a T>, T: 'a + ?Sized {

    inner: Box<I>,
    current: Option<&'a &'a T>,
}

impl<'a, I, T> FakeStreamingIterator<'a, I, T>
    where I: Iterator<Item=&'a &'a T>, T: ?Sized {

    fn new(inner: I) -> FakeStreamingIterator<'a, I, T> {
        FakeStreamingIterator { inner: Box::new(inner), current: None }
    }
}

impl<'a, I, T> StreamingIterator for FakeStreamingIterator<'a, I, T>
    where I: Iterator<Item=&'a &'a T>, T: ?Sized {

    type Item = T;

    fn advance(&mut self) { self.current = self.inner.next(); }
    fn get(&self) -> Option<&T> { self.current.map(|x| *x) }
}

pub fn convert<'a, I, T>(iterator: I) -> FakeStreamingIterator<'a, I, T>
    where I: Iterator<Item=&'a &'a T>, T: ?Sized {

    FakeStreamingIterator::new(iterator)
}

This then allows me to construct a FakeStreamingIterator from a slice of references, and treat it as a normal StreamingIterator. However, it's a bit of a hack, so I'm curious what the officially supported way to handle this case is — maybe something like my FakeStreamingIterator should be included to support this use case?

Yep, that seems totally reasonable to add. I think it'd probably like this to avoid the forced double indirection: fn convert_ref<'a, I, T>(i: I) -> ConvertRef<I> where I: Iterator<Item = &'a T>. You could then call it like convert_ref(my_values.iter().map(|v| *v)).

Yeah, that would be fine — this is just what I came up with after several hours of blindly fighting the compiler. :D

Shall I make a PR?

Yes please!