use std::fmt;
use intern::{Symbol, sym};
use span::{Edition, SyntaxContext};
use syntax::utils::is_raw_identifier;
use syntax::{ast, format_smolstr};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Name {
symbol: Symbol,
ctx: (),
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Name")
.field("symbol", &self.symbol.as_str())
.field("ctx", &self.ctx)
.finish()
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.symbol.as_str().cmp(other.symbol.as_str())
}
}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<Symbol> for Name {
fn eq(&self, sym: &Symbol) -> bool {
self.symbol == *sym
}
}
impl PartialEq<&Symbol> for Name {
fn eq(&self, &sym: &&Symbol) -> bool {
self.symbol == *sym
}
}
impl PartialEq<Name> for Symbol {
fn eq(&self, name: &Name) -> bool {
*self == name.symbol
}
}
impl PartialEq<Name> for &Symbol {
fn eq(&self, name: &Name) -> bool {
**self == name.symbol
}
}
impl Name {
fn new_text(text: &str) -> Name {
Name { symbol: Symbol::intern(text), ctx: () }
}
pub fn new(text: &str, mut ctx: SyntaxContext) -> Name {
ctx.remove_root_edition();
_ = ctx;
match text.strip_prefix("r#") {
Some(text) => Self::new_text(text),
None => Self::new_text(text),
}
}
pub fn new_root(text: &str) -> Name {
Self::new(text, SyntaxContext::root(Edition::Edition2015))
}
pub fn new_tuple_field(idx: usize) -> Name {
let symbol = match idx {
0 => sym::INTEGER_0,
1 => sym::INTEGER_1,
2 => sym::INTEGER_2,
3 => sym::INTEGER_3,
4 => sym::INTEGER_4,
5 => sym::INTEGER_5,
6 => sym::INTEGER_6,
7 => sym::INTEGER_7,
8 => sym::INTEGER_8,
9 => sym::INTEGER_9,
10 => sym::INTEGER_10,
11 => sym::INTEGER_11,
12 => sym::INTEGER_12,
13 => sym::INTEGER_13,
14 => sym::INTEGER_14,
15 => sym::INTEGER_15,
_ => Symbol::intern(&idx.to_string()),
};
Name { symbol, ctx: () }
}
pub fn new_lifetime(lt: &str) -> Name {
match lt.strip_prefix("'r#") {
Some(lt) => Self::new_text(&format_smolstr!("'{lt}")),
None => Self::new_text(lt),
}
}
pub fn new_symbol(symbol: Symbol, ctx: SyntaxContext) -> Self {
debug_assert!(!symbol.as_str().starts_with("r#"));
_ = ctx;
Self { symbol, ctx: () }
}
pub fn new_symbol_root(sym: Symbol) -> Self {
Self::new_symbol(sym, SyntaxContext::root(Edition::Edition2015))
}
pub const fn missing() -> Name {
Name { symbol: sym::MISSING_NAME, ctx: () }
}
pub fn is_missing(&self) -> bool {
self == &Name::missing()
}
pub fn generate_new_name(idx: usize) -> Name {
Name::new_text(&format!("<ra@gennew>{idx}"))
}
pub fn as_tuple_index(&self) -> Option<usize> {
self.symbol.as_str().parse().ok()
}
pub fn needs_escape(&self, edition: Edition) -> bool {
is_raw_identifier(self.symbol.as_str(), edition)
}
pub fn as_str(&self) -> &str {
self.symbol.as_str()
}
pub fn display<'a>(
&'a self,
db: &dyn crate::db::ExpandDatabase,
edition: Edition,
) -> impl fmt::Display + 'a {
_ = db;
self.display_no_db(edition)
}
#[doc(hidden)]
pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
Display { name: self, edition }
}
pub fn symbol(&self) -> &Symbol {
&self.symbol
}
pub fn is_generated(&self) -> bool {
self.as_str().starts_with("<ra@gennew>")
}
}
struct Display<'a> {
name: &'a Name,
edition: Edition,
}
impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut symbol = self.name.symbol.as_str();
if symbol == "'static" {
return f.write_str(symbol);
}
if let Some(s) = symbol.strip_prefix('\'') {
f.write_str("'")?;
symbol = s;
}
if is_raw_identifier(symbol, self.edition) {
f.write_str("r#")?;
}
f.write_str(symbol)
}
}
pub trait AsName {
fn as_name(&self) -> Name;
}
impl AsName for ast::NameRef {
fn as_name(&self) -> Name {
match self.as_tuple_field() {
Some(idx) => Name::new_tuple_field(idx),
None => Name::new_root(&self.text()),
}
}
}
impl AsName for ast::Name {
fn as_name(&self) -> Name {
Name::new_root(&self.text())
}
}
impl AsName for ast::NameOrNameRef {
fn as_name(&self) -> Name {
match self {
ast::NameOrNameRef::Name(it) => it.as_name(),
ast::NameOrNameRef::NameRef(it) => it.as_name(),
}
}
}
impl AsName for tt::Ident {
fn as_name(&self) -> Name {
Name::new_root(self.sym.as_str())
}
}
impl AsName for ast::FieldKind {
fn as_name(&self) -> Name {
match self {
ast::FieldKind::Name(nr) => nr.as_name(),
ast::FieldKind::Index(idx) => {
let idx = idx.text().parse::<usize>().unwrap_or(0);
Name::new_tuple_field(idx)
}
}
}
}
impl AsName for base_db::BuiltDependency {
fn as_name(&self) -> Name {
Name::new_symbol_root((*self.name).clone())
}
}