Reputation: 39
I am making an analog of c++'s iostream for rust recently, but get confused by the lifetime system.
I want to store a reference of reader or a bare reader in the IStream
, so I store an Q
in the structure. And than I use an phantom type D
for converting Q
to R
.
Here's the explaination:
R
is the Reader
where I actually need. Q
is the store type of R
, so Q
maybe a bare R
or reference &mut R
.D
to convert Q
to R
. Because borrow_from_mut(&mut R)
gives me an &mut R
, and borrow_from_mut(R)
also gives me an &mut R
. Thus it could be D: BorrowFromMut<Q>
.D
can be converted to R
by derefrence. So &mut D: DerefMut<R>
&mut D
can be dereferenced to D
, but I need the &mut D
dereferenced to R
, here must use a trait object
to dynamic dispatch the deref_mut
method, because of the absence of UFCS
.(trick: let tmp: &'c mut Q = &mut *self.istream.borrow_mut();
)Such trick makes IStream
able to store both &mut R
and R
.
But the code can't compile because of a lifetime issue:
let tmp: &'c mut Q = &mut *self.istream.borrow_mut();
//the Q borrowed from the RefCell only valid in the block, doesn't out live 'c.
how can I solve it?
here is the code sample:
pub struct IStream<'a,'b,R:'a+'b,Q:'a+'b,Sized? D:'b> where R: Reader, D: BorrowFromMut<Q>, &'b mut D: DerefMut<R> {
istream: Rc<RefCell<Q>>
}
impl<'a,'b,R,Q,D> Clone for IStream<'a,'b,R,Q,D> where R: Reader, D: BorrowFromMut<Q>, &'b mut D: DerefMut<R> {
fn clone(&self) -> IStream<'a,'b,R,Q,D> {
IStream {
istream: self.istream.clone()
}
}
}
impl<'a,'b,'c,F,R,Q,D> Shr<&'b mut F,IStream<'a,'c,R,Q,D>> for IStream<'a,'c,R,Q,D> where R: Reader, F: FromStr + Default, D: BorrowFromMut<Q>, &'c mut D: DerefMut<R> {
fn shr(mut self, output: &mut F) -> IStream<'a,'c,R,Q,D> {
let tmp: &'c mut Q = &mut *self.istream.borrow_mut();
let mut reader: &mut D = BorrowFromMut::borrow_from_mut(tmp);
let mut real_reader: &DerefMut<R> = &reader;
let mut buf = String::new(); // a string buffer
loop {
if let Ok(byte) = (*real_reader.deref_mut()).read_byte() {
if byte == '\u{A}' as u8 || byte == '\u{20}' as u8 {
break
} else {
buf.push(byte as char);
}
} else {
break
}
}
*output = FromStr::from_str(buf[]).unwrap_or_default();
IStream {
istream: self.istream.clone()
}
}
}
Upvotes: 2
Views: 188
Reputation: 430604
Here's a reproduction of the error you mentioned:
use std::cell::RefCell;
fn foo<'a>(rc: &'a RefCell<u8>) {
let b: &'a u8 = &*rc.borrow();
}
fn main() {
}
This fails to compile with
borrowed value does not live long enough
By definition, the result of borrow()
has a scope that is tied to the scope it's called in, you can't "trick" it by specifying a different lifetime. All that does is make the compiler tell you you can't do that.
Upvotes: 1
Reputation: 127761
I think you're trying to outsmart yourself. You don't need to be able to store a reader or a mutable reference to a reader at the same time, because you can easily convert such mutable reference to a full-fledged reader. Without these complications your code will look like this (note the example of by_ref()
below):
#![feature(slicing_syntax)]
use std::cell::RefCell;
use std::rc::Rc;
use std::str::FromStr;
use std::default::Default;
use std::io::ByRefReader;
pub struct IStream<R> where R: Reader {
istream: Rc<RefCell<R>>
}
impl<R> Clone for IStream<R> where R: Reader {
fn clone(&self) -> IStream<R> {
IStream {
istream: self.istream.clone()
}
}
}
impl<'b, F, R> Shr<&'b mut F, IStream<R>> for IStream<R> where R: Reader, F: FromStr + Default {
fn shr(self, output: &'b mut F) -> IStream<R> { // '
let mut real_reader = self.istream.borrow_mut();
let mut buf = String::new(); // a string buffer
loop {
if let Ok(byte) = real_reader.read_byte() {
if byte == '\u{A}' as u8 || byte == '\u{20}' as u8 {
break
} else {
buf.push(byte as char);
}
} else {
break
}
}
*output = FromStr::from_str(buf[]).unwrap_or_default();
self.clone()
}
}
fn main() {
let mut stdin = std::io::stdin();
let stdin_ref: &mut _ = &mut stdin; // a mutable reference to a reader
let is = IStream { istream: Rc::new(RefCell::new(stdin_ref.by_ref())) };
let mut x: uint = 0;
let mut y: uint = 0;
is >> &mut x >> &mut y;
println!("{}, {}", x, y);
}
Upvotes: 2