Skip to content

Commit 1f2729d

Browse files
committed
implement auto-documenting routes
1 parent fe23eae commit 1f2729d

File tree

7 files changed

+444
-2
lines changed

7 files changed

+444
-2
lines changed

core/codegen/src/attribute/route/mod.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,38 @@ fn sentinels_expr(route: &Route) -> TokenStream {
296296
quote!(::std::vec![#(#sentinel),*])
297297
}
298298

299+
fn schemas_expr(route: &Route) -> TokenStream {
300+
let ret_ty = match route.handler.sig.output {
301+
syn::ReturnType::Default => None,
302+
syn::ReturnType::Type(_, ref ty) => Some(ty.with_stripped_lifetimes())
303+
};
304+
305+
let generic_idents: Vec<_> = route.handler.sig.generics
306+
.type_params()
307+
.map(|p| &p.ident)
308+
.collect();
309+
310+
let eligible_types = route.guards()
311+
.map(|guard| &guard.ty)
312+
.chain(ret_ty.as_ref().into_iter())
313+
.flat_map(|ty| ty.unfold())
314+
.filter(|ty| ty.is_concrete(&generic_idents))
315+
.map(|child| (child.parent, child.ty));
316+
317+
let sentinel = eligible_types.map(|(parent, ty)| {
318+
define_spanned_export!(ty.span() => _doc);
319+
320+
match parent {
321+
Some(p) if p.is_concrete(&generic_idents) => {
322+
quote_spanned!(ty.span() => #_doc::resolve_doc!(#ty))
323+
}
324+
Some(_) | None => quote_spanned!(ty.span() => #_doc::resolve_doc!(#ty)),
325+
}
326+
});
327+
328+
quote!(::std::vec![#(#sentinel),*])
329+
}
330+
299331
fn codegen_route(route: Route) -> Result<TokenStream> {
300332
use crate::exports::*;
301333

@@ -305,8 +337,9 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
305337
let query_guards = query_decls(&route);
306338
let data_guard = route.data_guard.as_ref().map(data_guard_decl);
307339

308-
// Extract the sentinels from the route.
340+
// Extract the sentinels and schemas from the route.
309341
let sentinels = sentinels_expr(&route);
342+
let schemas = schemas_expr(&route);
310343

311344
// Gather info about the function.
312345
let (vis, handler_fn) = (&route.handler.vis, &route.handler);
@@ -319,6 +352,9 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
319352
let rank = Optional(route.attr.rank);
320353
let format = Optional(route.attr.format.as_ref());
321354

355+
// Get the doc comment
356+
let docstring = &route.docstring;
357+
322358
Ok(quote! {
323359
#handler_fn
324360

@@ -353,6 +389,8 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
353389
format: #format,
354390
rank: #rank,
355391
sentinels: #sentinels,
392+
schemas: #schemas,
393+
docstring: #docstring,
356394
}
357395
}
358396

core/codegen/src/attribute/route/parse.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub struct Route {
2929
pub handler: syn::ItemFn,
3030
/// The parsed arguments to the user's function.
3131
pub arguments: Arguments,
32+
/// The doc comment describing this route
33+
pub docstring: String,
3234
}
3335

3436
type ArgumentMap = IndexMap<Name, (syn::Ident, syn::Type)>;
@@ -209,9 +211,11 @@ impl Route {
209211
})
210212
.collect();
211213

214+
let docstring = String::from_attrs("doc", &handler.attrs)?.join("\n");
215+
212216
diags.head_err_or(Route {
213217
attr, path_params, query_params, data_guard, request_guards,
214-
handler, arguments,
218+
handler, arguments, docstring
215219
})
216220
}
217221
}

core/codegen/src/exports.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ define_exported_paths! {
7272
_route => ::rocket::route,
7373
_catcher => ::rocket::catcher,
7474
_sentinel => ::rocket::sentinel,
75+
_doc => ::rocket::doc,
7576
_log => ::rocket::log,
7677
_form => ::rocket::form::prelude,
7778
_http => ::rocket::http,

0 commit comments

Comments
 (0)