From 79489655221811894b9016e6d3a5999448aaa6a0 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Sun, 22 Jun 2025 22:56:47 -0400 Subject: [PATCH 1/2] Return the segment length instead of the segment The callers never need the actual segment so returning the length is more efficient. --- src/descriptors.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/descriptors.rs b/src/descriptors.rs index eadf427..aef4d8c 100644 --- a/src/descriptors.rs +++ b/src/descriptors.rs @@ -7,20 +7,21 @@ use std::{ use crate::ParseError; -// Returns the unqualified segment and the following char ('/', ';', or None) -// or an error. This only extracts the unqualified segment at the start of -// the given data, and ignores anything following. -fn parse_unqualified_segment(data: &str) -> Result<(&str, Option), ParseError> { +// Returns the length of the unqualified segment and the following char +// ('/', ';', or None) or an error. This only extracts the unqualified +// segment at the start of the given data, and ignores anything following. +#[inline(always)] +fn parse_unqualified_segment(data: &str) -> Result<(usize, Option), ParseError> { for (ix, c) in data.char_indices() { match c { '/' if ix == 0 => fail!("Unexpected '/' at start of unqualified segment"), ';' if ix == 0 => fail!("Unexpected ';' at start of unqualified segment"), - '/' | ';' => return Ok((&data[0..ix], Some(c))), + '/' | ';' => return Ok((ix, Some(c))), '.' | '[' | '<' | '>' => fail!("Disallowed character in unqualified segment"), _ => (), }; } - Ok((data, None)) + Ok((data.len(), None)) } /// Represents a valid binary class or interface name in the syntax of @@ -38,7 +39,7 @@ impl<'a> TryFrom> for ClassName<'a> { match parse_unqualified_segment(&value[index..])? { (_, None) => break, (_, Some(';')) => fail!("Disallowed ';' in class name"), - (segment, Some('/')) => index += segment.len() + 1, + (segment_len, Some('/')) => index += segment_len + 1, _ => panic!("Got unexpected return value from parse_unqualified_segment"), } } @@ -81,17 +82,15 @@ fn parse_class_descriptor<'a>( let mut next_index = index; loop { match parse_unqualified_segment(&data[next_index..])? { - (segment, Some(';')) => { + (segment_len, Some(';')) => { return Ok(ClassName(match data { - Cow::Borrowed(data) => { - Cow::Borrowed(&data[index..(next_index + segment.len())]) - } + Cow::Borrowed(data) => Cow::Borrowed(&data[index..(next_index + segment_len)]), Cow::Owned(data) => { - Cow::Owned(data[index..(next_index + segment.len())].to_string()) + Cow::Owned(data[index..(next_index + segment_len)].to_string()) } })) } - (segment, Some('/')) => next_index += segment.len() + 1, + (segment_len, Some('/')) => next_index += segment_len + 1, (_, None) => fail!("Unterminated unqualified segment"), _ => panic!("Got unexpected return value from parse_unqualified_segment"), } From 36e2eb715736f813e44adc796aaaa8accc4a1bf8 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 23 Jun 2025 08:18:01 -0400 Subject: [PATCH 2/2] Stop recomputing string length if no terminator was found --- src/descriptors.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/descriptors.rs b/src/descriptors.rs index aef4d8c..ab9e6c6 100644 --- a/src/descriptors.rs +++ b/src/descriptors.rs @@ -10,18 +10,19 @@ use crate::ParseError; // Returns the length of the unqualified segment and the following char // ('/', ';', or None) or an error. This only extracts the unqualified // segment at the start of the given data, and ignores anything following. +// Returns None if no unqualified segment terminator was found. #[inline(always)] -fn parse_unqualified_segment(data: &str) -> Result<(usize, Option), ParseError> { +fn parse_unqualified_segment(data: &str) -> Result, ParseError> { for (ix, c) in data.char_indices() { match c { '/' if ix == 0 => fail!("Unexpected '/' at start of unqualified segment"), ';' if ix == 0 => fail!("Unexpected ';' at start of unqualified segment"), - '/' | ';' => return Ok((ix, Some(c))), + '/' | ';' => return Ok(Some((ix, c))), '.' | '[' | '<' | '>' => fail!("Disallowed character in unqualified segment"), _ => (), }; } - Ok((data.len(), None)) + Ok(None) } /// Represents a valid binary class or interface name in the syntax of @@ -37,9 +38,9 @@ impl<'a> TryFrom> for ClassName<'a> { let mut index = 0; loop { match parse_unqualified_segment(&value[index..])? { - (_, None) => break, - (_, Some(';')) => fail!("Disallowed ';' in class name"), - (segment_len, Some('/')) => index += segment_len + 1, + None => break, + Some((_, ';')) => fail!("Disallowed ';' in class name"), + Some((segment_len, '/')) => index += segment_len + 1, _ => panic!("Got unexpected return value from parse_unqualified_segment"), } } @@ -82,7 +83,7 @@ fn parse_class_descriptor<'a>( let mut next_index = index; loop { match parse_unqualified_segment(&data[next_index..])? { - (segment_len, Some(';')) => { + Some((segment_len, ';')) => { return Ok(ClassName(match data { Cow::Borrowed(data) => Cow::Borrowed(&data[index..(next_index + segment_len)]), Cow::Owned(data) => { @@ -90,8 +91,8 @@ fn parse_class_descriptor<'a>( } })) } - (segment_len, Some('/')) => next_index += segment_len + 1, - (_, None) => fail!("Unterminated unqualified segment"), + Some((segment_len, '/')) => next_index += segment_len + 1, + None => fail!("Unterminated unqualified segment"), _ => panic!("Got unexpected return value from parse_unqualified_segment"), } }