Description
Some thing like @decorator
in python or #[derive()]
for fn
struct User { /* ... */ }
impl FromRequest for User {
// ...
}
#[decorate(HttpHandler)]
#[http(get("/"))]
fn index(user: User) -> String {
format!("hello, {}", user.name)
}
#[decorate(HttpHandler)]
#[http(get("/users/<id>"))]
fn get(user: User, id: String) -> Result<String, Status> {
if user.id != id {
Err(Status::Forbidden)
} else {
Ok(format!("name: {}, last login at: {}", user.name, user.last_login_time))
}
}
fn main() {
HttpServer::new()
.mount("/", vec![index, get])
.launch()
.expect("Failed to start server");
}
For now, this can be done by syntax plugin, but it will far from landing in stable (perhaps never).
See: https://github.com/SergioBenitez/Rocket (the example above is almost same as Rocket's example)
So maybe it can be done via same mechanism as derive
in proc macro:
The codegen crate will receive the signature of fn
and output a new decorated fn
and a inner function name , the inner function name will replace the old one. for example:
#[decorate(HttpHandler)]
#[http(get("/users/<id>"))]
fn get(user: User, id: String) -> Result<String, Status> {
// ...
}
codegen crate will receive
#[http(get("/users/<id>"))]
fn get(user: User, id: String) -> Result<String, Status> {}
and parse (via syn
as current proc macro codegen crates) and produce (via quote
) :
fn get(request: Request) -> Result<Response, Status> {
let user = User::from_request(&request)?;
let params = request.parse_parms("/user/<id>")?;
let id = params.get(1)?;
let body = __http_inner_get(user, id)?;
Ok(Response::build()
.header("Content-Type", "text/plain")
.sized_body(Cursor::new(body))
.ok())
}
and a inner function name for original function: '__http_inner_get'.
And then rustc will replace the original function's name with the given one. This is the only difference with deriving a struct/enum of current proc macro mechanism.
It is like python's decorator:
def require_user(request):
return db.load_user_by_session(request.cookie.get("session"))
@http.get("/users/<id:str>", from_request = [require_user])
def get(user, id):
# do something
return "hello %s" % user.name
The semantic of decorator is: function = decorator(old_function)
If multi decorator is used, then pipe them one by one:
function = decorator1(decorator2(old_function))