1use std::fmt;
4
5use intern::{sym, Symbol};
6use span::{Edition, SyntaxContextId};
7use syntax::utils::is_raw_identifier;
8use syntax::{ast, format_smolstr};
9
10#[derive(Clone, PartialEq, Eq, Hash)]
19pub struct Name {
20 symbol: Symbol,
21 ctx: (),
24}
25
26impl fmt::Debug for Name {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("Name")
29 .field("symbol", &self.symbol.as_str())
30 .field("ctx", &self.ctx)
31 .finish()
32 }
33}
34
35impl Ord for Name {
36 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
37 self.symbol.as_str().cmp(other.symbol.as_str())
38 }
39}
40
41impl PartialOrd for Name {
42 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
43 Some(self.cmp(other))
44 }
45}
46
47impl PartialEq<Symbol> for Name {
49 fn eq(&self, sym: &Symbol) -> bool {
50 self.symbol == *sym
51 }
52}
53
54impl PartialEq<&Symbol> for Name {
55 fn eq(&self, &sym: &&Symbol) -> bool {
56 self.symbol == *sym
57 }
58}
59
60impl PartialEq<Name> for Symbol {
61 fn eq(&self, name: &Name) -> bool {
62 *self == name.symbol
63 }
64}
65
66impl PartialEq<Name> for &Symbol {
67 fn eq(&self, name: &Name) -> bool {
68 **self == name.symbol
69 }
70}
71
72impl Name {
73 fn new_text(text: &str) -> Name {
74 Name { symbol: Symbol::intern(text), ctx: () }
75 }
76
77 pub fn new(text: &str, mut ctx: SyntaxContextId) -> Name {
78 ctx.remove_root_edition();
82 _ = ctx;
83 match text.strip_prefix("r#") {
84 Some(text) => Self::new_text(text),
85 None => Self::new_text(text),
86 }
87 }
88
89 pub fn new_root(text: &str) -> Name {
90 Self::new(text, SyntaxContextId::root(Edition::Edition2015))
92 }
93
94 pub fn new_tuple_field(idx: usize) -> Name {
95 let symbol = match idx {
96 0 => sym::INTEGER_0.clone(),
97 1 => sym::INTEGER_1.clone(),
98 2 => sym::INTEGER_2.clone(),
99 3 => sym::INTEGER_3.clone(),
100 4 => sym::INTEGER_4.clone(),
101 5 => sym::INTEGER_5.clone(),
102 6 => sym::INTEGER_6.clone(),
103 7 => sym::INTEGER_7.clone(),
104 8 => sym::INTEGER_8.clone(),
105 9 => sym::INTEGER_9.clone(),
106 10 => sym::INTEGER_10.clone(),
107 11 => sym::INTEGER_11.clone(),
108 12 => sym::INTEGER_12.clone(),
109 13 => sym::INTEGER_13.clone(),
110 14 => sym::INTEGER_14.clone(),
111 15 => sym::INTEGER_15.clone(),
112 _ => Symbol::intern(&idx.to_string()),
113 };
114 Name { symbol, ctx: () }
115 }
116
117 pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
118 let text = lt.text();
119 match text.strip_prefix("'r#") {
120 Some(text) => Self::new_text(&format_smolstr!("'{text}")),
121 None => Self::new_text(text.as_str()),
122 }
123 }
124
125 pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
126 debug_assert!(!symbol.as_str().starts_with("r#"));
127 _ = ctx;
128 Self { symbol, ctx: () }
129 }
130
131 pub fn new_symbol_root(sym: Symbol) -> Self {
133 Self::new_symbol(sym, SyntaxContextId::root(Edition::Edition2015))
134 }
135
136 pub const fn missing() -> Name {
146 Name { symbol: sym::consts::MISSING_NAME, ctx: () }
147 }
148
149 pub fn is_missing(&self) -> bool {
155 self == &Name::missing()
156 }
157
158 pub fn generate_new_name(idx: usize) -> Name {
162 Name::new_text(&format!("<ra@gennew>{idx}"))
163 }
164
165 pub fn as_tuple_index(&self) -> Option<usize> {
167 self.symbol.as_str().parse().ok()
168 }
169
170 pub fn needs_escape(&self, edition: Edition) -> bool {
172 is_raw_identifier(self.symbol.as_str(), edition)
173 }
174
175 pub fn as_str(&self) -> &str {
180 self.symbol.as_str()
181 }
182
183 pub fn display<'a>(
184 &'a self,
185 db: &dyn crate::db::ExpandDatabase,
186 edition: Edition,
187 ) -> impl fmt::Display + 'a {
188 _ = db;
189 self.display_no_db(edition)
190 }
191
192 #[doc(hidden)]
194 pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
195 Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) }
196 }
197
198 pub fn symbol(&self) -> &Symbol {
199 &self.symbol
200 }
201}
202
203struct Display<'a> {
204 name: &'a Name,
205 needs_escaping: bool,
206}
207
208impl fmt::Display for Display<'_> {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 if self.needs_escaping {
211 write!(f, "r#")?;
212 }
213 fmt::Display::fmt(self.name.symbol.as_str(), f)
214 }
215}
216
217pub trait AsName {
218 fn as_name(&self) -> Name;
219}
220
221impl AsName for ast::NameRef {
222 fn as_name(&self) -> Name {
223 match self.as_tuple_field() {
224 Some(idx) => Name::new_tuple_field(idx),
225 None => Name::new_root(&self.text()),
226 }
227 }
228}
229
230impl AsName for ast::Name {
231 fn as_name(&self) -> Name {
232 Name::new_root(&self.text())
233 }
234}
235
236impl AsName for ast::NameOrNameRef {
237 fn as_name(&self) -> Name {
238 match self {
239 ast::NameOrNameRef::Name(it) => it.as_name(),
240 ast::NameOrNameRef::NameRef(it) => it.as_name(),
241 }
242 }
243}
244
245impl<Span> AsName for tt::Ident<Span> {
246 fn as_name(&self) -> Name {
247 Name::new_root(self.sym.as_str())
248 }
249}
250
251impl AsName for ast::FieldKind {
252 fn as_name(&self) -> Name {
253 match self {
254 ast::FieldKind::Name(nr) => nr.as_name(),
255 ast::FieldKind::Index(idx) => {
256 let idx = idx.text().parse::<usize>().unwrap_or(0);
257 Name::new_tuple_field(idx)
258 }
259 }
260 }
261}
262
263impl AsName for base_db::Dependency {
264 fn as_name(&self) -> Name {
265 Name::new_symbol_root((*self.name).clone())
266 }
267}