mirror of https://github.com/astral-sh/uv
Skip unquote allocation for non-quoted strings (#11813)
## Summary Small optimization: no need to unquote if there aren't any quote characters.
This commit is contained in:
parent
a439b7944d
commit
f9497432dc
|
|
@ -5531,6 +5531,7 @@ dependencies = [
|
|||
"indoc",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"memchr",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest-middleware",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ uv-pypi-types = { workspace = true }
|
|||
uv-warnings = { workspace = true }
|
||||
|
||||
fs-err = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
reqwest = { workspace = true, optional = true }
|
||||
reqwest-middleware = { workspace = true, optional = true }
|
||||
thiserror = { workspace = true }
|
||||
|
|
@ -43,6 +43,7 @@ assert_fs = { version = "1.1.2" }
|
|||
indoc = { workspace = true }
|
||||
insta = { version = "1.40.0", features = ["filters"] }
|
||||
itertools = { version = "0.14.0" }
|
||||
regex = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
test-case = { version = "3.3.1" }
|
||||
tokio = { version = "1.40.0" }
|
||||
|
|
|
|||
|
|
@ -523,7 +523,10 @@ fn parse_entry(
|
|||
let start = s.cursor();
|
||||
Ok(Some(if s.eat_if("-r") || s.eat_if("--requirement") {
|
||||
let filename = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let filename = unquote(filename).unwrap_or_else(|_| filename.to_string());
|
||||
let filename = unquote(filename)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(|| filename.to_string());
|
||||
let end = s.cursor();
|
||||
RequirementsTxtStatement::Requirements {
|
||||
filename,
|
||||
|
|
@ -532,7 +535,10 @@ fn parse_entry(
|
|||
}
|
||||
} else if s.eat_if("-c") || s.eat_if("--constraint") {
|
||||
let filename = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let filename = unquote(filename).unwrap_or_else(|_| filename.to_string());
|
||||
let filename = unquote(filename)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(|| filename.to_string());
|
||||
let end = s.cursor();
|
||||
RequirementsTxtStatement::Constraint {
|
||||
filename,
|
||||
|
|
@ -577,6 +583,8 @@ fn parse_entry(
|
|||
} else if s.eat_if("-i") || s.eat_if("--index-url") {
|
||||
let given = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let given = unquote(given)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(given));
|
||||
let expanded = expand_env_vars(given.as_ref());
|
||||
|
|
@ -606,6 +614,8 @@ fn parse_entry(
|
|||
} else if s.eat_if("--extra-index-url") {
|
||||
let given = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let given = unquote(given)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(given));
|
||||
let expanded = expand_env_vars(given.as_ref());
|
||||
|
|
@ -637,6 +647,8 @@ fn parse_entry(
|
|||
} else if s.eat_if("--find-links") || s.eat_if("-f") {
|
||||
let given = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let given = unquote(given)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(given));
|
||||
let expanded = expand_env_vars(given.as_ref());
|
||||
|
|
@ -666,6 +678,8 @@ fn parse_entry(
|
|||
} else if s.eat_if("--no-binary") {
|
||||
let given = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let given = unquote(given)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(given));
|
||||
let specifier = PackageNameSpecifier::from_str(given.as_ref()).map_err(|err| {
|
||||
|
|
@ -680,6 +694,8 @@ fn parse_entry(
|
|||
} else if s.eat_if("--only-binary") {
|
||||
let given = parse_value(content, s, |c: char| !is_terminal(c))?;
|
||||
let given = unquote(given)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(given));
|
||||
let specifier = PackageNameSpecifier::from_str(given.as_ref()).map_err(|err| {
|
||||
|
|
|
|||
|
|
@ -142,12 +142,20 @@ fn unquote_open_escape(acc: &mut String, cursor: &mut std::iter::Enumerate<std::
|
|||
///
|
||||
/// The result is canonical. There is only one valid unquoted result for a given input.
|
||||
///
|
||||
/// If the string does not require any quoting or escaping, returns `Ok(None)`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(r_shquote::unquote("foobar").unwrap(), "foobar");
|
||||
/// ```
|
||||
pub(crate) fn unquote(source: &str) -> Result<String, UnquoteError> {
|
||||
pub(crate) fn unquote(source: &str) -> Result<Option<String>, UnquoteError> {
|
||||
// If the string does not contain any single-quotes, double-quotes, or escape sequences, it
|
||||
// does not require any unquoting.
|
||||
if memchr::memchr3(b'\'', b'"', b'\\', source.as_bytes()).is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// An unquote-operation never results in a longer string. Furthermore, the common case is
|
||||
// most of the string is unquoted / unescaped. Hence, we simply allocate the same space
|
||||
// for the resulting string as the input.
|
||||
|
|
@ -182,7 +190,7 @@ pub(crate) fn unquote(source: &str) -> Result<String, UnquoteError> {
|
|||
acc.push(next_ch);
|
||||
}
|
||||
None => {
|
||||
break Ok(acc);
|
||||
break Ok(Some(acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -194,10 +202,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn basic() {
|
||||
assert_eq!(unquote("foobar").unwrap(), "foobar");
|
||||
assert_eq!(unquote("foo'bar'").unwrap(), "foobar");
|
||||
assert_eq!(unquote("foo\"bar\"").unwrap(), "foobar");
|
||||
assert_eq!(unquote("\\foobar\\").unwrap(), "foobar");
|
||||
assert_eq!(unquote("\\'foobar\\'").unwrap(), "'foobar'");
|
||||
assert_eq!(unquote("foobar").unwrap(), None);
|
||||
assert_eq!(unquote("foo'bar'").unwrap().unwrap(), "foobar");
|
||||
assert_eq!(unquote("foo\"bar\"").unwrap().unwrap(), "foobar");
|
||||
assert_eq!(unquote("\\foobar\\").unwrap().unwrap(), "foobar");
|
||||
assert_eq!(unquote("\\'foobar\\'").unwrap().unwrap(), "'foobar'");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue