lcov2cobertura/
demangle.rs

1//! Interface and implemtation of different demanglers
2use regex::Regex;
3use rustc_demangle::demangle;
4use std::borrow::Cow;
5use std::io::{self, BufRead, BufReader, Write};
6use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
7
8/// Basic interface to demangle function/method names
9pub trait Demangler<'a, 'b> {
10    /// demangles an identifier
11    fn demangle(&'b mut self, ident: &'a str) -> io::Result<Cow<'a, str>>;
12    /// consumes the instance closing opened resources
13    fn stop(self) -> io::Result<()>;
14}
15
16/// C++ demangling, actually accepts any demangler tool that works over stdin/stdout
17/// it writes the mangled named to spawned process' stdin and reads the demangled response from
18/// stdout
19pub struct CppDemangler {
20    child: Child,
21    child_in: ChildStdin,
22    child_out: BufReader<ChildStdout>,
23}
24
25impl CppDemangler {
26    /// pass in full path to command that does the demangling
27    // safety: stdin/stdout is only taken once, panic unlikely
28    #[allow(clippy::unwrap_used, clippy::unwrap_in_result)]
29    pub fn new(cmd: &str) -> io::Result<Self> {
30        let mut child = Command::new(cmd)
31            .stdin(Stdio::piped())
32            .stdout(Stdio::piped())
33            .spawn()?;
34        let child_in = child.stdin.take().unwrap();
35        let child_out = BufReader::new(child.stdout.take().unwrap());
36        Ok(Self {
37            child,
38            child_in,
39            child_out,
40        })
41    }
42}
43
44impl<'a> Demangler<'a, '_> for CppDemangler {
45    fn demangle(&mut self, ident: &str) -> io::Result<Cow<'a, str>> {
46        self.child_in.write_all(format!("{}\n", ident).as_bytes())?;
47        let mut line = String::new();
48        self.child_out.read_line(&mut line)?;
49        Ok(Cow::Owned(line.trim().into()))
50    }
51
52    fn stop(mut self) -> io::Result<()> {
53        self.child.kill()?;
54        Ok(())
55    }
56}
57
58/// Demangles rustc names, uses [rustc_demangle](https://docs.rs/rustc-demangle/) crate
59pub struct RustDemangler {
60    /// strips crate disambiguators
61    disambiguator: Regex,
62}
63impl Default for RustDemangler {
64    fn default() -> Self {
65        Self::new()
66    }
67}
68
69impl RustDemangler {
70    /// creates the Regex instance needed for later demangling
71    // safety: regex is known to compile fine, no panic
72    #[allow(clippy::unwrap_used)]
73    pub fn new() -> Self {
74        Self {
75            disambiguator: Regex::new(r"\[[0-9a-f]{5,16}\]::").unwrap(),
76        }
77    }
78}
79impl<'a> Demangler<'a, '_> for RustDemangler {
80    fn demangle(&mut self, ident: &str) -> io::Result<Cow<'a, str>> {
81        let demangled = demangle(ident).to_string();
82        Ok(Cow::Owned(
83            self.disambiguator.replace_all(&demangled, "::").to_string(),
84        ))
85    }
86
87    fn stop(self) -> io::Result<()> {
88        Ok(())
89    }
90}
91
92/// default demangler, does nothing to the identifier names
93pub struct NullDemangler {}
94impl Default for NullDemangler {
95    fn default() -> Self {
96        Self::new()
97    }
98}
99
100impl NullDemangler {
101    /// constructs the NullDemangler
102    pub fn new() -> Self {
103        Self {}
104    }
105}
106impl<'a, 'b> Demangler<'a, 'b> for NullDemangler {
107    fn demangle(&'b mut self, ident: &'a str) -> io::Result<Cow<'a, str>> {
108        Ok(Cow::Borrowed(ident))
109    }
110
111    fn stop(self) -> io::Result<()> {
112        Ok(())
113    }
114}