Return Cow from UrlString::with_ methods (#14319)

A minor performance improvement as a follow-up to #14245 (and an
accompanying test).
This commit is contained in:
John Mumm 2025-06-27 19:54:52 +02:00 committed by GitHub
parent 74468dac15
commit f892b8564f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 24 deletions

View file

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
@ -160,27 +161,22 @@ impl UrlString {
.unwrap_or(self.as_ref()) .unwrap_or(self.as_ref())
} }
/// Return the [`UrlString`] with any fragments removed. /// Return the [`UrlString`] (as a [`Cow`]) with any fragments removed.
#[must_use] #[must_use]
pub fn without_fragment(&self) -> Self { pub fn without_fragment(&self) -> Cow<'_, Self> {
Self( self.as_ref()
self.as_ref() .split_once('#')
.split_once('#') .map(|(path, _)| Cow::Owned(UrlString(SmallString::from(path))))
.map(|(path, _)| path) .unwrap_or(Cow::Borrowed(self))
.map(SmallString::from)
.unwrap_or_else(|| self.0.clone()),
)
} }
/// Return the [`UrlString`] with trailing slash removed. /// Return the [`UrlString`] (as a [`Cow`]) with trailing slash removed.
#[must_use] #[must_use]
pub fn without_trailing_slash(&self) -> Self { pub fn without_trailing_slash(&self) -> Cow<'_, Self> {
Self( self.as_ref()
self.as_ref() .strip_suffix('/')
.strip_suffix('/') .map(|path| Cow::Owned(UrlString(SmallString::from(path))))
.map(SmallString::from) .unwrap_or(Cow::Borrowed(self))
.unwrap_or_else(|| self.0.clone()),
)
} }
} }
@ -263,16 +259,29 @@ mod tests {
#[test] #[test]
fn without_fragment() { fn without_fragment() {
// Borrows a URL without a fragment
let url = UrlString("https://example.com/path".into());
assert_eq!(url.without_fragment(), Cow::Borrowed(&url));
// Removes the fragment if present on the URL
let url = UrlString("https://example.com/path?query#fragment".into()); let url = UrlString("https://example.com/path?query#fragment".into());
assert_eq!( assert_eq!(
url.without_fragment(), url.without_fragment(),
UrlString("https://example.com/path?query".into()) Cow::Owned(UrlString("https://example.com/path?query".into()))
); );
}
let url = UrlString("https://example.com/path#fragment".into()); #[test]
assert_eq!(url.base_str(), "https://example.com/path"); fn without_trailing_slash() {
// Borrows a URL without a slash
let url = UrlString("https://example.com/path".into()); let url = UrlString("https://example.com/path".into());
assert_eq!(url.base_str(), "https://example.com/path"); assert_eq!(url.without_trailing_slash(), Cow::Borrowed(&url));
// Removes the trailing slash if present on the URL
let url = UrlString("https://example.com/path/".into());
assert_eq!(
url.without_trailing_slash(),
Cow::Owned(UrlString("https://example.com/path".into()))
);
} }
} }

View file

@ -1490,7 +1490,11 @@ impl Lock {
.version .version
.as_ref() .as_ref()
.expect("version for registry source"); .expect("version for registry source");
return Ok(SatisfiesResult::MissingRemoteIndex(name, version, url)); return Ok(SatisfiesResult::MissingRemoteIndex(
name,
version,
url.into_owned(),
));
} }
} }
RegistrySource::Path(path) => { RegistrySource::Path(path) => {
@ -4692,7 +4696,7 @@ impl From<Hash> for Hashes {
/// Convert a [`FileLocation`] into a normalized [`UrlString`]. /// Convert a [`FileLocation`] into a normalized [`UrlString`].
fn normalize_file_location(location: &FileLocation) -> Result<UrlString, ToUrlError> { fn normalize_file_location(location: &FileLocation) -> Result<UrlString, ToUrlError> {
match location { match location {
FileLocation::AbsoluteUrl(absolute) => Ok(absolute.without_fragment()), FileLocation::AbsoluteUrl(absolute) => Ok(absolute.without_fragment().into_owned()),
FileLocation::RelativeUrl(_, _) => Ok(normalize_url(location.to_url()?)), FileLocation::RelativeUrl(_, _) => Ok(normalize_url(location.to_url()?)),
} }
} }