I am sorry if the title sounds confusing, i wouldn't know how to phrase it better.
We try to use this csv crate to read csv files. Due to our framework's design, we should expose the functions init()
and tick()
, where tick()
should read and handle one value from the csv iterator. However, i do not yet understand how to deal with lifetimes in this case. Here is a simplified example:
extern crate csv;
extern crate rustc_serialize;
use csv::DecodedRecords;
use std::fs;
fn main() {
let mut handle = CSVHandle { reader: None, iterator: None};
handle.init();
handle.tick();
}
struct CSVHandle<'a> {
pub reader: Option<Box<csv::Reader<fs::File>>>,
pub iterator: Option<Box<csv::DecodedRecords<'a, fs::File, Point>>>
}
impl<'a> CSVHandle<'a> {
fn init(&mut self) {
self.reader = Some(Box::new(csv::Reader::from_file("./src/Sample.csv").unwrap()));
}
fn tick(&mut self) {
//read one element from iterator and do stuff
}
}
#[derive(RustcDecodable, Clone, Debug)]
pub struct Point {
pub x: i32,
pub y: i32,
pub z: i32
}
If i understand lifetimes correctly (please correct me if i do not), this should create a Reader
on the heap (since it is in a box), and move the box into self
. The box and the reader should have the same lifetime, and the compiler knows it can drop them when it drops the CSVHandle
because we transferred the ownership to it. What is the lifetime of them now, actually? A new created one? Since i could assign a new value to reader
and that should lead to the old one being dropped i presume it cannot be the one of the CSVHandle
.
Now we need an iterator for the values, which i can get with:
pub fn decode<'a, D: Decodable>(&'a mut self) -> DecodedRecords<'a, R, D>
I guess the definition makes sense: The DecodedRecords
lifetime should not exceed the one of the Reader
it belongs to. But how can i save/move ownership of a DecodedRecords
?
If i change init()
to this:
let mut r = Box::new(csv::Reader::from_file("./src/Sample.csv").unwrap());
let mut i = Box::new(r.decode::<Point>());
the compiler does not complain, because r
and i
live in the same lifetime and all is well.
But we have to save i
, but i cannot just do self.iterator = Some(i);
because i would drop r
when it goes out of scope ("error: *r
does not live long enough").
So i tried to save both:
let mut r = Box::new(csv::Reader::from_file("./src/Sample.csv").unwrap());
self.reader = Some(r);
let mut i = Box::new(r.decode::<Point>());
self.iterator = Some(i);
but this way i would use a moved value. Saving the reader after decoding is also not possible: decode
borrows the reader, i cannot use it in the same scope afterwards.
So i tried playing with scopes:
let mut r = Box::new(csv::Reader::from_file("./src/Sample.csv").unwrap());
{
let i = Box::new(r.decode::<Point>());
self.iterator = Some(i);
}
self.reader = Some(r);
This way i can deal with decode
borrowing my reader and saving it later, but self.iterator = Some(i);
is not allowed because the compiler does not know that r
will actually live long enough - it thinks that r
will be dropped after init()
, and thus throws an error.
TL;DR: I have two things A and B, where B needs A as long as it is alive, and i want to move the ownership of both to a struct. How can i do that?