5
5
//! symbol name. The demangled representation will be the same as the original
6
6
//! if it doesn't look like a mangled symbol name.
7
7
//!
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
+ //!
8
12
//! # Examples
9
13
//!
10
14
//! ```
13
17
//! assert_eq!(demangle("_ZN4testE").to_string(), "test");
14
18
//! assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar");
15
19
//! 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");
16
24
//! ```
17
25
18
26
#![ no_std]
@@ -29,6 +37,8 @@ pub struct Demangle<'a> {
29
37
original : & ' a str ,
30
38
inner : & ' a str ,
31
39
valid : bool ,
40
+ /// The number of ::-separated elements in the original name.
41
+ elements : usize ,
32
42
}
33
43
34
44
/// De-mangles a Rust symbol into a more readable version
@@ -86,6 +96,7 @@ pub fn demangle(s: &str) -> Demangle {
86
96
valid = false ;
87
97
}
88
98
99
+ let mut elements = 0 ;
89
100
if valid {
90
101
let mut chars = inner. chars ( ) ;
91
102
while valid {
@@ -102,13 +113,16 @@ pub fn demangle(s: &str) -> Demangle {
102
113
break ;
103
114
} else if chars. by_ref ( ) . take ( i - 1 ) . count ( ) != i - 1 {
104
115
valid = false ;
116
+ } else {
117
+ elements += 1 ;
105
118
}
106
119
}
107
120
}
108
121
109
122
Demangle {
110
123
inner : inner,
111
124
valid : valid,
125
+ elements : elements,
112
126
original : s,
113
127
}
114
128
}
@@ -120,6 +134,11 @@ impl<'a> Demangle<'a> {
120
134
}
121
135
}
122
136
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
+
123
142
impl < ' a > fmt:: Display for Demangle < ' a > {
124
143
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
125
144
// Alright, let's do this.
@@ -128,20 +147,22 @@ impl<'a> fmt::Display for Demangle<'a> {
128
147
}
129
148
130
149
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 {
138
151
let mut rest = inner;
139
152
while rest. chars ( ) . next ( ) . unwrap ( ) . is_digit ( 10 ) {
140
153
rest = & rest[ 1 ..] ;
141
154
}
142
155
let i: usize = inner[ ..( inner. len ( ) - rest. len ( ) ) ] . parse ( ) . unwrap ( ) ;
143
156
inner = & rest[ i..] ;
144
157
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
+ }
145
166
if rest. starts_with ( "_$" ) {
146
167
rest = & rest[ 1 ..] ;
147
168
}
@@ -224,6 +245,12 @@ mod tests {
224
245
} )
225
246
}
226
247
248
+ macro_rules! t_nohash {
249
+ ( $a: expr, $b: expr) => ( {
250
+ assert_eq!( format!( "{:#}" , super :: demangle( $a) ) , $b) ;
251
+ } )
252
+ }
253
+
227
254
#[ test]
228
255
fn demangle ( ) {
229
256
t ! ( "test" , "test" ) ;
@@ -266,4 +293,29 @@ mod tests {
266
293
t ! ( "_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE" ,
267
294
"<Test + 'static as foo::Bar<Test>>::bar" ) ;
268
295
}
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
+ }
269
321
}
0 commit comments