use regex::Regex;
use rustc_demangle::demangle;
use std::borrow::Cow;
use std::io::{self, BufRead, BufReader, Write};
use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
pub trait Demangler<'a, 'b> {
fn demangle(&'b mut self, ident: &'a str) -> io::Result<Cow<'a, str>>;
fn stop(self) -> io::Result<()>;
}
pub struct CppDemangler {
child: Child,
child_in: ChildStdin,
child_out: BufReader<ChildStdout>,
}
impl CppDemangler {
#[allow(clippy::unwrap_used)]
pub fn new(cmd: &str) -> io::Result<Self> {
let mut child = Command::new(cmd)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
let child_in = child.stdin.take().unwrap();
let child_out = BufReader::new(child.stdout.take().unwrap());
Ok(Self {
child,
child_in,
child_out,
})
}
}
impl<'a, 'b> Demangler<'a, 'b> for CppDemangler {
fn demangle(&mut self, ident: &str) -> io::Result<Cow<'a, str>> {
self.child_in.write_all(format!("{}\n", ident).as_bytes())?;
let mut line = String::new();
self.child_out.read_line(&mut line)?;
Ok(Cow::Owned(line.trim().into()))
}
fn stop(mut self) -> io::Result<()> {
self.child.kill()?;
Ok(())
}
}
pub struct RustDemangler {
disambiguator: Regex,
}
impl Default for RustDemangler {
fn default() -> Self {
Self::new()
}
}
impl RustDemangler {
#[allow(clippy::unwrap_used)]
pub fn new() -> Self {
Self {
disambiguator: Regex::new(r"\[[0-9a-f]{5,16}\]::").unwrap(),
}
}
}
impl<'a, 'b> Demangler<'a, 'b> for RustDemangler {
fn demangle(&mut self, ident: &str) -> io::Result<Cow<'a, str>> {
let demangled = demangle(ident).to_string();
Ok(Cow::Owned(
self.disambiguator.replace_all(&demangled, "::").to_string(),
))
}
fn stop(self) -> io::Result<()> {
Ok(())
}
}
pub struct NullDemangler {}
impl Default for NullDemangler {
fn default() -> Self {
Self::new()
}
}
impl NullDemangler {
pub fn new() -> Self {
Self {}
}
}
impl<'a, 'b> Demangler<'a, 'b> for NullDemangler {
fn demangle(&'b mut self, ident: &'a str) -> io::Result<Cow<'a, str>> {
Ok(Cow::Borrowed(ident))
}
fn stop(self) -> io::Result<()> {
Ok(())
}
}