use crate::syn::{self, Ident, ext::IdentExt}; use crate::http::uncased::UncasedStr; use crate::proc_macro2::Span; /// A "name" read by codegen, which may or may not be an identifier. A `Name` is /// typically constructed indirectly via FromMeta, or From or directly /// from a string via `Name::new()`. /// /// Some "names" in Rocket include: /// * Dynamic parameter: `name` in `` /// * Renamed fields: `foo` in #[field(name = "foo")]. /// /// `Name` implements Hash, PartialEq, and Eq, and additionally PartialEq for /// all types `S: PartialEq`. These implementations all compare the value /// of `as_str()` only. #[derive(Debug, Clone)] pub struct Name { value: String, span: Span, } impl Name { /// Creates a new `Name` from the string `name` and span `span`. If /// `name` is a valid ident, the ident is stored as well. pub fn new>(name: S, span: Span) -> Self { Name { value: name.into(), span } } /// Returns the name as a string. Notably, if `self` was constructed from an /// Ident this method returns a name *without* an `r#` prefix. pub fn as_str(&self) -> &str { &self.value } /// Like `as_str()` but into an `&UncasedStr`. pub fn as_uncased_str(&self) -> &UncasedStr { UncasedStr::new(self.as_str()) } pub fn span(&self) -> Span { self.span } } impl devise::FromMeta for Name { fn from_meta(meta: &devise::MetaItem) -> devise::Result { use devise::ext::SpanDiagnosticExt; if let syn::Lit::Str(s) = meta.lit()? { return Ok(Name::new(s.value(), s.span())); } Err(meta.value_span().error("invalid value: expected string literal")) } } impl quote::ToTokens for Name { fn to_tokens(&self, tokens: &mut devise::proc_macro2::TokenStream) { syn::LitStr::new(self.as_str(), self.span()).to_tokens(tokens) } } impl From<&Ident> for Name { fn from(ident: &Ident) -> Self { Name::new(ident.unraw().to_string(), ident.span()) } } impl AsRef for Name { fn as_ref(&self) -> &str { self.as_str() } } impl std::hash::Hash for Name { fn hash(&self, hasher: &mut H) { self.as_str().hash(hasher) } } impl std::ops::Deref for Name { type Target = str; fn deref(&self) -> &Self::Target { self.as_str() } } impl Eq for Name { } impl + ?Sized> PartialEq for Name { fn eq(&self, other: &S) -> bool { other == self.as_str() } } impl std::fmt::Display for Name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_str().fmt(f) } }