I have an asynchronous responder impl, but something is wrong with the lifetime of the objects. The code:
#[rocket::async_trait]
impl<'r> Responder<'r, 'static> for LoginUser {
async fn respond_to(self, _: &'r Request) -> response::Result<'static> {
use LicensesStatus::*;
let status = self.check_licenses().await;
let json = serde_json::json!({"status": format!("{:?}", status)}).to_string();
let response = Response::build()
.sized_body(json.len(), Cursor::new(&json))
.header(ContentType::JSON);
match status {
Valid => response.ok(),
_ => response.status(Status::Conflict).ok()
}
}
}
Compilation error:
error[E0195]: lifetime parameters or bounds on method `respond_to` do not match the trait declaration
--> src/views/login.rs:64:14
|
64 | async fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
The Responder trait and its respond_to method are not async, so your implementation will not match the trait. You'll need to rethink your object such that the LoginUser already knows the license status, or move this logic into the handler itself.
Related
I have a trait Serializer:
trait Serializer {
fn serialize(&self, data: Rc<()>) -> Result<(), Error>;
}
And some Foo which implements it. Notably, data is not Send.
The actual implementation requires an async context to execute, so I've split the creation of an async runtime away from the actual implementation, like so:
struct Foo {}
impl Foo {
async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
unimplemented!();
}
}
impl Serializer for Foo {
fn serialize(&self, data: Rc<()>) -> Result<(), Error> {
let runtime = Builder::new_current_thread().enable_all().build().unwrap();
runtime.block_on(async move { self.async_serialize(data).await })
}
}
This compiles and works how I would expect.
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=04171e7fb65a9e158903978fd19ef8ac
If I refactor the code such that the async Runtime creation is done by way of a trait:
#[async_trait]
trait AsyncSerializer {
async fn async_serialize(&self, data: Rc<()>) -> Result<(), Error>;
}
#[async_trait]
impl AsyncSerializer for Foo {
async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
unimplemented!();
}
}
This does not compile, now complaining that Rc<()> isn't Send:
error: future cannot be sent between threads safely
--> src/main.rs:19:73
|
19 | async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
| _________________________________________________________________________^
20 | | unimplemented!();
21 | | }
| |_____^ future created by async block is not `Send`
|
= help: within `impl Future<Output = Result<(), anyhow::Error>>`, the trait `Send` is not implemented for `Rc<()>`
note: captured value is not `Send`
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=23f61162b5be8384092888635d8daacc
This error message makes sense to me, Rc is not Send, but:
Why was this not a problem before? The prior implementations (impl on Foo versus impl AsyncSerializer for Foo) look analogous to me.
Can I wrap data in some way to avoid this?
The way that #[async_trait] de-sugars your code requires your futures to be send, as explained here. To fix that change the attribute macro to be #[async_trait(?Send)].
I need to implement a trait that is returning the futures::StreamExt trait.
In general this sounds easy and there are several answers to this e.g. this here.
I tried this with StreamExt but this does - for some reason - not work. Here my sample code:
// [dependencies]
// futures = "0.3.6"
// async-std = { version = "1.6.5", features = ["attributes", "unstable"] } // interval function is unstable atm.
use std::time::Duration;
use futures::StreamExt;
trait StreamProvidingTrait {
fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
}
struct StreamProvider {}
impl StreamProvidingTrait for StreamProvider {
fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
return Box::new(async_std::stream::interval(Duration::from_millis(1000)).map(|_| 1));
}
}
#[async_std::main]
async fn main() {
let mut counter = 0;
let object = StreamProvider {};
// creates a stream
let worx = object.returnastream();
// mappes the stream into something....
let mut mapped_stream = worx.map(|_| {
counter = counter + 1;
counter
});
// subscribing to the items
while let item = mapped_stream.next().await {
match item {
Some(value) => println!("{}", value),
_ => {}
}
}
}
And here the error:
Compiling traittest v0.1.0 (/Users/andre/repos/traittest)
warning: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:1326:8
|
1326 | fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
| ^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `poll_next_unpin` references the `Self` type in its `where` clause
|
= note: `#[warn(where_clauses_object_safety)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> src/main.rs:6:36
|
6 | fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
|
::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
|
226 | fn next(&mut self) -> Next<'_, Self>
| ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
...
976 | fn by_ref(&mut self) -> &mut Self {
| ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
...
1381 | fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
| ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type
error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> src/main.rs:12:36
|
12 | fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
|
::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
|
226 | fn next(&mut self) -> Next<'_, Self>
| ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
...
976 | fn by_ref(&mut self) -> &mut Self {
| ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
...
1381 | fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
| ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0038`.
error: could not compile `traittest`.
To learn more, run the command again with --verbose.
Process finished with exit code 101
When I exchange the StreamExt trait with my own one, this code works perfectly.
trait SomeTrait {
fn returnatrait(self: &Self) -> Box<dyn SomeOtherTrait>;
}
trait SomeOtherTrait {
fn sayHelloWorld(&self);
}
struct DummyStruct {}
impl SomeOtherTrait for DummyStruct {
fn sayHelloWorld(&self) {
println!("hello world");
}
}
struct Implementation {}
impl SomeTrait for Implementation {
fn returnatrait(self: &Self) -> Box<dyn SomeOtherTrait> {
return Box::new(DummyStruct{});
}
}
fn main() {
let implementation = Implementation{};
let worx = implementation.returnatrait();
worx.sayHelloWorld();
}
What's wrong here? There's obviously something I don't understand. Please help me understand this!
A function returning a trait can use the impl Trait syntax to return an opaque type that implements the trait. A trait method returning a trait currently doesn't support this feature and requires the trait to be returned as a trait object - a dynamically dispatched reference or smart pointer such as Box or Rc. Not all traits are object-safe, though, and the bad news is that StreamExt is among those that aren't, for reasons pointed out by the compiler, such as referencing Self in method return types and where clauses.
The good news, however, is that this is not a problem: StreamExt is an extension trait, one that provides a blanket implementation for all types that implement Stream. So you don't need to bother returning a dyn StreamExt trait object, you can return a dyn Stream one, and you'll still get access to StreamExt methods simply by requesting them with use StreamExt. In other words, you can just replace Box<dyn StreamExt> with Box<dyn Stream> in the return type of your trait.
Another issue you might encounter is that Box<dyn Stream> doesn't work on methods that need to move the stream, which includes many methods provided by StreamExt. Those will require the stream to be pinned, which can be fixed by returning Pin<Box<dyn Stream>> instead of Box<dyn Stream>. There is even a boxed() method on StreamExt that pins and boxes the stream in one operation; code that uses it would look like this (playground):
use futures::stream::{Stream, StreamExt};
use std::pin::Pin;
trait StreamProvidingTrait {
fn returnastream(&self) -> Pin<Box<dyn Stream<Item = i32>>>;
}
struct StreamProvider {}
impl StreamProvidingTrait for StreamProvider {
fn returnastream(&self) -> Pin<Box<dyn Stream<Item = i32>>> {
return tokio::stream::once(0).boxed();
}
}
fn main() {
let provider = StreamProvider {};
let stream = provider.returnastream();
let _fut = stream.into_future();
}
I have this piece of code using futures v0.1:
impl ArcService for (Box<MiddleWare<Request>>, Box<ArcService>) {
fn call(&self, req: Request, res: Response) -> Box<Future<Item = Response, Error = Error>> {
box self.0.call(req).and_then(move |req| self.1.call(req, res))
}
}
pub trait ArcService: Send + Sync {
fn call(&self, req: Request, res: Response) -> Box<Future<Item = Response, Error = Error>>;
}
pub trait MiddleWare<T>: Sync + Send {
fn call<'a>(&'a self, param: T) -> Box<Future<Item = T, Error = Error> + 'a>;
}
type MiddleWareFuture<'a, I> = Box<Future<Item = I, Error = Error> + 'a>;
impl MiddleWare<Request> for Vec<Box<MiddleWare<Request>>> {
fn call(&self, request: Request) -> MiddleWareFuture<Request> {
self.iter()
.fold(box Ok(request).into_future(), |request, middleware| {
box request.and_then(move |req| middleware.call(req))
})
}
}
pub struct ArcRouter {
routes: HashMap<Method, Box<ArcService>>,
}
// Service implementation
impl hyper::Server::Service for ArcRouter {
type Response = Response;
type Request = Request;
type Error = hyper::Error;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn call(&self, req: Request) -> Box<Future<Item = Self::Response, Error = Self::Error>> {
if let Some(routeMatch) = self.matchRoute(req.path(), req.method()) {
let mut request: ArcRequest = req.into();
request.paramsMap.insert(routeMatch.params);
let response = routeMatch.handler //handler is ArcService
.call(request, ArcResponse::new())
.map(|res| res.into());
return box response;
}
// TODO: this should be handled by a user defined 404 handler
return box Ok(Response::new().with_status(StatusCode::NotFound)).into_future();
}
}
Note the lifetime parameter on Middleware — it is used to avoid lifetime issues.
This does not compile because Box<Future<Item = Response, Error = Error>> is implicitly 'static and therefore causes lifetime issues. hyper::Server::Service requires a 'static Future
Here is an example that aptly describes my problem:
extern crate futures; // v0.1 (old)
use futures::{future, Future};
struct Example {
age: i32,
}
// trait is defined in an external crate. You can't change it's definition
trait MakeFuture {
fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>>;
}
impl MakeFuture for Example {
fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>> {
let f = future::ok(self).map(|ex| ex.age + 1);
Box::new(f)
}
}
playground link
which gives the lifetime error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:16:28
|
16 | let f = future::ok(self).map(|ex| ex.age + 1);
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 15:5...
--> src/main.rs:15:5
|
15 | / fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>> {
16 | | let f = future::ok(self).map(|ex| ex.age + 1);
17 | | Box::new(f)
18 | | }
| |_____^
note: ...so that expression is assignable (expected &Example, found &Example)
--> src/main.rs:16:28
|
16 | let f = future::ok(self).map(|ex| ex.age + 1);
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Item=i32, Error=()> + 'static>, found std::boxed::Box<futures::Future<Item=i32, Error=()>>)
--> src/main.rs:17:9
|
17 | Box::new(f)
| ^^^^^^^^^^^
Is there a way to get around this? I'm building with hyper::Service and using Rust v1.25.0 (nightly)
How to return a future combinator with &self
You return a future that refers to self like this:
use futures::future::{self, FutureResult}; // 0.1.28
struct Example {
age: i32,
}
impl Example {
fn make_a_future(&self) -> FutureResult<&Example, ()> {
future::ok(self)
}
}
As discussed in the Tokio documentation on returning futures, the easiest stable solution to returning a complicated future is a impl Trait. Note that we assign an explicit lifetime to self and use that in the returned value (via + 'a):
use futures::{future, Future}; // 0.1.28
struct Example {
age: i32,
}
impl Example {
fn make_a_future<'a>(&'a self) -> impl Future<Item = i32, Error = ()> + 'a {
future::ok(self).map(|ex| ex.age + 1)
}
}
Your real question is "how can I lie to the compiler and attempt to introduce memory unsafety into my program?"
Box<SomeTrait + 'static> (or Box<SomeTrait> by itself) means that the trait object must not contain any references that do not last for the entire program. By definition, your Example struct has a shorter lifetime than that.
This has nothing to do with futures. This is a fundamental Rust concept.
There are many questions that ask the same thing in regards to threads, which have similar restrictions. A small sampling:
Lifetime of variables passed to a new thread
How do I use static lifetimes with threads?
The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
Lifetime troubles sharing references between threads
Like in those cases, you are attempting to share a reference to a variable with something that may exist after the variable is destroyed. Languages such as C or C++ would let you do this, only to have your program crash at a seemingly random point in time in the future when that variable is accessed after being freed. The crash is the good case, by the way; information leaks or code execution is also possible.
Like the case for threads, you have to ensure that this doesn't happen. The easiest way is to move the variable into the future, not sharing it at all. Another option is to use something like an Arc around your variable, clone the Arc and hand the clone to the future.
std::result::Result implements IntoFuture, but the following code doesn't compile:
extern crate futures; // 0.1.25
use futures::{future::Either, prelude::*, sync::mpsc};
fn example() -> impl Future<Item = (), Error = ()> {
let (tx, rx) = mpsc::channel(0);
let data = Some(1);
match data {
Some(d) => Either::A(tx.send(d).and_then(|x| Ok(())).map_err(|e| ())),
None => Either::B(Ok(()) as Result<(), ()>),
}
}
Full error message:
error[E0277]: the trait bound `std::result::Result<(), ()>: futures::Future` is not satisfied
--> src/lib.rs:5:17
|
5 | fn example() -> impl Future<Item = (), Error = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures::Future` is not implemented for `std::result::Result<(), ()>`
|
= note: required because of the requirements on the impl of `futures::Future` for `futures::future::Either<futures::MapErr<futures::AndThen<futures::sink::Send<futures::sync::mpsc::Sender<{integer}>>, std::result::Result<(), futures::sync::mpsc::SendError<{integer}>>, [closure#src/lib.rs:9:50: 9:60]>, [closure#src/lib.rs:9:70: 9:76]>, std::result::Result<(), ()>>`
= note: the return type of a function must have a statically known size
Moreover, IntoFuture doesn't require Sized. Why can't Result<(), ()> be treated as a Future here?
Either only implements Future when both of its children implement Future and their types line up:
impl<A, B> Future for Either<A, B>
where
A: Future,
B: Future<Item = A::Item, Error = A::Error>,
Result does not implement Future, so placing a Result directly inside of an Either will not implement Future either.
The IntoFuture trait is orthogonal to Future. As its documentation states:
This trait is very similar to the IntoIterator trait and is intended to be used in a very similar fashion.
You can't call Iterator::map on a Vec (vec![1, 2, 3].map(...)), even though Vec implements IntoIterator, and the same logic applies to Result / Future / IntoFuture.
Most of the time, you will want to use futures::ok:
extern crate futures; // 0.1.25
use futures::{
future::{self, Either},
prelude::*,
sync::mpsc,
};
fn example() -> impl Future<Item = (), Error = ()> {
let (tx, _) = mpsc::channel(0);
let data = Some(1);
match data {
Some(d) => Either::A(tx.send(d).map(|_| ()).map_err(|_| ())),
None => Either::B(future::ok(())),
}
}
You could also choose to call into_future directly:
Either::B(Ok(()).into_future())
I have this piece of code using futures v0.1:
impl ArcService for (Box<MiddleWare<Request>>, Box<ArcService>) {
fn call(&self, req: Request, res: Response) -> Box<Future<Item = Response, Error = Error>> {
box self.0.call(req).and_then(move |req| self.1.call(req, res))
}
}
pub trait ArcService: Send + Sync {
fn call(&self, req: Request, res: Response) -> Box<Future<Item = Response, Error = Error>>;
}
pub trait MiddleWare<T>: Sync + Send {
fn call<'a>(&'a self, param: T) -> Box<Future<Item = T, Error = Error> + 'a>;
}
type MiddleWareFuture<'a, I> = Box<Future<Item = I, Error = Error> + 'a>;
impl MiddleWare<Request> for Vec<Box<MiddleWare<Request>>> {
fn call(&self, request: Request) -> MiddleWareFuture<Request> {
self.iter()
.fold(box Ok(request).into_future(), |request, middleware| {
box request.and_then(move |req| middleware.call(req))
})
}
}
pub struct ArcRouter {
routes: HashMap<Method, Box<ArcService>>,
}
// Service implementation
impl hyper::Server::Service for ArcRouter {
type Response = Response;
type Request = Request;
type Error = hyper::Error;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn call(&self, req: Request) -> Box<Future<Item = Self::Response, Error = Self::Error>> {
if let Some(routeMatch) = self.matchRoute(req.path(), req.method()) {
let mut request: ArcRequest = req.into();
request.paramsMap.insert(routeMatch.params);
let response = routeMatch.handler //handler is ArcService
.call(request, ArcResponse::new())
.map(|res| res.into());
return box response;
}
// TODO: this should be handled by a user defined 404 handler
return box Ok(Response::new().with_status(StatusCode::NotFound)).into_future();
}
}
Note the lifetime parameter on Middleware — it is used to avoid lifetime issues.
This does not compile because Box<Future<Item = Response, Error = Error>> is implicitly 'static and therefore causes lifetime issues. hyper::Server::Service requires a 'static Future
Here is an example that aptly describes my problem:
extern crate futures; // v0.1 (old)
use futures::{future, Future};
struct Example {
age: i32,
}
// trait is defined in an external crate. You can't change it's definition
trait MakeFuture {
fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>>;
}
impl MakeFuture for Example {
fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>> {
let f = future::ok(self).map(|ex| ex.age + 1);
Box::new(f)
}
}
playground link
which gives the lifetime error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:16:28
|
16 | let f = future::ok(self).map(|ex| ex.age + 1);
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 15:5...
--> src/main.rs:15:5
|
15 | / fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>> {
16 | | let f = future::ok(self).map(|ex| ex.age + 1);
17 | | Box::new(f)
18 | | }
| |_____^
note: ...so that expression is assignable (expected &Example, found &Example)
--> src/main.rs:16:28
|
16 | let f = future::ok(self).map(|ex| ex.age + 1);
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Item=i32, Error=()> + 'static>, found std::boxed::Box<futures::Future<Item=i32, Error=()>>)
--> src/main.rs:17:9
|
17 | Box::new(f)
| ^^^^^^^^^^^
Is there a way to get around this? I'm building with hyper::Service and using Rust v1.25.0 (nightly)
How to return a future combinator with &self
You return a future that refers to self like this:
use futures::future::{self, FutureResult}; // 0.1.28
struct Example {
age: i32,
}
impl Example {
fn make_a_future(&self) -> FutureResult<&Example, ()> {
future::ok(self)
}
}
As discussed in the Tokio documentation on returning futures, the easiest stable solution to returning a complicated future is a impl Trait. Note that we assign an explicit lifetime to self and use that in the returned value (via + 'a):
use futures::{future, Future}; // 0.1.28
struct Example {
age: i32,
}
impl Example {
fn make_a_future<'a>(&'a self) -> impl Future<Item = i32, Error = ()> + 'a {
future::ok(self).map(|ex| ex.age + 1)
}
}
Your real question is "how can I lie to the compiler and attempt to introduce memory unsafety into my program?"
Box<SomeTrait + 'static> (or Box<SomeTrait> by itself) means that the trait object must not contain any references that do not last for the entire program. By definition, your Example struct has a shorter lifetime than that.
This has nothing to do with futures. This is a fundamental Rust concept.
There are many questions that ask the same thing in regards to threads, which have similar restrictions. A small sampling:
Lifetime of variables passed to a new thread
How do I use static lifetimes with threads?
The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
Lifetime troubles sharing references between threads
Like in those cases, you are attempting to share a reference to a variable with something that may exist after the variable is destroyed. Languages such as C or C++ would let you do this, only to have your program crash at a seemingly random point in time in the future when that variable is accessed after being freed. The crash is the good case, by the way; information leaks or code execution is also possible.
Like the case for threads, you have to ensure that this doesn't happen. The easiest way is to move the variable into the future, not sharing it at all. Another option is to use something like an Arc around your variable, clone the Arc and hand the clone to the future.