I am learning Rust and playing with Tokio, channels and Serde. I am having difficulty writing some very basic code:
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::{channel, Receiver};
struct WorkflowProcess {
rx: Receiver<String>,
}
#[derive(Deserialize, Serialize)]
struct Msg {
version: i32,
}
impl WorkflowProcess {
async fn process<'a, T: Deserialize<'a>>(&mut self, callback: impl Fn(T)) {
let r = self.rx.recv().await;
if let Some(v) = r {
let s: &str = v.as_str();
let deserialized: T = serde_json::from_str(s).unwrap();
callback(deserialized);
}
}
}
#[tokio::main]
async fn main() {
let (tx, rx) = channel::<String>(100);
let mut workflow = WorkflowProcess { rx };
let worker = tokio::spawn(async move {
let x = |msg: Msg| {
assert_eq!(
msg.version,
32
);
};
workflow.process(x).await;
});
let serialized = serde_json::to_string(&Msg { version: 32 }).unwrap();
tx.send(serialized).await;
worker.await;
}
Trying to compile gives me this error:
error[E0597]: `v` does not live long enough
--> src/main.rs:17:27
|
14 | async fn process<'a, T: Deserialize<'a>>(&mut self, callback: impl Fn(T)) {
| -- lifetime `'a` defined here
...
17 | let s: &str = v.as_str();
| ^^^^^^^^^^ borrowed value does not live long enough
18 | let deserialized: T = serde_json::from_str(s).unwrap();
| ----------------------- argument requires that `v` is borrowed for `'a`
19 | callback(deserialized);
20 | }
| - `v` dropped here while still borrowed
It seems to me the deserialized lifetime falls within the lifetime of v and s, but I am guessing 'a is not what I think it is. I wish there was a lifetime debugger/visualizer for Rust. Is 'a same as 'static in this case?
I know I can use DeserializeOwned, but I really wanted to get to the bottom of my misunderstanding.
You can use HRTB as #Jmb suggested in the comments:
impl WorkflowProcess {
async fn process<T>(&mut self, callback: impl Fn(T))
where
for<'a> T: Deserialize<'a>,
{
let r = self.rx.recv().await;
if let Some(v) = r {
let deserialized: T = {
let s: &str = v.as_str();
serde_json::from_str(s).unwrap()
};
callback(deserialized);
}
}
}
Playground
Related
I'm using the below code in my real project. (Obviously this is simplified and one file only for playground.)
Rust explorer playground
As you can see I'm trying to use a sqlx Transaction from one function to a closure.
But I'm stucked.
I don't even know if this (so common Golang pattern) is the best wat to do in Rust. But at least it should work now.
use std::{future::Future, pin::Pin, sync::Arc};
pub trait Trait: Send + Sync + Player + Shirt {}
impl<T: Player + Shirt> Trait for T {}
pub type Lambda<'a, ArgT, ResT> =
dyn Fn(ArgT) -> Pin<Box<dyn Future<Output = Result<ResT, String>> + Send + 'a>> + Sync + 'a;
#[async_trait::async_trait]
pub trait Player: Send + Sync {
async fn player_create<'a>(
&'a self,
_input: &PlayerInput,
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer, String>;
}
#[async_trait::async_trait]
pub trait Shirt: Send + Sync {
async fn shirt_get_next_and_increase<'a>(
&'a self,
tx: &'a mut sqlx::PgConnection,
model: String,
) -> Result<i64, String>;
}
pub struct Repo {
pub pool: Arc<sqlx::PgPool>,
}
impl Repo {
pub fn new(pool: Arc<sqlx::PgPool>) -> Self {
Self { pool }
}
}
#[async_trait::async_trait]
impl Player for Repo {
async fn player_create<'a>(
&'a self,
_input: &PlayerInput,
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer, String> {
let mut tx = self.pool.begin().await.unwrap();
// use _input here
let shirt_next_value = Box::new(|model: String| {
self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
});
let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
let res =
sqlx::query_as::<_, DomainPlayer>("INSERT INTO player (...) VALUES (...) RETURNING *")
.bind(domain_player.id)
.bind(domain_player.shirt_number)
.fetch_one(&mut *tx)
.await
.unwrap();
Ok(res)
}
}
#[async_trait::async_trait]
impl Shirt for Repo {
async fn shirt_get_next_and_increase<'a>(
&'a self,
_tx: &'a mut sqlx::PgConnection,
_model: String,
) -> Result<i64, String> {
// Here I'm awaiting an async call for DB operations using the same DB transacion of the caller (_tx)...
// use _tx here...
let res = 123;
Ok(res)
}
}
pub struct Needs {
pub command_pg_repo: Arc<dyn Trait>,
}
#[derive(Default)]
pub struct PlayerInput {
pub id: String,
}
#[derive(Debug, Default, Clone, sqlx::FromRow)]
pub struct DomainPlayer {
pub id: String,
pub shirt_number: i64,
}
pub struct PlayerCreateLambdaArgs<'a> {
// other needed fields here
pub shirt_next_value: Box<
dyn FnMut(String) -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send + 'a>>
+ Send
+ Sync
+ 'a,
>,
}
pub struct Handler {
needs: Arc<Needs>,
}
impl Handler {
pub fn new(needs: Arc<Needs>) -> Self {
Self { needs }
}
pub async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
let res = self
.needs
.command_pg_repo
.player_create(&input, &|mut args| {
let input = input;
Box::pin(async move {
let shirt_number = (args.shirt_next_value)("player".to_string()).await?;
let o = DomainPlayer {
id: input.id.to_string(),
shirt_number,
};
Ok(o)
})
})
.await?;
Ok(res)
}
}
#[tokio::main]
async fn main() -> Result<(), String> {
let db_conn = sqlx::PgPool::connect("fake_url").await.unwrap();
let pg_repo = Arc::new(Repo::new(Arc::new(db_conn)));
let needs = Arc::new(Needs {
command_pg_repo: pg_repo,
});
let handler = Handler::new(needs);
let new_player_input = PlayerInput {
id: "abc".to_string(),
};
let player = handler.handle(&new_player_input).await?;
dbg!(player);
Ok(())
}
The error:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:62:13
|
57 | let mut tx = self.pool.begin().await.unwrap();
| ------ variable defined here
...
61 | let shirt_next_value = Box::new(|model: String| {
| - inferred to be a `FnMut` closure
62 | self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^
| | |
| | variable captured here
| returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
error[E0597]: `tx` does not live long enough
--> src/main.rs:62:65
|
55 | lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
| ------ lifetime `'1` appears in the type of `lambda`
...
61 | let shirt_next_value = Box::new(|model: String| {
| --------------- value captured here
62 | self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
| ^^ borrowed value does not live long enough
...
65 | let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
| ---------------- this usage requires that `tx` is borrowed for `'1`
...
76 | }
| - `tx` dropped here while still borrowed
error[E0499]: cannot borrow `tx` as mutable more than once at a time
--> src/main.rs:71:34
|
55 | lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
| ------ lifetime `'1` appears in the type of `lambda`
...
61 | let shirt_next_value = Box::new(|model: String| {
| --------------- first mutable borrow occurs here
62 | self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
| -- first borrow occurs due to use of `tx` in closure
...
65 | let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
| ---------------- this usage requires that `tx` is borrowed for `'1`
...
71 | .fetch_one(&mut *tx)
| ^^ second mutable borrow occurs here
Some errors have detailed explanations: E0499, E0597.
For more information about an error, try `rustc --explain E0499`.
There are 3 main issues with the code (more like 2 and a half):
Closures cannot return references to things the closure owns, or things the closure borrowed mutably (More formally: the return type of the Fn* function/closure family of traits cannot borrow from the closure type itself). One way to fix this is to have tx be moved into the closure, and then moved into the closure's returned Future. Shared ownership can be achieved with std::sync::Arc, and cloning it and moving it when you need to give another task ownership.
Fn closures may be called concurrently, so they cannot use mutable references to things the closure owns or has borrowed, but this code tries to use a &mut tx borrowing from the outer scope inside a Fn closure. (This issue is bypassed with the solution outlined below).
If you want to access something mutably when it is shared, you need to synchronize those accesses so only one thing can actually access it at a time. One way to do this in async Rust is using tokio::sync::Mutex.
Combining the above, putting tx into a Arc<Mutex<...>>, moving .clone()s of the Arc into the tasks that need ownership, and .lock().awaiting whenever you need to access it mutably may fix your problem (it makes it compile at least).
Rust explorer
diff --git a/src/main.rs b/src/main.rs
index 89fc611..6f7d375 100644
--- a/src/main.rs
+++ b/src/main.rs
## -1,5 +1,7 ##
use std::{future::Future, pin::Pin, sync::Arc};
+use tokio::sync::Mutex;
+
pub trait Trait: Send + Sync + Player + Shirt {}
impl<T: Player + Shirt> Trait for T {}
## -42,12 +44,19 ## impl Player for Repo {
_input: &PlayerInput,
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer, String> {
- let mut tx = self.pool.begin().await.unwrap();
+ let tx = Arc::new(Mutex::new(self.pool.begin().await.unwrap()));
// use _input here
- let shirt_next_value = Box::new(|model: String| {
- self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
+ let shirt_next_value = Box::new({
+ let tx = tx.clone();
+ move |model: String| -> Pin<Box<dyn Future<Output = Result<i64, std::string::String>> + Send>> {
+ let tx = tx.clone();
+ Box::pin(async move {
+ self::Shirt::shirt_get_next_and_increase(self, &mut *tx.lock().await, model)
+ .await
+ })
+ }
});
let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
## -56,7 +65,7 ## impl Player for Repo {
sqlx::query_as::<_, DomainPlayer>("INSERT INTO player (...) VALUES (...) RETURNING *")
.bind(domain_player.id)
.bind(domain_player.shirt_number)
- .fetch_one(&mut *tx)
+ .fetch_one(&mut *tx.lock().await)
.await
.unwrap();
Note that because a &mut PgConenction is passed to shirt_get_next_and_increase inside the async block, which references the MutexGuard<Transaction<...>> returned by tx.lock().await, the MutexGuard will be held until shirt_get_next_and_increase completes, even while it yeilds (if it yields). This shouldn't be an issue in this code, since it appears to be mostly sequential, and does not access tx until shirt_get_next_and_increase has completed. If this is not what you want, (i.e. if your actual code does access tx concurrently while shirt_get_next_and_increase is running) you could instead have shirt_get_next_and_increase take a &Mutex<Transaction<...>>, and only have it hold the lock when it needs to access the connection.
An sketch of an alternate solution would be to restructure the code so that the Transaction is passed around by value in function arguments and return values, e.g.
pub type Lambda<'a, ArgT, ResT> =
dyn Fn(ArgT) -> Pin<Box<dyn Future<Output = Result<(ResT, ArgT), String>> + Send + 'a>> + Sync + 'a;
// ...
async fn shirt_get_next_and_increase<'a>(
&'a self,
mut tx: sqlx::Transaction<'static, sqlx::PgConnection>,
_model: String,
) -> Result<(i64, sqlx::Transaction<'static, sqlx::PgConnection>), String> {
// ...
Ok((value, tx))
}
This could resolve the borrowing and shared-mutability issues, but may make the API more cumbersome, and may be infeasible for other reasons.
I am new to Rust and trying to implement a simple TCP-Server that sends me a live image. Therefore I am using this crate https://crates.io/crates/tinybmp for the RawBmp-type. Now I am struggling a bit to understand some of Rusts functionality. Or let's say I am still trying to figure out how to accomplish this in the 'Rust way'.
pub struct TCPBasePackage {
haspayload: bool,
pkgbytes: Vec<u8>,
}
impl TCPBasePackage {
pub const CMD: i32 = 0;
pub fn new() -> TCPBasePackage {
TCPBasePackage { haspayload: false, pkgbytes: Vec::new()}
}
}
impl TCPPackage for TCPBasePackage {
fn serialize(&mut self) -> &[u8] {
self.pkgbytes.append(&mut self.get_command().to_be_bytes().to_vec());
self.pkgbytes.append(&mut [u8::from(self.haspayload)].to_vec());
self.pkgbytes.as_slice()
}
fn read_from_stream(&mut self, mut stream: &TcpStream) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
let mut buf_pkg: [u8; 5] = [0; 5];
stream.read_exact(&mut buf_pkg).unwrap();
vec.append(&mut buf_pkg.to_vec());
self.pkgbytes = vec.to_vec();
return self.pkgbytes.clone();
}
fn deserialize(&mut self, buff: &[u8]) -> i32 {
self.haspayload = buff[4] != 0;
return 5;
}
fn get_command(&self) -> i32 {
TCPBasePackage::CMD
}
}
pub struct MsgLiveImage<'a> {
tcppackage: TCPBasePackage,
imgbytes: Vec::<u8>,
img: RawBmp<'a>,
}
impl<'a> MsgLiveImage<'a> {
pub const CMD: i32 = 2;
pub fn new() -> MsgLiveImage<'static> {
MsgLiveImage {
tcppackage: TCPBasePackage { haspayload: false, pkgbytes: Vec::new() },
imgbytes: Vec::new(),
img: RawBmp::from_slice(&[]).unwrap()
}
}
pub fn set_image_data(&'a mut self, data: Vec::<u8>) {
self.imgbytes = data;
self.img = RawBmp::from_slice(&self.imgbytes.as_slice()).unwrap();
}
}
In some function of my application I want to do this:
fn write_response_to_stream(
mut request: &Box<dyn mytcp::TCPPackage>,
mut stream: &TcpStream,
raspicam: &Arc<Mutex<camserv::CamServ>>,
) -> Result<Box<dyn mytcp::TCPPackage>, &'static str> {
match request.get_command() {
mytcp::MsgLiveImage::CMD => {
let mut pkg = mytcp::MsgLiveImage::new();
{
{
let tmpcam = raspicam.lock().unwrap(); // lock the camera server
let tmpbuff = tmpcam.imgbuff.lock().unwrap(); // lock the buffer of last image
pkg.set_image_data((*tmpbuff).clone()); // make copy of my image and transfer ownership of that copy to the package struct
}
{
let sbuff = pkg.serialize();
stream.write(&sbuff);
}
stream.flush();
}
Ok(Box::new(pkg)) // return the response package
}
_ => Err("Unknown request package"),
}
}
But the problem is, that the compiler is complaining about multiple borrowing the pkg-variable. As well as moving the pkg out of scope (which i learned should be possible by wrapping it in a Box.
Can someone explain me why the first mutable borrow still lasts even after the method returns? How can i achieve to call multiple methods on my struct without getting these borrowing conflicts?
Errors from rustc:
error[E0499]: cannot borrow `pkg` as mutable more than once at a time
--> src/raspiserv/mod.rs:90:33
|
87 | pkg.set_image_data((*tmpbuff).clone());
| -------------------------------------- first mutable borrow occurs here
...
90 | let sbuff = pkg.serialize();
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
95 | Ok(Box::new(pkg))
| ----------------- returning this value requires that `pkg` is borrowed for `'static`
error[E0515]: cannot return value referencing local variable `pkg`
--> src/raspiserv/mod.rs:95:13
|
87 | pkg.set_image_data((*tmpbuff).clone());
| -------------------------------------- `pkg` is borrowed here
...
95 | Ok(Box::new(pkg))
| ^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
error[E0505]: cannot move out of `pkg` because it is borrowed
--> src/raspiserv/mod.rs:95:25
|
87 | pkg.set_image_data((*tmpbuff).clone());
| -------------------------------------- borrow of `pkg` occurs here
...
95 | Ok(Box::new(pkg))
| ------------^^^--
| | |
| | move out of `pkg` occurs here
| returning this value requires that `pkg` is borrowed for `'static`
The problem is with your set_image_data
pub fn set_image_data(&'a mut self, data: Vec::<u8>) {
self.imgbytes = data;
self.img = RawBmp::from_slice(&self.imgbytes.as_slice()).unwrap();
}
you borrow self for the lifetime of 'a which is as long as the RawBmp inside of it is valid.
Thus the borrow lasts as long as the struct.
What you have is a self referential struct see this question on them for suggestions how to reslove this.
You can probably just drop the img from MsgLiveImage and replace it with a method:
impl MsgLiveImage {
pub fn as_img<'a>(&'a self) -> Result<RawBmp<'a>, ParseError> {
RawBmp::from_slice(&self.imgbytes.as_slice())
}
}
Might even be able to omit the lifetimes from that.
So I've got the following structs
struct Item;
#[derive(Default)]
struct Resource<'a> {
_marker: std::marker::PhantomData<&'a ()>,
}
impl<'a> Resource<'a> {
// Note: item has to be borrowed for 'a
fn do_nothing(&mut self, item: &'a Item) {
let _ = item;
}
}
struct Context<'a> {
resource: Resource<'a>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Self { resource: Resource::default() }
}
fn do_something(&mut self, item: &'a Item) {
self.resource.do_nothing(item);
}
}
And the following function that uses those sturcts.
fn do_stuff<F>(callback: F)
where
F: FnOnce(Context),
{
let ctx = Context::new();
(callback)(ctx);
}
When I try using this in the following manner
fn main() {
let item = Item;
do_stuff(|mut ctx| {
ctx.do_something(&item);
});
}
It gives the following compiler error:
error[E0597]: `item` does not live long enough
--> src/main.rs:40:27
|
39 | do_stuff(|mut ctx| {
| --------- value captured here
40 | ctx.do_something(&item);
| ------------------^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `item` is borrowed for `'static`
41 | });
42 | }
| - `item` dropped here while still borrowed
However, with my limited understanding of rust lifetimes, I'm not sure how to fix it. Item should outlive ctx as ctx only lives as long as do_stuff(?). Is there a way to tell the compiler that item lives longer then ctx?
One thing I highly recommend when dealing with lifetimes is to attempt to desugar lifetime elision as much as possible. The issue here actually happens in your definition of do_stuff:
fn do_stuff<F>(callback: F)
where
F: FnOnce(Context),
{
let ctx = Context::new();
(callback)(ctx);
}
which desugars to:
fn do_stuff<F>(callback: F)
where
F: FnOnce(Context<'static>),
{
let ctx = Context::new();
callback(ctx);
}
That 'static is what is causing the error. If you make the function generic over lifetime 'a the error goes away:
fn do_stuff<'a, F>(callback: F)
where
F: FnOnce(Context<'a>),
{
let ctx = Context::new();
callback(ctx);
}
playground
I'm playing around with building a very simple stack based evaluator in Rust. I want the user to be able to define functions later, so I'm storing all operators in a HashMap with closures as values.
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator<'a> {
stack: Vec<Value>,
ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)>,
}
impl<'a> Evaluator<'a> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)> = HashMap::new();
ops.insert("+".to_string(), &|stack: &'a mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
});
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&'a mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
I'm currently getting two errors:
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:34:17
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
34 | self.stack.push(n);
| ^^^^^^^^^^ second mutable borrow occurs here
...
38 | f(&mut self.stack);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `self.stack` is borrowed for `'a`
error[E0596]: cannot borrow `**f` as mutable, as it is behind a `&` reference
--> src/sample.rs:38:21
|
38 | f(&mut self.stack);
| ^ cannot borrow as mutable
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:38:23
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
38 | f(&mut self.stack);
| --^^^^^^^^^^^^^^^-
| | |
| | `self.stack` was mutably borrowed here in the previous iteration of the loop
| argument requires that `self.stack` is borrowed for `'a`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0499, E0596.
For more information about an error, try `rustc --explain E0499`.
My concern is the first one. I'm not sure what I'm doing wrong as I'm not borrowing them at the same time. Can I tell Rust the previous borrow (self.stack.pop()) is done? Any help appreciated.
I think I solved my problem. The thing I kept coming back to is, "What owns the closures?" In this case I'm using references, but nothing is taking ownership of the data. When I refactored (below) with Box to take ownership, it worked.
I'm curious if there is a way to do this with with just references and/or if my explanation is wrong?
Working code:
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator {
stack: Vec<Value>,
ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>>,
}
impl Evaluator {
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>> = HashMap::new();
ops.insert("+".to_string(), Box::new(|stack: &mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
}));
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get_mut(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
You have borrows with conflicting lifetimes:
You are defining a lifetime 'a for the struct in line 5: pub struct Evaluator<'a> {
In line 7, you are stating that ops is a HashMap that holds functions that receive mutable borrows for the whole duration of 'a
Then, in line 28, you are defining an eval method that holds a mutable reference to self for the whole duration of the struct ('a)
The conflict can be solved if you use two different lifetimes, since the time that an operation borrows self should be inherently shorter than the lifetime for the whole evaluation, since in eval you are running a loop and multiple invocations to the operations.
This should fix the issues mentioned above:
pub struct Evaluator<'a, 'b> {
stack: Vec<Value>,
ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)>,
}
impl<'a, 'b> Evaluator<'a, 'b> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)> = HashMap::new();
I feel like I am totally lost; what does "'1" mean in the error message?
error[E0597]: `o` does not live long enough
--> src/main.rs:32:19
|
31 | async fn foo6(&mut self, mut o: &'a mut Outer) {
| --------- lifetime `'1` appears in the type of `self`
32 | self.foo5(&mut o).await
| ----------^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `o` is borrowed for `'1`
33 | }
| - `o` dropped here while still borrowed
What can I do to make o live long enough? I think I'm using futures 03.
use futures::future::BoxFuture;
use futures::FutureExt;
use futures::stream::FuturesOrdered;
struct Inner {}
impl Inner {
async fn foo3(&mut self) -> Result<u32, ()> {
Ok(8)
}
}
// --- 1
struct Outer {
i: Inner,
}
impl Outer {
fn foo4(&mut self) -> BoxFuture<'_, Result<u32, ()>> {
self.i.foo3().boxed()
}
}
/// --- 2
struct Outer2<'a> {
futures_list: FuturesOrdered<BoxFuture<'a, Result<u32, ()>>>,
}
impl <'a> Outer2<'a> {
async fn foo6(&mut self, mut o: &'a mut Outer) {
self.foo5(&mut o).await
}
async fn foo5(&mut self, o: &'a mut Outer) {
self.futures_list.push(o.foo4());
}
}
#[tokio::main]
async fn main() {
let mut o = Outer { i: Inner {} };
let mut o2 = Outer2 { futures_list: FuturesOrdered::new() };
o2.foo5(&mut o).await;
}
playground
The '1 represents the anonymous lifetime of the self parameter for function foo5.
Note that in foo6, o is already a mutable reference to Outer, so writing &mut o actually gives you a mutable reference to a mutable reference to Outer with one too many indirections. You can fix your code by removing the extra reference:
async fn foo6(&mut self, mut o: &'a mut Outer) {
self.foo5(o).await
}
Playground