mirror of https://github.com/rwf2/Rocket.git
Generate deterministic names for 'uri' macros.
This commit is contained in:
parent
2a1afd12f5
commit
120d1e78da
|
@ -209,9 +209,11 @@ fn internal_uri_macro_decl(route: &Route) -> TokenStream {
|
|||
// 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.uniqueify_with(|mut hasher| {
|
||||
route.handler.sig.ident.hash(&mut hasher);
|
||||
route.attr.method.0.hash(&mut hasher);
|
||||
route.attr.uri.path().hash(&mut hasher);
|
||||
route.attr.uri.query().hash(&mut hasher)
|
||||
route.attr.uri.query().hash(&mut hasher);
|
||||
route.attr.data.as_ref().map(|d| d.value.hash(&mut hasher));
|
||||
route.attr.format.as_ref().map(|f| f.0.hash(&mut hasher));
|
||||
});
|
||||
|
||||
let route_uri = route.attr.uri.to_string();
|
||||
|
|
|
@ -80,18 +80,21 @@ impl IdentExt for syn::Ident {
|
|||
self.prepend(crate::ROCKET_IDENT_PREFIX)
|
||||
}
|
||||
|
||||
/// Create a unqiue version of the ident `self` based on the hash of `self`,
|
||||
/// its span, the current call site, and any additional information provided
|
||||
/// by the closure `f`.
|
||||
///
|
||||
/// Span::source_file() / line / col are not stable, but the byte span and
|
||||
/// some kind of scope identifier do appear in the `Debug` representation
|
||||
/// for `Span`. And they seem to be consistent across compilations: "#57
|
||||
/// bytes(106..117)" at the time of writing. So we use that.
|
||||
fn uniqueify_with<F: FnMut(&mut dyn Hasher)>(&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);
|
||||
format!("{:?}", self.span()).hash(&mut hasher);
|
||||
format!("{:?}", Span::call_site()).hash(&mut hasher);
|
||||
f(&mut hasher);
|
||||
|
||||
self.append(&format!("_{}", hasher.finish()))
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
#[get("/")]
|
||||
fn index() { }
|
||||
|
||||
mod module {
|
||||
// This one has all the same macro inputs, and we need it to
|
||||
// generate a crate-wide unique identifier for the macro it
|
||||
// defines.
|
||||
#[get("/")]
|
||||
pub fn index() { }
|
||||
}
|
||||
|
||||
// Makes sure that the hashing of the proc macro's call site span
|
||||
// is enough, even if we're inside a declarative macro
|
||||
macro_rules! gen_routes {
|
||||
() => {
|
||||
#[get("/")]
|
||||
pub fn index() { }
|
||||
|
||||
pub mod two {
|
||||
#[get("/")]
|
||||
pub fn index() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod module2 {
|
||||
gen_routes!();
|
||||
|
||||
pub mod module3 {
|
||||
gen_routes!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uri_reachability() {
|
||||
use rocket::http::Status;
|
||||
use rocket::local::blocking::Client;
|
||||
|
||||
let rocket = rocket::build()
|
||||
.mount("/", routes![index])
|
||||
.mount("/module", routes![module::index])
|
||||
.mount("/module2", routes![module2::index])
|
||||
.mount("/module2/two", routes![module2::two::index])
|
||||
.mount("/module2/module3", routes![module2::module3::index])
|
||||
.mount("/module2/module3/two", routes![module2::module3::two::index]);
|
||||
|
||||
let uris = rocket.routes()
|
||||
.map(|r| r.uri.base().to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let client = Client::debug(rocket).unwrap();
|
||||
for uri in uris {
|
||||
let response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uri_calls() {
|
||||
let uris = [
|
||||
uri!(index()),
|
||||
uri!(module::index()),
|
||||
uri!(module2::index()),
|
||||
uri!(module2::two::index()),
|
||||
uri!(module2::module3::index()),
|
||||
uri!(module2::module3::two::index()),
|
||||
];
|
||||
|
||||
assert!(uris.iter().all(|uri| uri == "/"));
|
||||
}
|
Loading…
Reference in New Issue