diff --git a/src/legacy.rs b/src/legacy.rs index d55f3a1..3648cee 100644 --- a/src/legacy.rs +++ b/src/legacy.rs @@ -46,19 +46,19 @@ pub struct Demangle<'a> { // Note that this demangler isn't quite as fancy as it could be. We have lots // of other information in our symbols like hashes, version, type information, // etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> { +pub fn demangle(s: &str) -> Result<(Demangle<'_>, &str), ()> { // First validate the symbol. If it doesn't look like anything we're // expecting, we just print it literally. Note that we must handle non-Rust // symbols because we could have any function in the backtrace. - let inner = if s.starts_with("_ZN") { - &s[3..] - } else if s.starts_with("ZN") { + let inner = if let Some(s) = s.strip_prefix("_ZN") { + s + } else if let Some(s) = s.strip_prefix("ZN") { // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" // form too. - &s[2..] - } else if s.starts_with("__ZN") { + s + } else if let Some(s) = s.strip_prefix("__ZN") { // On OSX, symbols are prefixed with an extra _ - &s[4..] + s } else { return Err(()); }; @@ -69,15 +69,16 @@ pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> { } let mut elements = 0; - let mut chars = inner.chars(); + // we checked, that string is in ascii range + let mut chars = inner.bytes(); let mut c = chars.next().ok_or(())?; - while c != 'E' { + while c != b'E' { // Decode an identifier element's length. - if !c.is_digit(10) { + if !(c as char).is_digit(10) { return Err(()); } let mut len = 0usize; - while let Some(d) = c.to_digit(10) { + while let Some(d) = (c as char).to_digit(10) { len = len .checked_mul(10) .and_then(|len| len.checked_add(d as usize)) @@ -94,21 +95,30 @@ pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> { elements += 1; } - Ok((Demangle { inner, elements }, chars.as_str())) + let chars_left = chars.count(); + Ok(( + Demangle { inner, elements }, + &inner[inner.len() - chars_left..], + )) } // Rust hashes are hex digits with an `h` prepended. fn is_rust_hash(s: &str) -> bool { - s.starts_with('h') && s[1..].chars().all(|c| c.is_digit(16)) + s.starts_with('h') && s[1..].bytes().all(|c| (c as char).is_digit(16)) } impl<'a> fmt::Display for Demangle<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Alright, let's do this. let mut inner = self.inner; for element in 0..self.elements { let mut rest = inner; - while rest.chars().next().unwrap().is_digit(10) { + while rest + .bytes() + .next() + .map(|c| (c as char).is_digit(10)) + .unwrap_or(false) + { rest = &rest[1..]; } let i: usize = inner[..(inner.len() - rest.len())].parse().unwrap(); @@ -116,7 +126,7 @@ impl<'a> fmt::Display for Demangle<'a> { rest = &rest[..i]; // Skip printing the hash if alternate formatting // was requested. - if f.alternate() && element + 1 == self.elements && is_rust_hash(&rest) { + if f.alternate() && element + 1 == self.elements && is_rust_hash(rest) { break; } if element != 0 { @@ -127,7 +137,7 @@ impl<'a> fmt::Display for Demangle<'a> { } loop { if rest.starts_with('.') { - if let Some('.') = rest[1..].chars().next() { + if let Some(b'.') = rest[1..].bytes().next() { f.write_str("::")?; rest = &rest[2..]; } else { @@ -153,10 +163,9 @@ impl<'a> fmt::Display for Demangle<'a> { "C" => ",", _ => { - if escape.starts_with('u') { - let digits = &escape[1..]; - let all_lower_hex = digits.chars().all(|c| match c { - '0'..='9' | 'a'..='f' => true, + if let Some(digits) = escape.strip_prefix('u') { + let all_lower_hex = digits.bytes().all(|c| match c { + b'0'..=b'9' | b'a'..=b'f' => true, _ => false, }); let c = u32::from_str_radix(digits, 16) diff --git a/src/lib.rs b/src/lib.rs index 1ecb13f..18b1bec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,15 +88,15 @@ enum DemangleStyle<'a> { /// assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar"); /// assert_eq!(demangle("foo").to_string(), "foo"); /// ``` -pub fn demangle(mut s: &str) -> Demangle { +pub fn demangle(mut s: &str) -> Demangle<'_> { // During ThinLTO LLVM may import and rename internal symbols, so strip out // those endings first as they're one of the last manglings applied to symbol // names. let llvm = ".llvm."; if let Some(i) = s.find(llvm) { let candidate = &s[i + llvm.len()..]; - let all_hex = candidate.chars().all(|c| match c { - 'A'..='F' | '0'..='9' | '@' => true, + let all_hex = candidate.bytes().all(|c| match c { + b'A'..=b'F' | b'0'..=b'9' | b'@' => true, _ => false, }); @@ -164,7 +164,7 @@ pub struct TryDemangleError { /// // While `demangle` will just pass the non-symbol through as a no-op. /// assert_eq!(rustc_demangle::demangle(not_a_rust_symbol).as_str(), not_a_rust_symbol); /// ``` -pub fn try_demangle(s: &str) -> Result { +pub fn try_demangle(s: &str) -> Result, TryDemangleError> { let sym = demangle(s); if sym.style.is_some() { Ok(sym) @@ -241,7 +241,7 @@ impl fmt::Write for SizeLimitedFmtAdapter { } impl<'a> fmt::Display for Demangle<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.style { None => f.write_str(self.original)?, Some(ref d) => { @@ -276,7 +276,7 @@ impl<'a> fmt::Display for Demangle<'a> { } impl<'a> fmt::Debug for Demangle<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) } } diff --git a/src/v0.rs b/src/v0.rs index 3e88fa6..b06d49a 100644 --- a/src/v0.rs +++ b/src/v0.rs @@ -38,23 +38,22 @@ pub fn demangle(s: &str) -> Result<(Demangle, &str), ParseError> { // First validate the symbol. If it doesn't look like anything we're // expecting, we just print it literally. Note that we must handle non-Rust // symbols because we could have any function in the backtrace. - let inner; - if s.len() > 2 && s.starts_with("_R") { - inner = &s[2..]; - } else if s.len() > 1 && s.starts_with('R') { + let inner = if let Some(s) = s.strip_prefix("_R") { + s + } else if let Some(s) = s.strip_prefix('R') { // On Windows, dbghelp strips leading underscores, so we accept "R..." // form too. - inner = &s[1..]; - } else if s.len() > 3 && s.starts_with("__R") { + s + } else if let Some(s) = s.strip_prefix("__R") { // On OSX, symbols are prefixed with an extra _ - inner = &s[3..]; + s } else { return Err(ParseError::Invalid); - } + }; // Paths always start with uppercase characters. - match inner.as_bytes()[0] { - b'A'..=b'Z' => {} + match inner.bytes().next() { + Some(b'A'..=b'Z') => {} _ => return Err(ParseError::Invalid), } @@ -161,8 +160,8 @@ impl<'s> Ident<'s> { let mut len = 0; // Populate initial output from ASCII fragment. - for c in self.ascii.chars() { - insert(len, c)?; + for c in self.ascii.bytes() { + insert(len, c as char)?; len += 1; }