An example from actix-web is as follows:
use actix_web::{web, App, Responder, HttpServer};
async fn index() -> impl Responder {
"Hello world!"
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new().service(
web::scope("/app").route("/index.html", web::get().to(index)),
)
})
.bind("127.0.0.1:8088")?
.run()
.await
}
My question is around how the statement to(index)
works in Rust.
Looking at the source code for to
we see:
pub fn to<F, T, R, U>(mut self, handler: F) -> Self
where
F: Factory<T, R, U>,
// --- snip
Where Factory
is defined as:
pub trait Factory<T, R, O>: Clone + 'static
where
R: Future<Output = O>,
O: Responder,
{
fn call(&self, param: T) -> R;
}
What is the mechanism by which the function async fn index() -> impl Responder
gets converted to Factory<T, R, O>
?
The Into trait is simply the reciprocal of the From trait. That is, if you have implemented the From trait for your type, Into will call it when necessary.
Implementing Into for conversions to external types in old versions of Rust. It is important to understand that Into does not provide a From implementation (as From does with Into ). Therefore, you should always try to implement From and then fall back to Into if From can't be implemented.
There is an implementation of the trait just after your snippet:
impl<F, R, O> Factory<(), R, O> for F
where
F: Fn() -> R + Clone + 'static,
R: Future<Output = O>,
O: Responder,
{
fn call(&self, _: ()) -> R {
(self)()
}
}
This can be read as: if a type F
implements Fn() -> Future<Output = impl Responder> + ...
then it also implements Factory<(), _, _>
.
And an async fn
is syntactic sugar for a function which returns a Future
of some sort (and can use .await
internally), so async fn index() -> impl Responder
implements Fn() -> impl Future<Output = impl Responder>
so it also implements Factory<(), _, _>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With