Skip to content

Commit 1523aeb

Browse files
authored
Merge pull request #5 from luser/format-without-hash
Allow formatting the demangled symbol name without the trailing hash.
2 parents 38e866b + 5941ee9 commit 1523aeb

File tree

1 file changed

+59
-7
lines changed

1 file changed

+59
-7
lines changed

src/lib.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
//! symbol name. The demangled representation will be the same as the original
66
//! if it doesn't look like a mangled symbol name.
77
//!
8+
//! `Demangle` can be formatted with the `Display` trait. The alternate
9+
//! modifier (`#`) can be used to format the symbol name without the
10+
//! trailing hash value.
11+
//!
812
//! # Examples
913
//!
1014
//! ```
@@ -13,6 +17,10 @@
1317
//! assert_eq!(demangle("_ZN4testE").to_string(), "test");
1418
//! assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar");
1519
//! assert_eq!(demangle("foo").to_string(), "foo");
20+
//! // With hash
21+
//! assert_eq!(format!("{}", demangle("_ZN3foo17h05af221e174051e9E")), "foo::h05af221e174051e9");
22+
//! // Without hash
23+
//! assert_eq!(format!("{:#}", demangle("_ZN3foo17h05af221e174051e9E")), "foo");
1624
//! ```
1725
1826
#![no_std]
@@ -29,6 +37,8 @@ pub struct Demangle<'a> {
2937
original: &'a str,
3038
inner: &'a str,
3139
valid: bool,
40+
/// The number of ::-separated elements in the original name.
41+
elements: usize,
3242
}
3343

3444
/// De-mangles a Rust symbol into a more readable version
@@ -86,6 +96,7 @@ pub fn demangle(s: &str) -> Demangle {
8696
valid = false;
8797
}
8898

99+
let mut elements = 0;
89100
if valid {
90101
let mut chars = inner.chars();
91102
while valid {
@@ -102,13 +113,16 @@ pub fn demangle(s: &str) -> Demangle {
102113
break;
103114
} else if chars.by_ref().take(i - 1).count() != i - 1 {
104115
valid = false;
116+
} else {
117+
elements += 1;
105118
}
106119
}
107120
}
108121

109122
Demangle {
110123
inner: inner,
111124
valid: valid,
125+
elements: elements,
112126
original: s,
113127
}
114128
}
@@ -120,6 +134,11 @@ impl<'a> Demangle<'a> {
120134
}
121135
}
122136

137+
// Rust hashes are hex digits with an `h` prepended.
138+
fn is_rust_hash(s: &str) -> bool {
139+
s.starts_with('h') && s[1..].chars().all(|c| c.is_digit(16))
140+
}
141+
123142
impl<'a> fmt::Display for Demangle<'a> {
124143
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125144
// Alright, let's do this.
@@ -128,20 +147,22 @@ impl<'a> fmt::Display for Demangle<'a> {
128147
}
129148

130149
let mut inner = self.inner;
131-
let mut first = true;
132-
while !inner.is_empty() {
133-
if !first {
134-
try!(f.write_str("::"));
135-
} else {
136-
first = false;
137-
}
150+
for element in 0..self.elements {
138151
let mut rest = inner;
139152
while rest.chars().next().unwrap().is_digit(10) {
140153
rest = &rest[1..];
141154
}
142155
let i: usize = inner[..(inner.len() - rest.len())].parse().unwrap();
143156
inner = &rest[i..];
144157
rest = &rest[..i];
158+
// Skip printing the hash if alternate formatting
159+
// was requested.
160+
if f.alternate() && element+1 == self.elements && is_rust_hash(&rest) {
161+
break;
162+
}
163+
if element != 0 {
164+
try!(f.write_str("::"));
165+
}
145166
if rest.starts_with("_$") {
146167
rest = &rest[1..];
147168
}
@@ -224,6 +245,12 @@ mod tests {
224245
})
225246
}
226247

248+
macro_rules! t_nohash {
249+
($a:expr, $b:expr) => ({
250+
assert_eq!(format!("{:#}", super::demangle($a)), $b);
251+
})
252+
}
253+
227254
#[test]
228255
fn demangle() {
229256
t!("test", "test");
@@ -266,4 +293,29 @@ mod tests {
266293
t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
267294
"<Test + 'static as foo::Bar<Test>>::bar");
268295
}
296+
297+
#[test]
298+
fn demangle_without_hash() {
299+
let s = "_ZN3foo17h05af221e174051e9E";
300+
t!(s, "foo::h05af221e174051e9");
301+
t_nohash!(s, "foo");
302+
}
303+
304+
#[test]
305+
fn demangle_without_hash_edgecases() {
306+
// One element, no hash.
307+
t_nohash!("_ZN3fooE", "foo");
308+
// Two elements, no hash.
309+
t_nohash!("_ZN3foo3barE", "foo::bar");
310+
// Longer-than-normal hash.
311+
t_nohash!("_ZN3foo20h05af221e174051e9abcE", "foo");
312+
// Shorter-than-normal hash.
313+
t_nohash!("_ZN3foo5h05afE", "foo");
314+
// Valid hash, but not at the end.
315+
t_nohash!("_ZN17h05af221e174051e93fooE", "h05af221e174051e9::foo");
316+
// Not a valid hash, missing the 'h'.
317+
t_nohash!("_ZN3foo16ffaf221e174051e9E", "foo::ffaf221e174051e9");
318+
// Not a valid hash, has a non-hex-digit.
319+
t_nohash!("_ZN3foo17hg5af221e174051e9E", "foo::hg5af221e174051e9");
320+
}
269321
}

0 commit comments

Comments
 (0)