Trouble with closure lifetimes - rust

I am really struggling with closure lifetimes. I'm making a simple hangman game where all connections play one game. I'm attempting to pass a closure to a channel that will update the game and then broadcast JSON, but I am running into lifetime issues.
extern crate names;
extern crate ws;
#[macro_use]
extern crate json;
use names::{Generator, Name};
use std::collections::HashSet;
use std::sync::mpsc;
use std::thread;
use ws::{listen, CloseCode, Handler, Message, Result, Sender};
type Job = Box<FnMut(&mut Game) + Send>;
#[derive(Debug)]
struct Game {
word: Vec<String>,
guesses: HashSet<String>,
misses: u32,
progress: Vec<String>,
}
impl Game {
fn increment_miss(&mut self) {
self.misses += 1;
}
fn update_progress(&mut self, guess: &String) {
for (i, letter) in self.word.iter().enumerate() {
if letter == guess {
self.progress[i] = letter.clone();
}
}
}
fn status(&self) -> &str {
if self.misses > 10 {
"lose"
} else if self.progress == self.word {
"win"
} else {
"active"
}
}
}
struct Server {
out: Sender,
tx: std::sync::mpsc::Sender<Job>,
}
impl Handler for Server {
fn on_message(&mut self, msg: Message) -> Result<()> {
let string_msg = msg.to_string();
self.tx
.send(Box::new(move |mut game: &mut Game| {
if game.guesses.insert(string_msg.clone()) {
check_letter(&mut game, &string_msg);
};
let status = game.status();
let progress = game.progress.clone();
let guesses = game.guesses.clone().into_iter().collect::<Vec<String>>();
println!(
"guesses: {:?}, progress: {:?}, misses: {}, status: {}",
guesses, progress, game.misses, status
);
self.out.broadcast(json::stringify(object!{
"status" => "status",
"progress" => "progress",
"guesses" => "guesses",
"misses" => "misses",
}));
}))
.unwrap();
Ok(())
}
fn on_close(&mut self, code: CloseCode, reason: &str) {
match code {
CloseCode::Normal => println!("The client is done with the connection."),
CloseCode::Away => println!("The client is leaving the site."),
_ => println!("The client encountered an error: {}", reason),
}
}
}
fn check_letter(game: &mut Game, guess: &String) {
if game.word.contains(guess) {
game.update_progress(guess);
} else {
game.increment_miss();
}
}
fn generate_word() -> Vec<String> {
let mut generator = Generator::with_naming(Name::Plain);
generator
.next()
.unwrap()
.split("")
.map(|c| c.to_string())
.filter(|s| s != "")
.collect::<Vec<String>>()
}
fn start_game() -> Game {
let word = generate_word();
Game {
progress: vec!["".to_string(); word.len()],
word: word,
guesses: HashSet::new(),
misses: 0,
}
}
fn main() {
let (tx, rx) = mpsc::channel::<Job>();
thread::spawn(move || {
let mut game = start_game();
for mut received in rx {
received(&mut game)
}
});
listen("127.0.0.1:3000", |out| Server {
out: out,
tx: mpsc::Sender::clone(&tx),
}).unwrap();
}
I am getting the following error:
Compiling hang_man v0.1.0 (file:///Users/smykowski/workspace/rust/hang_man)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/main.rs:54:5
|
54 | / fn on_message(&mut self, msg: Message) -> Result<()> {
55 | | let string_msg = msg.to_string();
56 | |
57 | | self.tx.send(Box::new(move |mut game: &mut Game| {
... |
78 | | Ok(())
79 | | }
| |_____^
note: ...so that the type `[closure#src/main.rs:57:31: 76:10 string_msg:std::string::String, self:&mut Server]` will meet its required lifetime bounds
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<for<'r> std::ops::FnMut(&'r mut Game) + std::marker::Send + 'static>, found std::boxed::Box<for<'r> std::ops::FnMut(&'r mut Game) + std::marker::Send>)
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^

There is some confusion here because Rust is not very explicit about some features of lifetimes. In this example,
A closure's lifetime is limited by the lifetime of all the params moved into it. In your case, the closure is limited by self because of the line self.out.broadcast. Note that self is actually a reference in this case coming from the &self argument in fn on_message. Essentially you create something like
Box<FnMut(&mut Game) + Send + 'a>
Where 'a is a lifetime of &self.
When you create a boxed trait object, the default lifetime is 'static. That means that
type Job = Box<FnMut(&mut Game) + Send> = Box<FnMut(&mut Game) + Send + 'static>
To avoid this, you can make self cloneable and move self.clone() inside this closure.

Related

Iterator next method lifetime mismatch

I'm trying to create an Iterator interface using the csv crate such that I can return a HashMap of col-name: value and am running into a lifetime error I cannot figure out.
For the code below:
use csv::{
Reader,
StringRecord,
StringRecordsIter,
};
use std::collections::HashMap;
use std::fs::File;
pub struct Handler {
pub reader: Reader<File>
}
impl Handler {
pub fn new(file: File) -> Handler {
Handler { reader: Reader::from_reader(file) }
}
}
// type Row = HashMap<String, String>;
pub struct Row<'r> {
number: usize,
fields: HashMap<&'r str, &'r str>,
}
pub struct CSVIterator<'f> {
current_row: usize,
headers: StringRecord,
records: StringRecordsIter<'f, File>,
}
impl<'f> CSVIterator<'f> {
pub fn new(handler: &'f mut Handler) -> CSVIterator<'f> {
CSVIterator {
current_row: 0,
headers: handler.reader.headers().unwrap().clone(),
records: handler.reader.records(),
}
}
}
impl<'f> Iterator for CSVIterator<'f> {
type Item = Row<'f>;
fn next(&mut self) -> Option<Self::Item> {
let next_record = self.records.next();
if next_record.is_none() {
return None;
}
let record = next_record.unwrap().unwrap();
let fields = make_fields(&record, &self.headers);
let row = Row {
number: self.current_row,
fields: fields,
};
return Some(row)
}
}
fn make_fields<'r>(
record: &'r StringRecord, header: &'r StringRecord
) -> HashMap<&'r str, &'r str> {
let mut row: HashMap<&str, &str> = HashMap::new();
for (colname, value) in header.iter().zip(record) {
row.insert(colname, value);
}
row
}
I'm getting the following error:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/csvio.rs:55:43
|
55 | let fields = make_fields(&record, &self.headers);
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/csvio.rs:47:13
|
47 | fn next(&mut self) -> Option<Self::Item> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/csvio.rs:55:43
|
55 | let fields = make_fields(&record, &self.headers);
| ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'f` as defined here...
--> src/csvio.rs:44:6
|
44 | impl<'f> Iterator for CSVIterator<'f> {
| ^^
note: ...so that the types are compatible
--> src/csvio.rs:47:46
|
47 | fn next(&mut self) -> Option<Self::Item> {
| ______________________________________________^
48 | | let next_record = self.records.next();
49 | |
50 | | if next_record.is_none() {
... |
61 | | return Some(row)
62 | | }
| |_____^
= note: expected `<CSVIterator<'f> as Iterator>`
found `<CSVIterator<'_> as Iterator>`
For more information about this error, try `rustc --explain E0495`.
I may not intuitively understand the lifetime requirements for the next method here, can someone point me in the right direction?
Thanks!

Changing a member while in an async stream

I have a struct with a member. The implementation returns an async stream which changes this member on a specific event (in the example on each).
This fails with a lifetime error, which is understandable, since the struct itself is not necessarily in the same lifetime as the map in the stream. it sounds similar to lifetime around async and stream, but I am not sure if it is related.
use async_std::pin::Pin;
use futures::{Stream, StreamExt};
use std::time::Duration;
struct StreamProvider {
value: u16,
}
impl StreamProvider {
fn returnastream(self: &mut Self) -> Pin<Box<dyn Stream<Item = i32>>> {
return async_std::stream::interval(Duration::from_millis(1000))
.map(|_| {
// change a value of Self within the stream
self.value = self.value + 1;
1
})
.boxed();
}
}
#[async_std::main]
async fn main() {
let mut object = StreamProvider { value: 1 };
let mut worx = object.returnastream();
// subscribing to the items
while let item = worx.next().await {
match item {
Some(value) => println!("{}", value),
_ => {}
}
}
}
[dependencies]
futures = "0.3.6"
async-std = { version = "1.6.5", features = ["attributes", "unstable"] }
The Error message:
/Users/andre/.cargo/bin/cargo run --color=always --package traittest --bin traittest
Compiling traittest v0.1.0 (/Users/andre/repos/traittest)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:20:12
|
20 | }).boxed();
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 14:3...
--> src/main.rs:14:3
|
14 | / fn returnastream(self: &mut Self) -> Pin<Box<dyn Stream<Item=i32>>> {
15 | | return async_std::stream::interval(Duration::from_millis(1000))
16 | | .map(|_| {
17 | | // change a value of Self within the stream
... |
20 | | }).boxed();
21 | | }
| |___^
note: ...so that the type `futures_util::stream::stream::map::Map<async_std::stream::interval::Interval, [closure#src/main.rs:16:14: 20:10 self:&mut &mut StreamProvider]>` will meet its required lifetime bounds
--> src/main.rs:20:12
|
20 | }).boxed();
| ^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> src/main.rs:15:12
|
15 | return async_std::stream::interval(Duration::from_millis(1000))
| ____________^
16 | | .map(|_| {
17 | | // change a value of Self within the stream
18 | | self.value = self.value + 1;
19 | | 1
20 | | }).boxed();
| |__________________^
= note: expected `std::pin::Pin<std::boxed::Box<(dyn futures_core::stream::Stream<Item = i32> + 'static)>>`
found `std::pin::Pin<std::boxed::Box<dyn futures_core::stream::Stream<Item = i32>>>`
error: aborting due to previous error
Thanks to Peter Hall:
You need to use synchonisation primitives, for example Arc and Mutex, in order to access and mutate values that are owned by another thread.
This was the link I missed. Here's the result:
use std::time::Duration;
use async_std::pin::Pin;
use futures::{Stream, StreamExt};
use std::sync::{Arc, Mutex};
struct StreamProvider {
value: Arc<Mutex<u16>>,
}
impl StreamProvider {
fn returnastream(self: &mut Self) -> Pin<Box<dyn Stream<Item = i32>>> {
let v = self.value.clone();
return async_std::stream::interval(Duration::from_millis(1000))
.map(move |_| {
let mut a = v.lock().unwrap();
// change a value of Self within the stream
*a += 1;
1
})
.boxed();
}
}
#[async_std::main]
async fn main() {
let mut object = StreamProvider {
value: Arc::new(Mutex::new(1)),
};
let mut worx = object.returnastream();
// subscribing to the items
while let item = worx.next().await {
match item {
Some(_) => println!("{}", object.value.lock().unwrap()),
_ => {}
}
}
}
[dependencies]
futures = "0.3.6"
async-std = { version = "1.6.5", features = ["attributes", "unstable"] }

How to use Diesel connection and Gtk-rs events?

I am trying to do a get a object from a database with Diesel when the Enter key is pressed in a gtk Entry. My idea is to create a Diesel SQLite connection in main function and then borrow it every time that I need it.
To do that, I am trying to use a very simple MVC. The idea is to pass the connection to all the controllers and reuse it. I know that lifetime is necessary here.
pub struct Controller<'a> {
pub connection: &'a SQLiteConnection,
pub search_entry: SearchEntry,
....
}
impl<'a> Controller<'a> {
pub fn new(conn: &'a SQLiteConnection) -> Self {
Self {
search_entry: SearchEntry::new(),
connection: conn,
....
}
}
pub fn init(&self) {
self.search_entry.connect_activate(|x| {
let need_it = diesel_table
.filter(column_id.eq(&x.get_text().unwrap()))
.first(self.connection)
.unwrap();
});
}
}
When compile I get this:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:44:44
|
44 | self.search_entry.connect_activate(|x| {
| ____________________________________________^
45 | | let need_it = diesel_table
46 | | .filter(column_id.eq(&x.get_text().unwrap()))
47 | | .first(self.connection)
48 | | .unwrap();
49 | | });
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 43:5...
--> src/lib.rs:43:5
|
43 | / pub fn init(&self) {
44 | | let need_it = diesel_table
46 | | .filter(column_id.eq(&x.get_text().unwrap()))
47 | | .first(self.connection)
48 | | .unwrap();
49 | | });
50 | | }
| |_____^
note: ...so that the types are compatible
--> src/lib.rs:44:44
|
44 | self.search_entry.connect_activate(|x| {
| ____________________________________________^
45 | | let need_it = diesel_table
46 | | .filter(column_id.eq(&x.get_text().unwrap()))
47 | | .first(self.connection)
48 | | .unwrap();
49 | | });
| |_________^
= note: expected `&&Controller<'_>`
found `&&Controller<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#src/lib.rs:44:44: 49:10 self:&&Controller<'_>]` will meet its required lifetime bounds
--> src/lib.rs:44:27
|
44 | self.search_entry.connect_activate(|x| {
| ^^^^^^^^^^^^^^^^
This error is because the function connect_activate has a static parameter: fn connect_activate<F: Fn(&Self) + 'static>.
I would not like to initialize the connection every time that the user press the Intro key by using a function that returns a connection. Instead I would like to borrow that connection.
What would be the most efficient way to do that?
Thanks you very much. I hope you understand everything.
I think you need a Rc<SQLiteConnection>
The question contains various other code issues beside the one mentioned by the OP, so I will include a full working example based on the information provided above. For future questions: Please make sure that your example is self contained and do not contain other compilation errors as that one mentioned in the question. That will make it easier for other people to reproduce your problem and answer the question.
#[macro_use] extern crate diesel;
use diesel::prelude::*;
table! {
diesel_table(id) {
id -> Integer,
column_id -> Text,
}
}
pub struct Controller<'a> {
pub connection: &'a SqliteConnection,
pub search_entry: SearchEntry,
}
pub struct SearchEntry;
impl SearchEntry {
fn new() -> Self {
SearchEntry
}
fn connect_activate<'a, F: Fn(&Self) + 'a>(&self, f: F) {
f(self)
}
fn get_text(&self) -> Option<&'static str> {
Some("foo")
}
}
impl<'a> Controller<'a> {
pub fn new(conn: &'a SqliteConnection) -> Self {
Self {
search_entry: SearchEntry::new(),
connection: conn,
}
}
pub fn init(&self) {
self.search_entry.connect_activate(|x| {
use self::diesel_table::dsl::*;
let need_it: (i32, String) = diesel_table
.filter(column_id.eq(&x.get_text().unwrap()))
.first(self.connection)
.unwrap();
});
}
}
The only relevant change for solving the error described in the OP is the following change to connect_activate:
- fn connect_activate<F: Fn(&Self) + 'static>(&self, f: F) {
+ fn connect_activate<'a, F: Fn(&Self) + 'a>(&self, f: F) {

How to solve "lifetime must be valid for the static lifetime" in calling thread methods

I am a Rust beginner and I can’t get the following code to compile. I know this problem might be not new, tried searching all over the place but couldn't find a proper answer to the below problem.
Basically i m trying to call methods from thread, and also using different structs for sending and receiving objects between the threads.
use std::{thread, time};
struct SenderStruct;
impl SenderStruct {
fn send(&self, sndr: Sender<(Option<String>)>) {
let count = 0;
loop {
sndr.send(Some(String::from("Hello"))).unwrap();
thread::sleep(time::Duration::from_millis(1000));
count = count + 1;
if count == 50 {
break;
}
}
sndr.send(None);
}
}
struct ReceiveStruct;
impl ReceiveStruct {
fn receive(&self, rec: Receiver<Option<String>>) {
loop {
let recv_out = rec.recv().unwrap();
match recv_out {
Some(some_str) => println!("{}", some_str),
None => break,
}
}
}
}
struct SendReceiveStruct {
m_ss: SenderStruct,
m_sos: ReceiveStruct,
m_recv_hndlr: Option<thread::JoinHandle<()>>,
}
impl SendReceiveStruct {
fn new() -> Self {
SendReceiveStruct {
m_ss: SenderStruct {},
m_sos: ReceiveStruct {},
m_recv_hndlr: None,
}
}
fn start(&mut self) {
let (tx, rx): (Sender<(Option<String>)>, Receiver<Option<String>>) = channel();
thread::spawn(move || self.m_ss.send(tx));
self.m_recv_hndlr = Some(thread::spawn(move || self.m_sos.receive(rx)));
}
fn wait_for_recevier(&mut self) {
self.m_recv_hndlr.unwrap().join();
}
}
fn main() {
println!("Hello, world!");
let mut ubs = SendReceiveStruct::new();
ubs.start();
ubs.wait_for_recevier();
}
But i m getting lifetime issues all over the place
$ cargo build
Compiling threads v0.1.0 (/root/learn-rust/threads)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:55:23
|
55 | thread::spawn(move || self.m_ss.send(tx));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 52:5...
--> src/main.rs:52:5
|
52 | / fn start(&mut self) {
53 | | let (tx, rx): (Sender<(Option<String>)>, Receiver<Option<String>>) = channel();
54 | |
55 | | thread::spawn(move || self.m_ss.send(tx));
56 | | self.m_recv_hndlr = Some(thread::spawn(move || self.m_sos.receive(rx)));
57 | | }
| |_____^
= note: ...so that the types are compatible:
expected &mut SendReceiveStruct
found &mut SendReceiveStruct
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#src/main.rs:55:23: 55:49 self:&mut SendReceiveStruct, tx:std::sync::mpsc::Sender<std::option::Option<std::string::String>>]` will meet its required lifetime bounds
--> src/main.rs:55:9
|
55 | thread::spawn(move || self.m_ss.send(tx));
Any pointers (or other references) would really help, and also any other possible approaches for the above problem ?
If you examine the signature of std::thread::spawn:
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
and its documentation closely:
The 'static constraint means that the closure and its return value must have a lifetime of the whole program execution. The reason for this is that threads can detach and outlive the lifetime they have been created in.
However, the &mut self value closure closes over may not live long enough. One way to overcome that is to clone the value the closure actually uses:
#[derive(Clone)]
struct SenderStruct;
#[derive(Clone)]
struct ReceiveStruct;
impl SendReceiveStruct {
fn start(&mut self) {
let (tx, rx): (Sender<Option<String>>, Receiver<Option<String>>) = channel();
thread::spawn({
let ss = self.m_ss.clone();
move || ss.send(tx)
});
self.m_recv_hndlr = Some(thread::spawn({
let sos = self.m_sos.clone();
move || sos.receive(rx)
}));
}
fn wait_for_recevier(&mut self) {
self.m_recv_hndlr.take().unwrap().join();
}
}
Except for several other minor issues, your code now compiles.

Anonymous vs struct lifetime for assignment

For this code (trimmed some, sorry not more), I get a lifetime problem:
fn main() {
println!("Hello, world!");
}
#[derive(Debug)]
pub struct Token<'a> {
pub line: usize,
// Col in code points.
pub col: usize,
// Index in bytes.
pub index: usize,
pub state: TokenState,
pub text: &'a str,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TokenState {
VSpace,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ParseState {
Expr,
}
pub struct Node<'a> {
kids: Vec<Node<'a>>,
state: ParseState,
token: Option<&'a Token<'a>>,
}
impl<'a> Node<'a> {
fn new(state: ParseState) -> Node<'a> {
Node {
kids: vec![],
state,
token: None,
}
}
fn new_token(token: &'a Token<'a>) -> Node<'a> {
// TODO Control state? Some token state?
Node {
kids: vec![],
state: ParseState::Expr,
token: Some(&token),
}
}
fn push_if(&mut self, node: Node<'a>) {
if !node.kids.is_empty() {
self.kids.push(node);
}
}
}
pub fn parse<'a>(tokens: &'a Vec<Token<'a>>) -> Node<'a> {
let mut root = Node::new(ParseState::Expr);
let mut parser = Parser {
index: 0,
tokens: tokens,
};
parser.parse_block(&mut root);
root
}
struct Parser<'a> {
index: usize,
tokens: &'a Vec<Token<'a>>,
}
impl<'a> Parser<'a> {
fn parse_block(&mut self, parent: &mut Node) {
loop {
let mut row = Node::new(ParseState::Expr);
match self.peek() {
Some(_) => {
self.parse_row(&mut row);
}
None => {
break;
}
}
parent.push_if(row);
}
}
fn parse_row(&mut self, parent: &mut Node) {
loop {
match self.next() {
Some(ref token) => match token.state {
TokenState::VSpace => break,
_ => {
parent.kids.push(Node::new_token(&token));
}
},
None => break,
}
}
}
fn next(&mut self) -> Option<&Token> {
let index = self.index;
if index < self.tokens.len() {
self.index += 1;
}
self.tokens.get(index)
}
fn peek(&mut self) -> Option<&Token> {
self.tokens.get(self.index)
}
}
(playground)
This is the error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:90:24
|
90 | match self.next() {
| ^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 72:1...
--> src/main.rs:72:1
|
72 | / impl<'a> Parser<'a> {
73 | | fn parse_block(&mut self, parent: &mut Node) {
74 | | loop {
75 | | let mut row = Node::new(ParseState::Expr);
... |
112| | }
113| | }
| |_^
note: ...so that the type `Parser<'a>` is not borrowed for too long
--> src/main.rs:90:19
|
90 | match self.next() {
| ^^^^
note: but, the lifetime must be valid for the anonymous lifetime #3 defined on the method body at 88:5...
--> src/main.rs:88:5
|
88 | / fn parse_row(&mut self, parent: &mut Node) {
89 | | loop {
90 | | match self.next() {
91 | | Some(ref token) => match token.state {
... |
99 | | }
100| | }
| |_____^
note: ...so that expression is assignable (expected Node<'_>, found Node<'_>)
--> src/main.rs:94:42
|
94 | parent.kids.push(Node::new_token(&token));
| ^^^^^^^^^^^^^^^^^^^^^^^
All the references should be tied to the same outside lifetime. In my full code (of which I just have an excerpt here), I expect to hang onto the original parsed source, and I'm trying to tie everything to that.
I know the error messages are trying to be helpful, but I'm really unsure what the conflict is. And I'm unsure what other lifetime questions here are related to the same issue I have or not.
Let's take a look at the signature of Parser::next:
fn next(&mut self) -> Option<&Token>
This function promises to return an Option<&Token>. There are elided lifetimes here; let's rewrite the signature to make them explicit:
fn next<'b>(&'b mut self) -> Option<&'b Token<'b>>
We can now see that next is generic over lifetime 'b. Notice how the return type uses 'b, not 'a. This is valid in itself, because the compiler can infer that 'b is a shorter than 'a, and mutable references (&'a mut T) are covariant over 'a ("covariant" in this context means that we can substitute lifetime 'a with a shorter lifetime). But what the function ends up promising is that the result lives at least as long as itself, while it can in fact live at least as long as 'a.
In Parser::parse_row, you're trying to take the result of Parser::next and insert it into parent. Let's look at Parser::parse_row's signature:
fn parse_row(&mut self, parent: &mut Node)
We have some omitted lifetimes here again. Let's spell them out:
fn parse_row<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>)
'c is not going to be important, so we can ignore it.
If we try to compile now, the last two notes are different:
note: but, the lifetime must be valid for the lifetime 'd as defined on the method body at 88:5...
--> src/main.rs:88:5
|
88 | / fn parse_row<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>) {
89 | | loop {
90 | | match self.next() {
91 | | Some(ref token) => match token.state {
... |
99 | | }
100| | }
| |_____^
note: ...so that expression is assignable (expected Node<'d>, found Node<'_>)
--> src/main.rs:94:42
|
94 | parent.kids.push(Node::new_token(&token));
| ^^^^^^^^^^^^^^^^^^^^^^^
Now, one of the anonymous lifetimes is identified as 'd. The other is still an anonymous lifetime, and that's an artifact of how the compiler manipulates lifetimes, but we can think of it as being 'b here.
The problem should be a bit clearer now: we're trying to push a Node<'b> into a collection of Node<'d> objects. It's important that the type be exactly Node<'d>, because mutable references (&'a mut T) are invariant over T ("invariant" means it can't change).
Let's make the lifetimes match. First, we'll change next's signature to match what we can actually return:
fn next(&mut self) -> Option<&'a Token<'a>>
This means that now, when we call self.next() in parse_row, we'll be able to construct a Node<'a>. A Node<'x> can only store Node<'x> objects (per your definition of Node), so the parent parameter's referent must also be of type Node<'a>.
fn parse_row(&mut self, parent: &mut Node<'a>)
If we try to compile now, we'll get an error in Parser::parse_block on the call to parse_row. The problem is similar to what we just saw. parse_block's signature is:
fn parse_block(&mut self, parent: &mut Node)
which expands to:
fn parse_block<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>)
Here's the error the compiler gives with this elaborated signature:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:78:26
|
78 | self.parse_row(&mut row);
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 72:1...
--> src/main.rs:72:1
|
72 | / impl<'a> Parser<'a> {
73 | | fn parse_block<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>) {
74 | | loop {
75 | | let mut row = Node::new(ParseState::Expr);
... |
112| | }
113| | }
| |_^
note: ...so that types are compatible (expected &mut Parser<'_>, found &mut Parser<'a>)
--> src/main.rs:78:26
|
78 | self.parse_row(&mut row);
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'd as defined on the method body at 73:5...
--> src/main.rs:73:5
|
73 | / fn parse_block<'b, 'c, 'd>(&'b mut self, parent: &'c mut Node<'d>) {
74 | | loop {
75 | | let mut row = Node::new(ParseState::Expr);
76 | | match self.peek() {
... |
85 | | }
86 | | }
| |_____^
note: ...so that types are compatible (expected &mut Node<'_>, found &mut Node<'d>)
--> src/main.rs:84:20
|
84 | parent.push_if(row);
| ^^^^^^^
The compiler is unable to infer the type of row (specifically, the lifetime in its type Node<'x>). On one hand, the call to parse_row means it should be Node<'a>, but the call to push_if means it should be Node<'d>. 'a and 'd are unrelated, so the compiler doesn't know how to unify them.
The solution is easy, and it's the same as above: just make parent have type &mut Node<'a>.
fn parse_block(&mut self, parent: &mut Node<'a>)
Now your code compiles!

Resources