Skip to content

Commit 85cc156

Browse files
committed
optimizations in URL implementation
1 parent 1e1c962 commit 85cc156

File tree

2 files changed

+26
-36
lines changed

2 files changed

+26
-36
lines changed

src/url.rs

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::borrow::Cow;
22
use std::collections::hash_map::DefaultHasher;
33
use std::fmt;
4-
use std::fmt::Formatter;
4+
use std::fmt::{Formatter, Write};
55
use std::hash::{Hash, Hasher};
66
use std::sync::OnceLock;
77

88
use idna::punycode::decode_to_string;
99
use jiter::{PartialMode, StringCacheMode};
10-
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
10+
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
1111
use pyo3::exceptions::PyValueError;
1212
use pyo3::pyclass::CompareOp;
1313
use pyo3::sync::OnceLockExt;
@@ -360,53 +360,49 @@ impl PyMultiHostUrl {
360360
let host_offset = scheme.len() + 3;
361361

362362
let mut full_url = self.ref_url.unicode_string(py).into_owned();
363-
full_url.insert(host_offset, ',');
363+
let mut extra_hosts = String::new();
364364

365365
// special urls will have had a trailing slash added, non-special urls will not
366366
// hence we need to remove the last char if the scheme is special
367367
#[allow(clippy::bool_to_int_with_if)]
368368
let sub = if scheme_is_special(scheme) { 1 } else { 0 };
369369

370-
let hosts = extra_urls
371-
.iter()
372-
.map(|url| {
373-
let str = unicode_url(url.as_str(), url);
374-
str[host_offset..str.len() - sub].to_string()
375-
})
376-
.collect::<Vec<String>>()
377-
.join(",");
378-
full_url.insert_str(host_offset, &hosts);
370+
for url in extra_urls {
371+
let str = unicode_url(url.as_str(), url);
372+
extra_hosts.push_str(&str[host_offset..str.len() - sub]);
373+
extra_hosts.push(',');
374+
}
375+
376+
full_url.insert_str(host_offset, &extra_hosts);
379377
Cow::Owned(full_url)
380378
} else {
381379
self.ref_url.unicode_string(py)
382380
}
383381
}
384382

385-
pub fn __str__(&self, py: Python<'_>) -> String {
383+
pub fn __str__(&self, py: Python<'_>) -> Cow<'_, str> {
386384
if let Some(extra_urls) = &self.extra_urls {
387385
let scheme = self.ref_url.lib_url.scheme();
388386
let host_offset = scheme.len() + 3;
389387

390388
let mut full_url = self.ref_url.serialized(py).to_string();
391-
full_url.insert(host_offset, ',');
389+
let mut extra_hosts = String::new();
392390

393391
// special urls will have had a trailing slash added, non-special urls will not
394392
// hence we need to remove the last char if the scheme is special
395393
#[allow(clippy::bool_to_int_with_if)]
396394
let sub = if scheme_is_special(scheme) { 1 } else { 0 };
397395

398-
let hosts = extra_urls
399-
.iter()
400-
.map(|url| {
401-
let str = url.as_str();
402-
&str[host_offset..str.len() - sub]
403-
})
404-
.collect::<Vec<&str>>()
405-
.join(",");
406-
full_url.insert_str(host_offset, &hosts);
407-
full_url
396+
for url in extra_urls {
397+
let str = url.as_str();
398+
extra_hosts.push_str(&str[host_offset..str.len() - sub]);
399+
extra_hosts.push(',');
400+
}
401+
402+
full_url.insert_str(host_offset, &extra_hosts);
403+
Cow::Owned(full_url)
408404
} else {
409-
self.ref_url.__str__(py).to_string()
405+
Cow::Borrowed(self.ref_url.__str__(py))
410406
}
411407
}
412408

@@ -439,7 +435,7 @@ impl PyMultiHostUrl {
439435
self.clone().into_py_any(py)
440436
}
441437

442-
fn __getnewargs__(&self, py: Python<'_>) -> (String,) {
438+
fn __getnewargs__(&self, py: Python<'_>) -> (Cow<'_, str>,) {
443439
(self.__str__(py),)
444440
}
445441

@@ -474,7 +470,7 @@ impl PyMultiHostUrl {
474470
"expected one of 'host', 'username', 'password' or 'port' to be set",
475471
));
476472
}
477-
multi_url.push_str(&single_host.to_string());
473+
write!(multi_url, "{single_host}").expect("string formatting never fails");
478474
if index != hosts.len() - 1 {
479475
multi_url.push(',');
480476
}
@@ -602,13 +598,8 @@ fn is_punnycode_domain(lib_url: &Url, domain: &str) -> bool {
602598
scheme_is_special(lib_url.scheme()) && domain.split('.').any(|part| part.starts_with(PUNYCODE_PREFIX))
603599
}
604600

605-
fn encode_userinfo_component(value: &str) -> Cow<'_, str> {
606-
let encoded = percent_encode(value.as_bytes(), NON_ALPHANUMERIC).to_string();
607-
if encoded == value {
608-
Cow::Borrowed(value)
609-
} else {
610-
Cow::Owned(encoded)
611-
}
601+
fn encode_userinfo_component(value: &str) -> impl fmt::Display + use<'_> {
602+
utf8_percent_encode(value, NON_ALPHANUMERIC)
612603
}
613604
// based on https://github.com/servo/rust-url/blob/1c1e406874b3d2aa6f36c5d2f3a5c2ea74af9efb/url/src/parser.rs#L161-L167
614605
pub fn scheme_is_special(scheme: &str) -> bool {

src/validators/url.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::borrow::Cow;
21
use std::cell::RefCell;
32
use std::iter::Peekable;
43
use std::str::Chars;
@@ -214,7 +213,7 @@ impl UrlValidator {
214213

215214
let either_str_owned;
216215
let url_str = if let Some(multi_host_url) = downcast_python_input::<PyMultiHostUrl>(input) {
217-
Cow::Owned(multi_host_url.get().__str__(py))
216+
multi_host_url.get().__str__(py)
218217
} else if let Ok(either_str) = input.validate_str(strict, false).map(ValidationMatch::into_inner) {
219218
either_str_owned = either_str; // to extend the lifetime outside the if let
220219
either_str_owned.as_cow()?

0 commit comments

Comments
 (0)