Skip to content

Commit

Permalink
implement auto-documenting routes
Browse files Browse the repository at this point in the history
  • Loading branch information
ThouCheese committed May 24, 2021
1 parent fe23eae commit 1f2729d
Show file tree
Hide file tree
Showing 7 changed files with 444 additions and 2 deletions.
40 changes: 39 additions & 1 deletion core/codegen/src/attribute/route/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,38 @@ fn sentinels_expr(route: &Route) -> TokenStream {
quote!(::std::vec![#(#sentinel),*])
}

fn schemas_expr(route: &Route) -> TokenStream {
let ret_ty = match route.handler.sig.output {
syn::ReturnType::Default => None,
syn::ReturnType::Type(_, ref ty) => Some(ty.with_stripped_lifetimes())
};

let generic_idents: Vec<_> = route.handler.sig.generics
.type_params()
.map(|p| &p.ident)
.collect();

let eligible_types = route.guards()
.map(|guard| &guard.ty)
.chain(ret_ty.as_ref().into_iter())
.flat_map(|ty| ty.unfold())
.filter(|ty| ty.is_concrete(&generic_idents))
.map(|child| (child.parent, child.ty));

let sentinel = eligible_types.map(|(parent, ty)| {
define_spanned_export!(ty.span() => _doc);

match parent {
Some(p) if p.is_concrete(&generic_idents) => {
quote_spanned!(ty.span() => #_doc::resolve_doc!(#ty))
}
Some(_) | None => quote_spanned!(ty.span() => #_doc::resolve_doc!(#ty)),
}
});

quote!(::std::vec![#(#sentinel),*])
}

fn codegen_route(route: Route) -> Result<TokenStream> {
use crate::exports::*;

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

// Extract the sentinels from the route.
// Extract the sentinels and schemas from the route.
let sentinels = sentinels_expr(&route);
let schemas = schemas_expr(&route);

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

// Get the doc comment
let docstring = &route.docstring;

Ok(quote! {
#handler_fn

Expand Down Expand Up @@ -353,6 +389,8 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
format: #format,
rank: #rank,
sentinels: #sentinels,
schemas: #schemas,
docstring: #docstring,
}
}

Expand Down
6 changes: 5 additions & 1 deletion core/codegen/src/attribute/route/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub struct Route {
pub handler: syn::ItemFn,
/// The parsed arguments to the user's function.
pub arguments: Arguments,
/// The doc comment describing this route
pub docstring: String,
}

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

let docstring = String::from_attrs("doc", &handler.attrs)?.join("\n");

diags.head_err_or(Route {
attr, path_params, query_params, data_guard, request_guards,
handler, arguments,
handler, arguments, docstring
})
}
}
Expand Down
1 change: 1 addition & 0 deletions core/codegen/src/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ define_exported_paths! {
_route => ::rocket::route,
_catcher => ::rocket::catcher,
_sentinel => ::rocket::sentinel,
_doc => ::rocket::doc,
_log => ::rocket::log,
_form => ::rocket::form::prelude,
_http => ::rocket::http,
Expand Down
Loading

0 comments on commit 1f2729d

Please sign in to comment.