Generate 'uri!' macro names independently of span.

Prior to this commit, codegen used 'Span' information to generate a
unique id for a given route. This commit changes the id generation to
instead use 1) the route's name and path, 2) a an per-generation
atomically increasing ID, and 3) the ids of the process/thread the
proc-macro is running in. Together, these values should provide a unique
id for a given route, even in the face of the reused processes and
threads, while also removing the dependence on unstable Span features.

Fixes #1373.
This commit is contained in:
Sergio Benitez 2020-07-14 00:44:59 -07:00
parent 816b8c44ab
commit dfca18d307
2 changed files with 26 additions and 9 deletions

View File

@ -1,3 +1,4 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
@ -38,9 +39,9 @@ struct MethodRouteAttribute {
/// This structure represents the parsed `route` attribute and associated items.
#[derive(Debug)]
struct Route {
/// The status associated with the code in the `#[route(code)]` attribute.
/// The attribute: `#[get(path, ...)]`.
attribute: RouteAttribute,
/// The function that was decorated with the `route` attribute.
/// The function the attribute decorated, i.e, the handler.
function: syn::ItemFn,
/// The non-static parameters declared in the route segments.
segments: IndexSet<Segment>,
@ -322,6 +323,9 @@ fn request_guard_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
}
fn generate_internal_uri_macro(route: &Route) -> TokenStream2 {
// Keep a global counter (+ thread ID later) to generate unique ids.
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let dynamic_args = route.segments.iter()
.filter(|seg| seg.source == Source::Path || seg.source == Source::Query)
.filter(|seg| seg.kind != Kind::Static)
@ -330,14 +334,13 @@ fn generate_internal_uri_macro(route: &Route) -> TokenStream2 {
.map(|(ident, _, ty)| quote!(#ident: #ty));
let mut hasher = DefaultHasher::new();
let route_span = route.function.span();
route_span.source_file().path().hash(&mut hasher);
let line_column = route_span.start();
line_column.line.hash(&mut hasher);
line_column.column.hash(&mut hasher);
route.function.sig.ident.hash(&mut hasher);
route.attribute.path.origin.0.path().hash(&mut hasher);
std::process::id().hash(&mut hasher);
std::thread::current().id().hash(&mut hasher);
COUNTER.fetch_add(1, Ordering::AcqRel).hash(&mut hasher);
let mut generated_macro_name = route.function.sig.ident.prepend(URI_MACRO_PREFIX);
generated_macro_name.set_span(Span::call_site().into());
let generated_macro_name = route.function.sig.ident.prepend(URI_MACRO_PREFIX);
let inner_generated_macro_name = generated_macro_name.append(&hasher.finish().to_string());
let route_uri = route.attribute.path.origin.0.to_string();

View File

@ -0,0 +1,14 @@
#![allow(dead_code)] // This test is only here to ensure it compiles.
#![allow(unused_variables)] // This test is only here to ensure it compiles.
mod a {
/// Docs.
#[rocket::post("/typed_uris/<id>")]
fn simple(id: i32) { }
}
mod b {
/// Docs.
#[rocket::post("/typed_uris/<id>")]
fn simple(id: i32) { }
}