Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usage of chars() iterator when bytes() can be used for ascii text #57

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
51 changes: 30 additions & 21 deletions src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(());
};
Expand All @@ -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))
Expand All @@ -94,29 +95,38 @@ 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();
inner = &rest[i..];
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 {
Expand All @@ -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 {
Expand All @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});

Expand Down Expand Up @@ -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<Demangle, TryDemangleError> {
pub fn try_demangle(s: &str) -> Result<Demangle<'_>, TryDemangleError> {
let sym = demangle(s);
if sym.style.is_some() {
Ok(sym)
Expand Down Expand Up @@ -241,7 +241,7 @@ impl<F: fmt::Write> fmt::Write for SizeLimitedFmtAdapter<F> {
}

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) => {
Expand Down Expand Up @@ -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)
}
}
Expand Down
23 changes: 11 additions & 12 deletions src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}

Expand Down Expand Up @@ -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;
}

Expand Down