diff --git a/core/codegen/src/attribute/route/mod.rs b/core/codegen/src/attribute/route/mod.rs index 5084e963..a24a2c43 100644 --- a/core/codegen/src/attribute/route/mod.rs +++ b/core/codegen/src/attribute/route/mod.rs @@ -1,5 +1,7 @@ mod parse; +use std::hash::Hash; + use proc_macro2::{TokenStream, Span}; use devise::{Spanned, SpanWrapped, Result, FromMeta, Diagnostic}; use devise::ext::TypeExt as _; @@ -8,9 +10,9 @@ use crate::{proc_macro2, syn}; use crate::proc_macro_ext::StringLit; use crate::syn_ext::{IdentExt, TypeExt as _}; use crate::http_codegen::{Method, Optional}; - use crate::attribute::param::Guard; -use parse::{Route, Attribute, MethodAttribute}; + +use self::parse::{Route, Attribute, MethodAttribute}; impl Route { pub fn guards(&self) -> impl Iterator { @@ -193,30 +195,20 @@ fn data_guard_decl(guard: &Guard) -> TokenStream { } fn internal_uri_macro_decl(route: &Route) -> TokenStream { - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - - // Keep a global counter (+ thread ID later) to generate unique ids. - static COUNTER: AtomicUsize = AtomicUsize::new(0); - // FIXME: Is this the right order? Does order matter? let uri_args = route.param_guards() .chain(route.query_guards()) .map(|guard| (&guard.fn_ident, &guard.ty)) .map(|(ident, ty)| quote!(#ident: #ty)); - // Generate entropy based on the route's metadata. - let mut hasher = DefaultHasher::new(); - route.handler.sig.ident.hash(&mut hasher); - route.attr.uri.path().hash(&mut hasher); - route.attr.uri.query().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); - + // Generate a unique macro name based on the route's metadata. let macro_name = route.handler.sig.ident.prepend(crate::URI_MACRO_PREFIX); - let inner_macro_name = macro_name.append(&hasher.finish().to_string()); + let inner_macro_name = macro_name.uniqueify_with(|mut hasher| { + route.handler.sig.ident.hash(&mut hasher); + route.attr.uri.path().hash(&mut hasher); + route.attr.uri.query().hash(&mut hasher) + }); + let route_uri = route.attr.uri.to_string(); quote_spanned! { Span::call_site() => diff --git a/core/codegen/src/syn_ext.rs b/core/codegen/src/syn_ext.rs index 27b81cde..5e700cd2 100644 --- a/core/codegen/src/syn_ext.rs +++ b/core/codegen/src/syn_ext.rs @@ -1,6 +1,7 @@ //! Extensions to `syn` types. use std::ops::Deref; +use std::hash::{Hash, Hasher}; use crate::syn::{self, Ident, ext::IdentExt as _, visit::Visit}; use crate::proc_macro2::Span; @@ -10,6 +11,7 @@ pub trait IdentExt { fn append(&self, string: &str) -> syn::Ident; fn with_span(self, span: Span) -> syn::Ident; fn rocketized(&self) -> syn::Ident; + fn uniqueify_with(&self, f: F) -> syn::Ident; } pub trait ReturnTypeExt { @@ -61,6 +63,23 @@ impl IdentExt for syn::Ident { fn rocketized(&self) -> syn::Ident { self.prepend(crate::ROCKET_IDENT_PREFIX) } + + fn uniqueify_with(&self, mut f: F) -> syn::Ident { + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::collections::hash_map::DefaultHasher; + + // Keep a global counter (+ thread ID later) to generate unique ids. + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut hasher = DefaultHasher::new(); + self.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); + f(&mut hasher); + + self.append(&format!("_{}", hasher.finish())) + } } impl ReturnTypeExt for syn::ReturnType {