From e9444d8a8a17c189558b15124284bc034b825cae Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 6 Feb 2025 18:23:15 -0500 Subject: [PATCH 1/3] Benchmark --- url/benches/parse_url.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/url/benches/parse_url.rs b/url/benches/parse_url.rs index ace1f47a..61e88162 100644 --- a/url/benches/parse_url.rs +++ b/url/benches/parse_url.rs @@ -33,6 +33,13 @@ fn plain(bench: &mut Bencher) { bench.iter(|| black_box(url).parse::().unwrap()); } +fn port(bench: &mut Bencher) { + let url = "https://example.com:8080"; + + bench.bytes = url.len() as u64; + bench.iter(|| black_box(url).parse::().unwrap()); +} + fn hyphen(bench: &mut Bencher) { let url = "https://hyphenated-example.com/"; @@ -95,6 +102,7 @@ benchmark_group!( long, fragment, plain, + port, hyphen, leading_digit, unicode_mixed, From 2042187734fc4e517b1c83442ef89508b4d6bc97 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 6 Feb 2025 18:40:43 -0500 Subject: [PATCH 2/3] add fast u16 to str --- url/src/parser.rs | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/url/src/parser.rs b/url/src/parser.rs index b89b8f32..1d672030 100644 --- a/url/src/parser.rs +++ b/url/src/parser.rs @@ -970,13 +970,17 @@ impl<'a> Parser<'a> { let (port, remaining) = if let Some(remaining) = remaining.split_prefix(':') { let scheme = || default_port(&self.serialization[..scheme_end as usize]); - Parser::parse_port(remaining, scheme, self.context)? + let (port, remaining) = Parser::parse_port(remaining, scheme, self.context)?; + if let Some(port) = port { + self.serialization.push(':'); + let mut buffer = [0u8; 5]; + let port_str = fast_u16_to_str(&mut buffer, port); + self.serialization.push_str(port_str); + } + (port, remaining) } else { (None, remaining) }; - if let Some(port) = port { - write!(&mut self.serialization, ":{}", port).unwrap() - } Ok((host_end, host.into(), port, remaining)) } @@ -1744,3 +1748,25 @@ fn starts_with_windows_drive_letter_segment(input: &Input<'_>) -> bool { _ => false, } } + +#[inline] +fn fast_u16_to_str( + // max 5 digits for u16 (65535) + buffer: &mut [u8; 5], + mut value: u16, +) -> &str { + let mut index = buffer.len(); + + loop { + index -= 1; + buffer[index] = b'0' + (value % 10) as u8; + value /= 10; + if value == 0 { + break; + } + } + + // SAFETY: we know the values in the buffer from the + // current index on will be a number + unsafe { std::str::from_utf8_unchecked(&buffer[index..]) } +} From b1921c048182c7c6cb649a49fd7769094d79b3b1 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 6 Feb 2025 18:43:58 -0500 Subject: [PATCH 3/3] fix no-std --- url/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/url/src/parser.rs b/url/src/parser.rs index 1d672030..1ab0dc1d 100644 --- a/url/src/parser.rs +++ b/url/src/parser.rs @@ -1768,5 +1768,5 @@ fn fast_u16_to_str( // SAFETY: we know the values in the buffer from the // current index on will be a number - unsafe { std::str::from_utf8_unchecked(&buffer[index..]) } + unsafe { core::str::from_utf8_unchecked(&buffer[index..]) } }