use std::collections::HashMap;
use itertools::Itertools;
use rustc_span::Symbol;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{AdtDef, TyCtxt};
use crate::callbacks::{ConfigStrExt, config};
#[derive(Debug)]
pub struct NamespaceNode<T> {
pub children: HashMap<Symbol, NamespaceNode<T>>,
pub items: Vec<(Symbol, T)>,
}
impl<T> Default for NamespaceNode<T> {
fn default() -> Self {
Self {
children: Default::default(),
items: Default::default(),
}
}
}
#[bon::bon]
impl<T> NamespaceNode<T> {
#[builder]
pub fn insert(
&mut self,
root_path: NamespacedPath,
item: T,
#[builder(default, with = || true)] allow_duplicates: bool,
) {
let mut segments = root_path.segments().to_vec();
if config().omit_crate_name() && segments.len() > 1 {
segments = segments.into_iter().skip(1).collect_vec();
}
match segments.split_last() {
None => {
}
Some((last_segment, [])) => {
if allow_duplicates || !self.items.iter().any(|(sym, _)| sym == last_segment) {
self.items.push((*last_segment, item));
}
}
Some((last_segment, prefix)) => {
let mut node = self;
for segment in prefix {
node = node.children.entry(*segment).or_default();
}
if allow_duplicates || !node.items.iter().any(|(sym, _)| sym == last_segment) {
node.items.push((*last_segment, item));
}
}
}
}
}
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct NamespacedPath(Vec<Symbol>);
impl NamespacedPath {
pub fn from_mod_syntax(s: &str) -> Self {
let segments = s.split("::").map(Symbol::intern).collect::<Vec<_>>();
Self(segments)
}
pub fn with_extra_segment(mut self, extra: impl Into<Symbol>) -> Self {
self.0.push(extra.into());
self
}
pub fn item_name(&self) -> &Symbol {
self.0
.last()
.unwrap_or_else(|| panic!("NamespacedPath is empty: {self:?}"))
}
#[allow(dead_code)]
pub fn with_different_item_name(mut self, alt: impl Into<Symbol>) -> Self {
self.0.pop();
self.0.push(alt.into());
self
}
pub fn new_for_adt(tcx: TyCtxt<'_>, adt: &AdtDef<'_>) -> Self {
Self::new(tcx, adt.did())
}
pub fn new(tcx: TyCtxt<'_>, did: DefId) -> Self {
let path = tcx.def_path(did);
let crate_name = tcx.crate_name(path.krate);
let mut symbols = vec![Symbol::intern(crate_name.as_str())];
symbols.extend(
path.data
.iter()
.map(|d| Symbol::intern(d.to_string().as_str())),
);
Self(symbols)
}
pub fn std_string() -> Self {
Self(vec![
Symbol::intern("alloc"),
Symbol::intern("string"),
Symbol::intern("String"),
])
}
pub fn std_vec() -> Self {
Self(vec![
Symbol::intern("alloc"),
Symbol::intern("vec"),
Symbol::intern("Vec"),
])
}
pub fn hashbrown_hashmap() -> Self {
Self(vec![
Symbol::intern("hashbrown"),
Symbol::intern("map"),
Symbol::intern("HashMap"),
])
}
pub fn std_hashmap() -> Self {
Self(vec![
Symbol::intern("std"),
Symbol::intern("collections"),
Symbol::intern("hash"),
Symbol::intern("map"),
Symbol::intern("HashMap"),
])
}
pub fn std_option() -> Self {
Self(vec![
Symbol::intern("core"),
Symbol::intern("option"),
Symbol::intern("Option"),
])
}
pub fn result() -> Self {
Self(vec![
Symbol::intern("core"),
Symbol::intern("result"),
Symbol::intern("Result"),
])
}
pub fn chrono_naive_date_time() -> Self {
Self(vec![
Symbol::intern("chrono"),
Symbol::intern("naive"),
Symbol::intern("datetime"),
Symbol::intern("NaiveDateTime"),
])
}
pub fn chrono_naive_date() -> Self {
Self(vec![
Symbol::intern("chrono"),
Symbol::intern("naive"),
Symbol::intern("date"),
Symbol::intern("NaiveDate"),
])
}
pub fn chrono_naive_time() -> Self {
Self(vec![
Symbol::intern("chrono"),
Symbol::intern("naive"),
Symbol::intern("time"),
Symbol::intern("NaiveTime"),
])
}
pub fn chrono_tz_timezones() -> Self {
Self(vec![
Symbol::intern("chrono_tz"),
Symbol::intern("timezones"),
Symbol::intern("Tz"),
])
}
pub fn uuid() -> Self {
Self(vec![Symbol::intern("uuid"), Symbol::intern("Uuid")])
}
pub fn segments(&self) -> &[Symbol] {
&self.0
}
pub fn is_user_defined(&self) -> bool {
!(self == &Self::std_string()
|| self == &Self::std_vec()
|| self == &Self::hashbrown_hashmap()
|| self == &Self::std_hashmap()
|| self == &Self::std_option()
|| self == &Self::chrono_naive_date_time()
|| self == &Self::chrono_naive_date()
|| self == &Self::chrono_naive_time()
|| self == &Self::uuid())
|| self == &Self::result()
}
}
#[derive(Clone, Debug)]
pub enum EntityName {
Ident(Symbol),
QualifiedEntityName(Box<QualifiedEntityName>),
}
#[derive(Clone, Debug)]
pub struct QualifiedEntityName {
pub left: EntityName,
pub right: Symbol,
}
impl From<NamespacedPath> for EntityName {
fn from(path: NamespacedPath) -> EntityName {
fn build_entity_name(segments: &[Symbol]) -> EntityName {
match segments {
[] => EntityName::Ident(Symbol::intern("")),
[single] => EntityName::Ident(*single),
_ => {
let (prefix, last) = segments.split_at(segments.len() - 1);
let prefix_maybe_camel = prefix
.iter()
.map(|s| Symbol::intern(s.as_str().namespace_name().as_ref()))
.collect::<Vec<_>>();
EntityName::QualifiedEntityName(Box::new(QualifiedEntityName {
left: build_entity_name(&prefix_maybe_camel),
right: Symbol::intern(last[0].as_str()),
}))
}
}
}
let root_path = if config().omit_crate_name() {
path.0[1..].to_vec()
} else {
path.0
};
build_entity_name(&root_path)
}
}
impl Iterator for NamespacedPath {
type Item = Symbol;
fn next(&mut self) -> Option<Self::Item> {
self.0.pop()
}
}
impl DoubleEndedIterator for NamespacedPath {
fn next_back(&mut self) -> Option<Self::Item> {
if self.0.is_empty() {
return None;
}
Some(self.0.remove(0))
}
}