use rustdoc_types::{Item, Span};
use std::fmt;
#[derive(Copy, Clone, Debug)]
pub enum ComponentType {
AssocConst,
AssocType,
Constant,
Crate,
Enum,
EnumVariant,
Function,
Impl,
Module,
ReExport,
Static,
Struct,
StructField,
Trait,
TypeAlias,
Union,
}
#[derive(Clone, Debug)]
struct Component {
typ: ComponentType,
name: String,
span: Option<Span>,
}
impl Component {
fn new(typ: ComponentType, name: String, span: Option<Span>) -> Self {
Self { typ, name, span }
}
}
#[derive(Clone, Debug)]
pub struct Path {
stack: Vec<Component>,
}
impl Path {
pub fn new(crate_name: &str) -> Self {
Self {
stack: vec![Component::new(
ComponentType::Crate,
crate_name.into(),
None,
)],
}
}
pub fn push(&mut self, typ: ComponentType, item: &Item) {
self.push_raw(typ, item.name.as_ref().expect("name"), item.span.as_ref());
}
pub fn push_raw(&mut self, typ: ComponentType, name: &str, span: Option<&Span>) {
self.stack
.push(Component::new(typ, name.into(), span.cloned()));
}
pub fn last_span(&self) -> Option<&Span> {
self.stack.last().and_then(|c| c.span.as_ref())
}
pub fn last_type(&self) -> Option<ComponentType> {
self.stack.last().map(|c| c.typ)
}
}
impl fmt::Display for Path {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let names: Vec<&str> = self
.stack
.iter()
.filter(|component| !component.name.is_empty())
.map(|component| component.name.as_str())
.collect();
write!(f, "{}", names.join("::"))
}
}