I implemented a BoxedIterator
in Rust that just boxes another Iterator
as a trait object. The full implementation is on Github. Why does Rust compile this code without complaint but fail with an "out of memory" message (OOM) when it first tries to call next
on the Iterator
trait object in the Box
?
As far as I can tell it doesn't allocate much memory before failing, so I'm inclined to think the OOM message is not correct.
//! BoxedIterator just wraps around a box of an iterator, it is an owned trait object.
//! This allows it to be used inside other data-structures, such as a `Result`.
//! That means that you can `.collect()` on an `I where I: Iterator<Result<V, E>>` and get out a
//! `Result<BoxedIterator<V>, E>`. And then you can `try!` it. At least, that was my use-case.
use std::iter::FromIterator;
use std::iter::IntoIterator;
pub struct BoxedIterator<T> {
iter: Box<Iterator<Item = T>>,
}
impl<T> Iterator for BoxedIterator<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next() // The OOM comes from this call of `next`
}
}
impl<T> FromIterator<T> for BoxedIterator<T> {
fn from_iter<I>(iter: I) -> Self
where I: IntoIterator<Item = T>,
I::IntoIter: 'static
{
BoxedIterator { iter: Box::new(iter.into_iter()) }
}
}
use std::fs::File;
use std::io;
fn main() {
let iter: Result<BoxedIterator<File>, io::Error> =
vec!["/usr/bin/vi"].iter().cloned().map(File::open).collect();
let mut iter = iter.unwrap();
println!("{:?}", iter.next());
}
I don't think I'm going to use this code, as I've figured that my use case will need to traverse the Iterator
of Result
s completely to extract any errors so I might as well gather them in a Vec
at that point. But I'm still curious about this OOM.
While creating a minimal example, I found that without doing the File IO, I get a segfault:
use iterator::BoxedIterator;
fn main() {
let iter: Result<BoxedIterator<&str>, ()> =
vec![Ok("test1"), Ok("test2")].iter().cloned().collect();
let mut iter = iter.unwrap();
println!("{:?}", iter.next());
}
If I don't use any Result
, just create a BoxedIterator
with collect
, the code works as expected:
use iterator::BoxedIterator;
fn main() {
let mut iter: BoxedIterator<&str> = vec!["test1", "test2"].iter().cloned().collect();
println!("{:?}", iter.next());
// prints: Some("test1")
}