use std::fmt;
use crate::{
demangle::demangle_symbol, print::PrintOptions, rust_path::RustPath, rust_type::TraitFnImpl,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum SymbolScope {
Unknown,
Compilation,
Linkage,
Dynamic,
}
impl fmt::Display for SymbolScope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unknown => write!(f, "unknown"),
Self::Compilation => write!(f, "local"),
Self::Linkage => write!(f, "static"),
Self::Dynamic => write!(f, "dynamic"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SymbolKind {
Unknown,
Text,
Data,
Section,
File,
Label,
Tls,
}
impl fmt::Display for SymbolKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unknown => write!(f, "unknown"),
Self::Text => write!(f, "function"),
Self::Data => write!(f, "data"),
Self::Section => write!(f, "section"),
Self::File => write!(f, "file"),
Self::Label => write!(f, "label"),
Self::Tls => write!(f, "tls"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FunctionOrPath {
Function(String),
RustPath(RustPath),
}
impl fmt::Display for FunctionOrPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Function(name) => write!(f, "{name}"),
Self::RustPath(path) => write!(f, "{path}"),
}
}
}
impl FunctionOrPath {
pub fn from_demangled(demangled: &str) -> Vec<Self> {
if demangled.starts_with("rustc[") {
if let Some(end_bracket) = demangled.find("]::") {
vec![Self::Function(demangled[end_bracket + 3..].to_owned())]
} else {
panic!("Weird symbol: {demangled:?}"); }
} else if let Ok(trait_impl) = TraitFnImpl::parse(demangled) {
trait_impl
.paths()
.into_iter()
.filter(|path| path.segments().len() > 1) .map(FunctionOrPath::RustPath)
.collect()
} else if demangled.contains("::") {
vec![Self::RustPath(RustPath::new(demangled))]
} else {
vec![Self::Function(demangled.to_owned())]
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Symbol {
pub mangled: String,
pub demangled: String,
pub scope: SymbolScope,
pub kind: SymbolKind,
}
impl Symbol {
pub fn with_metadata(mangled: String, scope: SymbolScope, kind: SymbolKind) -> Self {
let demangled = demangle_symbol(&mangled);
Self {
mangled,
demangled,
scope,
kind,
}
}
pub fn format(&self, include_mangled: bool) -> String {
let Self {
mangled, demangled, ..
} = self;
if include_mangled && mangled != demangled {
format!("{demangled} ({mangled})")
} else {
demangled.clone()
}
}
pub fn format_with_metadata(&self, options: &PrintOptions) -> String {
let base = self.format(options.include_mangled);
if options.show_metadata {
let scope_str = self.scope.to_string();
let kind_str = self.kind.to_string();
format!("{base} [{scope_str}/{kind_str}]")
} else {
base
}
}
pub fn paths(&self) -> Vec<FunctionOrPath> {
FunctionOrPath::from_demangled(&self.demangled)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_paths() {
let symbol = Symbol::with_metadata(
"parking_lot::raw_rwlock::RawRwLock::lock_shared_slow".to_owned(),
SymbolScope::Dynamic,
SymbolKind::Data,
);
assert_eq!(
symbol.paths(),
vec![FunctionOrPath::RustPath(RustPath::new(
"parking_lot::raw_rwlock::RawRwLock::lock_shared_slow"
))]
);
}
}