1use crate::http::uncased::UncasedStr;
2
3use syn::{self, Ident, ext::IdentExt};
4use proc_macro2::{Span, TokenStream};
5
6#[derive(Debug, Clone)]
18pub struct Name {
19 value: String,
20 span: Span,
21}
22
23impl Name {
24 pub fn new<S: Into<String>>(name: S, span: Span) -> Self {
27 Name { value: name.into(), span }
28 }
29
30 pub fn as_str(&self) -> &str {
33 &self.value
34 }
35
36 pub fn as_uncased_str(&self) -> &UncasedStr {
38 UncasedStr::new(self.as_str())
39 }
40
41 pub fn span(&self) -> Span {
42 self.span
43 }
44}
45
46impl devise::FromMeta for Name {
47 fn from_meta(meta: &devise::MetaItem) -> devise::Result<Self> {
48 use devise::ext::SpanDiagnosticExt;
49
50 if let syn::Lit::Str(s) = meta.lit()? {
51 return Ok(Name::new(s.value(), s.span()));
52 }
53
54 Err(meta.value_span().error("invalid value: expected string literal"))
55 }
56}
57
58impl quote::ToTokens for Name {
59 fn to_tokens(&self, tokens: &mut TokenStream) {
60 syn::LitStr::new(self.as_str(), self.span()).to_tokens(tokens)
61 }
62}
63
64impl From<&Ident> for Name {
65 fn from(ident: &Ident) -> Self {
66 Name::new(ident.unraw().to_string(), ident.span())
67 }
68}
69
70impl AsRef<str> for Name {
71 fn as_ref(&self) -> &str {
72 self.as_str()
73 }
74}
75
76impl std::hash::Hash for Name {
77 fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
78 self.as_str().hash(hasher)
79 }
80}
81
82impl std::ops::Deref for Name {
83 type Target = str;
84
85 fn deref(&self) -> &Self::Target {
86 self.as_str()
87 }
88}
89
90impl Eq for Name { }
91
92impl<S: PartialEq<str> + ?Sized> PartialEq<S> for Name {
93 fn eq(&self, other: &S) -> bool {
94 other == self.as_str()
95 }
96}
97
98impl std::fmt::Display for Name {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 self.as_str().fmt(f)
101 }
102}