refactor(nix-compat/store_path): speed up validate_name fast path
Change-Id: Ie50b29145804777f7644952c65cb42519a8565e3 Reviewed-on: https://cl.tvl.fyi/c/depot/+/9859 Reviewed-by: flokli <flokli@flokli.de> Tested-by: BuildkiteCI
This commit is contained in:
parent
c19c6c23cb
commit
520c5a191e
1 changed files with 39 additions and 12 deletions
|
@ -38,7 +38,7 @@ pub enum Error {
|
||||||
std::str::from_utf8(.0).unwrap_or(&BASE64.encode(.0)),
|
std::str::from_utf8(.0).unwrap_or(&BASE64.encode(.0)),
|
||||||
.1,
|
.1,
|
||||||
)]
|
)]
|
||||||
InvalidName(Vec<u8>, usize),
|
InvalidName(Vec<u8>, u8),
|
||||||
#[error("Tried to parse an absolute path which was missing the store dir prefix.")]
|
#[error("Tried to parse an absolute path which was missing the store dir prefix.")]
|
||||||
MissingStoreDir(),
|
MissingStoreDir(),
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,29 @@ impl StorePath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NAME_CHARS contains `true` for bytes that are valid in store path names,
|
||||||
|
/// not accounting for '.' being permitted only past the first character.
|
||||||
|
static NAME_CHARS: [bool; 256] = {
|
||||||
|
let mut tbl = [false; 256];
|
||||||
|
let mut c = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tbl[c as usize] = match c {
|
||||||
|
b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => true,
|
||||||
|
b'+' | b'-' | b'_' | b'?' | b'=' | b'.' => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if c == u8::MAX {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl
|
||||||
|
};
|
||||||
|
|
||||||
/// Checks a given &[u8] to match the restrictions for [StorePath::name], and
|
/// Checks a given &[u8] to match the restrictions for [StorePath::name], and
|
||||||
/// returns the name as string if successful.
|
/// returns the name as string if successful.
|
||||||
pub(crate) fn validate_name(s: &(impl AsRef<[u8]> + ?Sized)) -> Result<&str, Error> {
|
pub(crate) fn validate_name(s: &(impl AsRef<[u8]> + ?Sized)) -> Result<&str, Error> {
|
||||||
|
@ -185,19 +208,23 @@ pub(crate) fn validate_name(s: &(impl AsRef<[u8]> + ?Sized)) -> Result<&str, Err
|
||||||
return Err(Error::InvalidLength());
|
return Err(Error::InvalidLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, c) in s.iter().enumerate() {
|
if s[0] == b'.' {
|
||||||
if c.is_ascii_alphanumeric()
|
return Err(Error::InvalidName(s.to_vec(), 0));
|
||||||
|| (*c == b'.' && i != 0) // can't start with a dot
|
}
|
||||||
|| *c == b'-'
|
|
||||||
|| *c == b'_'
|
let mut valid = true;
|
||||||
|| *c == b'+'
|
for &c in s {
|
||||||
|| *c == b'?'
|
valid = valid && NAME_CHARS[c as usize];
|
||||||
|| *c == b'='
|
}
|
||||||
{
|
|
||||||
continue;
|
if !valid {
|
||||||
|
for (i, &c) in s.iter().enumerate() {
|
||||||
|
if !NAME_CHARS[c as usize] {
|
||||||
|
return Err(Error::InvalidName(s.to_vec(), i as u8));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(Error::InvalidName(s.to_vec(), i));
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(str::from_utf8(s).unwrap())
|
Ok(str::from_utf8(s).unwrap())
|
||||||
|
|
Loading…
Add table
Reference in a new issue