Cannot infer an appropriate lifetime due to conflicting requirements - rust

I am new to rust and I am building a TUI app using rust-tui to practice and understand the concepts of rust. I have this code:
// the widgets that can be renderd on the screen
#[derive(Clone)]
pub enum Widgets<'a> {
ResList(ResList<'a>),
ListResults(ListResults<'a>),
Input(Input),
}
pub struct Screen<'a> {
renders_done: u32,
tx: Sender<Result<Event, crossterm::ErrorKind>>,
rx: Receiver<Result<Event, crossterm::ErrorKind>>,
main_screen: Widgets<'a>,
}
impl Screen<'_> {
pub async fn handle_events(&mut self) {
let event = self
.rx
.recv()
.expect("Err while recievent the events in the reciever")
.unwrap();
let new_screen: Option<Widgets> = match &mut self.main_screen {
Widgets::ResList(res_list) => {
match event {
Event::Key(event) => match event.code {
KeyCode::Esc => {
Screen::exit_app();
None
}
_ => None,
}
}
Widgets::Input(input) => input.handle_events(event).await, <-- the problem comes when I add this
_ => None,
};
match new_screen {
Some(screen) => self.main_screen = screen,
None => {}
}
}
}
impl Input {
async fn handle_events(&mut self, event: Event) -> Option<Widgets> {
None
}
}
The idea is that if a sub-module returns a widget the main screen should be changed to that new widget. For texting purposes for now I never return a widget.
But when I try and build the code the compiler complains:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/model/tui/screen.rs:84:32
|
84 | pub async fn handle_events(&mut self) {
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the method body at 84:32...
--> src/model/tui/screen.rs:84:32
|
84 | pub async fn handle_events(&mut self) {
| ^
note: ...so that the expression is assignable
--> src/model/tui/screen.rs:84:32
|
84 | pub async fn handle_events(&mut self) {
| ^^^^^^^^^
= note: expected `&mut Screen<'_>`
found `&mut Screen<'_>`
note: but, the lifetime must be valid for the lifetime `'_` as defined on the impl at 45:13...
--> src/model/tui/screen.rs:45:13
|
45 | impl Screen<'_> {
| ^^
note: ...so that the expression is assignable
--> src/model/tui/screen.rs:126:52
|
126 | Some(mut screen) => self.main_screen = screen,
| ^^^^^^
= note: expected `Widgets<'_>`
found `Widgets<'_>`
error: aborting due to previous error; 8 warnings emitted
For more information about this error, try `rustc --explain E0495`.
From what I understand the lifetimes are not living enough to be saved in the struct but I am not using references anywhere they are all owned values. Can someone help me understand what am I missing?

Specify the lifetimes explicitly on the widget returned and create an explicit lifetime of the object:
impl<'screen> Screen<'screen> {
pub async fn handle_events<'c>(&'cmut self) {
let event = self
.rx
.recv()
.expect("Err while recievent the events in the reciever")
.unwrap();
let new_screen: Option<Widgets<'screen>> = match &mut self.main_screen {
Widgets::ResList(res_list) => {
match event {
Event::Key(event) => match event.code {
KeyCode::Esc => {
Screen::exit_app();
None
}
_ => None,
}
}
Widgets::Input(input) => input.handle_events(event).await,
_ => None,
};
match new_screen {
Some(screen) => self.main_screen = screen,
None => {}
}
}
}
Also add the lifetime explicitly when returning a Widget from inside a function

Related

Change the root node in a binary tree

I wrote a binary tree of i32. I want to change its root node to left node. But always failed. How to do it?
fn left(&mut self) -> Result<(), Error> {
match self.root.as_mut() {
Some(root) => match root.left {
Some(left) => {
self.root = Some(left); // this line always failed
return Ok(());
}
None => {
return Err(Error::NotFound);
}
},
None => {
return Err(Error::EmptyTree);
}
}
}
self.root = Some(left) I think it is easy to do this, but always failed.
error[E0507]: cannot move out of `root.left.0` which is behind a mutable reference
--> src/main.rs:120:33
|
120 | Some(root) => match root.left {
| ^^^^^^^^^ help: consider borrowing here: `&root.left`
121 | Some(left) => {
| ----
| |
| data moved here
| move occurs because `left` has type `Box<Node>`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
playground
You can use std::mem::take, which allows taking things out of a mutable reference to them (replacing the pointed value with the default value of that type). That is, your function left can be rewritten:
use std::mem::take;
fn left(&mut self) -> Result<(), Error> {
let root = self.root.as_mut().ok_or(Error::EmptyTree)?;
let left = take(&mut root.left).ok_or(Error::NotFound)?;
*root = left;
Ok(())
}
Edit: turns out there is a method that does exactly that. I'll leave my first snippet so that you understand what happens, but the following is probably more suitable in real code.
fn left(&mut self) -> Result<(), Error> {
let root = self.root.as_mut().ok_or(Error::EmptyTree)?;
let left = root.left.take().ok_or(Error::NotFound)?;
*root = left;
Ok(())
}

How to write an asynchronous recursive walkdir function with an asynchronous callback

I'm trying to write an async function that will traverse the filesystem tree, recursively, and calls an asynchronous callback for each file found.
This is for a learning effort, I have no real use case.
Here is what I have so far:
use async_std::{
fs::{self, *},
path::*,
prelude::*,
}; // 1.5.0, features = ["unstable"]
use futures::{
executor::block_on,
future::{BoxFuture, FutureExt},
}; // 0.3.4
use std::{marker::Sync, pin::Pin};
fn main() {
fn walkdir<F>(path: String, cb: &'static F) -> BoxFuture<'static, ()>
where
F: Fn(&DirEntry) -> BoxFuture<()> + Sync + Send,
{
async move {
let mut entries = fs::read_dir(&path).await.unwrap();
while let Some(path) = entries.next().await {
let entry = path.unwrap();
let path = entry.path().to_str().unwrap().to_string();
if entry.path().is_file().await {
cb(&entry).await
} else {
walkdir(path, cb).await
}
}
}
.boxed()
}
let foo = async {
walkdir(".".to_string(), &|entry: &DirEntry| async {
async_std::println!(">> {}\n", &entry.path().to_str().unwrap()).await
})
.await
};
block_on(foo);
}
I get this far by some sort of trial and error, but now I'm stuck on async closure callback with this error
warning: unused import: `path::*`
--> src/main.rs:3:5
|
3 | path::*,
| ^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `pin::Pin`
--> src/main.rs:10:25
|
10 | use std::{marker::Sync, pin::Pin};
| ^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:33:54
|
33 | walkdir(".".to_string(), &|entry: &DirEntry| async {
| ______________________________________________________^
34 | | async_std::println!(">> {}\n", &entry.path().to_str().unwrap()).await
35 | | })
| |_________^ expected struct `std::pin::Pin`, found opaque type
|
= note: expected struct `std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = ()> + std::marker::Send>>`
found opaque type `impl core::future::future::Future`
use async_std::{
fs::{self, *},
path::*,
prelude::*,
}; // 1.5.0
use futures::{future::{Future, FutureExt, LocalBoxFuture}, executor}; // 0.3.4
fn main() {
async fn walkdir<R>(path: impl AsRef<Path>, mut cb: impl FnMut(DirEntry) -> R)
where
R: Future<Output = ()>,
{
fn walkdir_inner<'a, R>(path: &'a Path, cb: &'a mut dyn FnMut(DirEntry) -> R) -> LocalBoxFuture<'a, ()>
where
R: Future<Output = ()>,
{
async move {
let mut entries = fs::read_dir(path).await.unwrap();
while let Some(path) = entries.next().await {
let entry = path.unwrap();
let path = entry.path();
if path.is_file().await {
cb(entry).await
} else {
walkdir_inner(&path, cb).await
}
}
}.boxed_local()
}
walkdir_inner(path.as_ref(), &mut cb).await
}
executor::block_on({
walkdir(".", |entry| async move {
async_std::println!(">> {}", entry.path().display()).await
})
});
}
Notable changes:
Take in AsRef<Path> instead of a String and a generic closure instead of a trait object reference
Change the closure type to be FnMut as it's more permissive
The closure returns any type that is a future.
There's an inner implementation function that hides the ugly API required for recursive async functions.
The callback takes the DirEntry by value instead of by reference.
See also:
How to asynchronously explore a directory and its sub-directories?
How to using async fn callback in rust

Converting a future result in another future

I have a function that returns a future with a User trait. I have two concrete implementations of it: AnonymousUser and BaseUser. To get the BaseUser, after authentication, I have to go to the database and fetch it, which may or not succeed, and return the new future with the correct type. I've tried the following (playground):
extern crate futures; // 0.1.23
extern crate rand; // 0.5.4
use futures::future::{ok, Future};
use std::io::Error;
trait User {}
#[derive(Debug)]
struct AnonymousUser;
impl User for AnonymousUser {}
#[derive(Debug)]
struct BaseUser;
impl User for BaseUser {}
fn fetch_base_user() -> impl Future<Item = BaseUser, Error = Error> {
ok(BaseUser)
}
fn run_future() -> impl Future<Item = impl User, Error = Error> {
match rand::random::<bool>() {
true => fetch_base_user().from_err().then(move |res| match res {
Ok(user) => ok(user),
Err(_) => ok(AnonymousUser),
}),
false => ok(AnonymousUser),
}
}
fn main() {
run_future().and_then(move |user| println!("User {:?}", user));
}
this failed because the return of the then function expects a BaseUser:
error[E0308]: match arms have incompatible types
--> src/main.rs:23:62
|
23 | true => fetch_base_user().from_err().then(move |res| match res {
| ______________________________________________________________^
24 | | Ok(user) => ok(user),
25 | | Err(_) => ok(AnonymousUser),
| | ----------------- match arm with an incompatible type
26 | | }),
| |_________^ expected struct `BaseUser`, found struct `AnonymousUser`
|
= note: expected type `futures::FutureResult<BaseUser, _>`
found type `futures::FutureResult<AnonymousUser, _>`
I tried forcing the return type:
use futures::future::FutureResult;
fn run_future() -> impl Future<Item=impl User, Error=Error> {
match rand::random::<bool>() {
true => fetch_base_user().from_err().then(move |res| ->
FutureResult<impl User, Error> { // Forcing the result type here
match res {
Ok(user) => ok(user),
Err(_) => ok(AnonymousUser),
}
}),
false => ok(AnonymousUser),
}
}
which fails with:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/main.rs:27:22
|
27 | FutureResult<impl User, Error> { // Forcing the result type here
| ^^^^^^^^^
I've tried to rework using Boxes for the return, which almost worked (playground)
fn run_future() -> impl Future<Item = Box<impl User>, Error = Error> {
match rand::random::<bool>() {
true => fetch_base_user()
.from_err()
.then(move |res| -> FutureResult<Box<User>, Error> {
match res {
Ok(user) => ok(Box::new(user) as Box<User>),
Err(_) => ok(Box::new(AnonymousUser) as Box<User>),
}
}),
false => ok(Box::new(AnonymousUser) as Box<User>),
}
}
which fails with
error[E0308]: match arms have incompatible types
--> src/main.rs:22:5
|
22 | / match rand::random::<bool>() {
23 | | true => fetch_base_user().from_err().then(move |res| match res {
24 | | Ok(user) => ok(Box::new(user) as Box<User>),
25 | | Err(_) => ok(Box::new(AnonymousUser) as Box<User>),
26 | | }),
27 | | false => ok(Box::new(AnonymousUser) as Box<User>),
| | ---------------------------------------- match arm with an incompatible type
28 | | }
| |_____^ expected struct `futures::Then`, found struct `futures::FutureResult`
|
= note: expected type `futures::Then<futures::future::FromErr<impl futures::Future, _>, futures::FutureResult<std::boxed::Box<User>, _>, [closure#src/main.rs:23:51: 26:10]>`
found type `futures::FutureResult<std::boxed::Box<User>, _>`
So I guess it's only a matter of forcing both to be the same result type
At the end the comment from shepmaster led me to the response through this other question: How do I conditionally return different types of futures?
Basically using Either::A and Either::B solves the issue. I still couldn't make it work without boxing the parameters but this might be a different question.

Resolve elided static lifetime when borrowing from an object pool

This is a simplified version of the issue I am currently facing.
trait SuperObject {
fn object_name(&self) -> String;
}
trait Inspect {
fn inspect(&self);
}
impl Inspect for SuperObject {
fn inspect(&self) {
println!("I am a Superobject.");
}
}
struct Object {
name: String
}
impl SuperObject for Box<Object> {
fn object_name(&self) -> String {
format!("I am {}.", self.name.clone())
}
}
struct ObjectPool {
object1: Box<Object>,
object2: Box<Object>,
object3: Box<Object>
}
impl ObjectPool {
pub fn new() -> ObjectPool {
ObjectPool {
object1: Box::new(Object { name: String::from("Object 1") }),
object2: Box::new(Object { name: String::from("Object 2") }),
object3: Box::new(Object { name: String::from("Object 3") })
}
}
fn all_objects(&self) -> Vec<&SuperObject> {
let mut ret: Vec<&SuperObject> = Vec::new();
ret.push(&self.object1);
ret.push(&self.object2);
ret.push(&self.object3);
ret
}
}
fn main() {
let objectpool: ObjectPool = ObjectPool::new();
let allobjects: Vec<&SuperObject> = objectpool.all_objects();
for i in &allobjects {
println!("{}", i.object_name());
// Comment the following line in order to drop error E0597
i.inspect(); // FIXME: borrowed value must be valid for the static lifetime
}
}
The error when attempting to compile this snippet is as follows:
error[E0597]: `objectpool` does not live long enough
--> src/main.rs:50:41
|
50 | let allobjects: Vec<&SuperObject> = objectpool.all_objects();
| ^^^^^^^^^^ does not live long enough
...
56 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
After numerous searches, from what I understand, the objects being instantiated have a default static lifetime, as referred in https://doc.rust-lang.org/book/second-edition/ch19-02-advanced-lifetimes.html
I believe the output of ObjectPool's all_objects method is elided by the compiler as static as is evidenced by one of the errors evoked when I attempted to debug the snippet:
error[E0308]: mismatched types
--> src/main.rs:42:18
|
42 | ret.push(&self.object2);
| ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found reference
|
= note: expected type `std::boxed::Box<SuperObject>`
found type `&std::boxed::Box<SuperObject + 'static>`
What would be the best course of action this doesn't involve scrapping the object pool altogether? Or is there a more elegant abstraction befitting for rust implementations?
The issue is your impl Inspect for SuperObject. Implementing a trait for another trait does not do what you expect from it. Basically the rule is: never do it. Essentially it means that only when you have a &(SuperObject + 'static), you'll be able to treat it as an Inspect. What you want is
impl<T: SuperObject + ?Sized> Inspect for T {
fn inspect(&self) {
println!("I am a Superobject.");
}
}

Lifetime issue with CpuPool

I'm writing a simple RPC server with tokio and futures-cpupool. The server holds a BTreeMap of boxed closures, with the function name as key. The current implementation is pretty straight-forward:
pub struct SlackerServiceSync<T>
where T: Send + Sync + 'static
{
functions: Arc<BTreeMap<String, RpcFnSync<T>>>,
pool: CpuPool,
}
impl<T> SlackerServiceSync<T>
where T: Send + Sync + 'static
{
pub fn new(functions: Arc<BTreeMap<String, RpcFnSync<T>>>,
threads: usize)
-> SlackerServiceSync<T> {
let pool = CpuPool::new(threads);
SlackerServiceSync { functions, pool }
}
}
impl<T> Service for SlackerServiceSync<T>
where T: Send + Sync + 'static
{
type Request = SlackerPacket<T>;
type Response = SlackerPacket<T>;
type Error = io::Error;
type Future = BoxFuture<Self::Response, Self::Error>;
fn call(&self, req: Self::Request) -> Self::Future {
match req {
SlackerPacket::Request(sreq) => {
debug!("getting request: {:?}", sreq.fname);
if let Some(f) = self.functions.get(&sreq.fname) {
self.pool
.spawn_fn(move || -> FutureResult<T, Self::Error> {
ok(f(&sreq.arguments))
})
.and_then(move |result| {
debug!("getting results");
ok(SlackerPacket::Response(SlackerResponse {
version: sreq.version,
code: RESULT_CODE_SUCCESS,
content_type: sreq.content_type,
serial_id: sreq.serial_id,
result: result,
}))
})
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Oneshot canceled"))
.boxed()
} else {
let error = SlackerError {
version: sreq.version,
code: RESULT_CODE_NOT_FOUND,
serial_id: sreq.serial_id,
};
ok(SlackerPacket::Error(error)).boxed()
}
}
SlackerPacket::Ping(ref ping) => {
ok(SlackerPacket::Pong(SlackerPong { version: ping.version })).boxed()
}
_ => err(io::Error::new(io::ErrorKind::InvalidInput, "Unsupported packet")).boxed(),
}
}
}
I'm currently blocked by this lifetime issue on self.functions.get(&sreq.fname).
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/service.rs:103:49
|
103 | if let Some(f) = self.functions.get(&sreq.fname) {
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 99:55...
--> src/service.rs:99:56
|
99 | fn call(&self, req: Self::Request) -> Self::Future {
| ________________________________________________________^
100 | | match req {
101 | | SlackerPacket::Request(sreq) => {
102 | | debug!("getting request: {:?}", sreq.fname);
... |
133 | | }
134 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/service.rs:103:34
|
103 | if let Some(f) = self.functions.get(&sreq.fname) {
| ^^^^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#src/service.rs:105:35: 107:36 f:&std::boxed::Box<for<'r> std::ops::Fn(&'r std::vec::Vec<T>) -> T + std::marker::Send + std::marker::Sync>, sreq:packets::SlackerRequest<T>]` will meet its required lifetime bounds
--> src/service.rs:105:26
|
105 | .spawn_fn(move || -> FutureResult<T, Self::Error> {
| ^^^^^^^^
Similar code works without CpuPool. I cannot fully understand the error reported by compiler.
Full code is here
It turns out I need to wrap the closure into an Arc by declaring the RcpFnSync like this:
pub type RpcFnSync<T> = Arc<Fn(&Vec<T>) -> T + Send + Sync + 'static>;
Then clone it before sending to another thread:
fn call(&self, req: Self::Request) -> Self::Future {
match req {
SlackerPacket::Request(sreq) => {
debug!("getting request: {:?}", sreq.fname);
if let Some(fi) = self.functions.get(&sreq.fname) {
let f = fi.clone();
self.pool
.spawn_fn(move || -> FutureResult<Self::Response, Self::Error> {
let result = f(&sreq.arguments);
ok(SlackerPacket::Response(SlackerResponse {
version: sreq.version,
code: RESULT_CODE_SUCCESS,
content_type: sreq.content_type,
serial_id: sreq.serial_id,
result: result,
}))
})
.boxed()
} else {
let error = SlackerError {
version: sreq.version,
code: RESULT_CODE_NOT_FOUND,
serial_id: sreq.serial_id,
};
ok(SlackerPacket::Error(error)).boxed()
}
}
SlackerPacket::Ping(ref ping) => {
ok(SlackerPacket::Pong(SlackerPong { version: ping.version })).boxed()
}
_ => err(io::Error::new(io::ErrorKind::InvalidInput, "Unsupported packet")).boxed(),
}
}

Resources