diff --git a/core/codegen/src/attribute/route/mod.rs b/core/codegen/src/attribute/route/mod.rs index a24a2c4326..5f46bc6d3e 100644 --- a/core/codegen/src/attribute/route/mod.rs +++ b/core/codegen/src/attribute/route/mod.rs @@ -319,6 +319,13 @@ fn codegen_route(route: Route) -> Result { let rank = Optional(route.attr.rank); let format = Optional(route.attr.format.as_ref()); + // Get the doc comment + let doc_comment = route + .doc_comment + .as_ref() + .map(|dc| quote! { Some(#dc.to_string()) }) + .unwrap_or_else(|| quote! { None }); + Ok(quote! { #handler_fn @@ -353,6 +360,7 @@ fn codegen_route(route: Route) -> Result { format: #format, rank: #rank, sentinels: #sentinels, + doc_comment: #doc_comment, } } diff --git a/core/codegen/src/attribute/route/parse.rs b/core/codegen/src/attribute/route/parse.rs index 0c83c26170..32f38c5501 100644 --- a/core/codegen/src/attribute/route/parse.rs +++ b/core/codegen/src/attribute/route/parse.rs @@ -1,6 +1,7 @@ use devise::{syn, Spanned, SpanWrapped, Result, FromMeta}; use devise::ext::{SpanDiagnosticExt, TypeExt}; use indexmap::{IndexSet, IndexMap}; +use syn::{Lit::Str, Meta::NameValue, MetaNameValue}; use crate::proc_macro_ext::Diagnostics; use crate::http_codegen::{Method, MediaType}; @@ -29,6 +30,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 doc_comment: Option } type ArgumentMap = IndexMap; @@ -209,9 +212,23 @@ impl Route { }) .collect(); + let doc_comment = handler + .attrs + .iter() + .filter(|a| a.path.is_ident("doc")) + .filter_map(|attr| attr.parse_meta().ok()) + .filter_map(|meta| if let NameValue(MetaNameValue { lit: Str(string), .. }) = meta { + Some(string.value()) + } else { + None + }) + .flat_map(|string| string.split('\n').map(|s| s.trim().to_owned()).collect::>()) + .fold(String::new(), |acc, elem| acc + &elem + "\n"); + let doc_comment = (!doc_comment.is_empty()).then(|| doc_comment); + diags.head_err_or(Route { attr, path_params, query_params, data_guard, request_guards, - handler, arguments, + handler, arguments, doc_comment }) } } diff --git a/core/lib/src/doc/mod.rs b/core/lib/src/doc/mod.rs new file mode 100644 index 0000000000..414b85ebab --- /dev/null +++ b/core/lib/src/doc/mod.rs @@ -0,0 +1,41 @@ +//! Traits and structs related to automagically generating documentation for your Rocket routes + +use std::marker::PhantomData; + +#[derive(Default)] +pub struct Docs { + title: Option, + description: Option, + content_type: Option, +} + +pub struct Resolve(PhantomData); + +pub trait Documented { + fn docs() -> Docs; +} + +trait Undocumented { + fn docs() -> Docs { + Docs::default() + } +} + +impl Undocumented for T { } + +impl Resolve { + pub const DOCUMENTED: bool = true; + + pub fn docs() -> Docs { + T::docs() + } +} + +// impl Documented for Json { +// fn docs() -> Docs { +// Docs { +// content_type: Some("application/json".to_string()), +// ..Self::docs() +// } +// } +// } diff --git a/core/lib/src/lib.rs b/core/lib/src/lib.rs index cf64ecf8e3..c62f49aef9 100644 --- a/core/lib/src/lib.rs +++ b/core/lib/src/lib.rs @@ -124,6 +124,7 @@ pub mod fairing; pub mod error; pub mod catcher; pub mod route; +pub mod doc; // Reexport of HTTP everything. pub mod http { diff --git a/core/lib/src/route/route.rs b/core/lib/src/route/route.rs index 618d5d1b2a..96ff53adc2 100644 --- a/core/lib/src/route/route.rs +++ b/core/lib/src/route/route.rs @@ -190,6 +190,8 @@ pub struct Route { pub format: Option, /// The discovered sentinels. pub(crate) sentinels: Vec, + /// The doc comment associated with this route. + pub(crate) doc_comment: Option, } impl Route { @@ -253,6 +255,7 @@ impl Route { sentinels: Vec::new(), handler: Box::new(handler), rank, uri, method, + doc_comment: None, } } @@ -345,6 +348,9 @@ pub struct StaticInfo { /// Route-derived sentinels, if any. /// This isn't `&'static [SentryInfo]` because `type_name()` isn't `const`. pub sentinels: Vec, + /// The doc comment associated with this route. + pub doc_comment: Option, + } #[doc(hidden)] @@ -361,6 +367,7 @@ impl From for Route { format: info.format, sentinels: info.sentinels.into_iter().collect(), uri, + doc_comment: info.doc_comment, } } }