Add codegen internal 'Ident::uniqueify()' method.

This makes an ident unique based on some or no metadata.
This commit is contained in:
Sergio Benitez 2021-04-28 01:24:03 -07:00
parent d21608ca7b
commit 41018a5112
2 changed files with 30 additions and 19 deletions

View File

@ -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<Item = &Guard> {
@ -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() =>

View File

@ -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<F: FnMut(&mut dyn Hasher)>(&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<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);
f(&mut hasher);
self.append(&format!("_{}", hasher.finish()))
}
}
impl ReturnTypeExt for syn::ReturnType {