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)),
|
||||
.1,
|
||||
)]
|
||||
InvalidName(Vec<u8>, usize),
|
||||
InvalidName(Vec<u8>, u8),
|
||||
#[error("Tried to parse an absolute path which was missing the store dir prefix.")]
|
||||
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
|
||||
/// returns the name as string if successful.
|
||||
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());
|
||||
}
|
||||
|
||||
for (i, c) in s.iter().enumerate() {
|
||||
if c.is_ascii_alphanumeric()
|
||||
|| (*c == b'.' && i != 0) // can't start with a dot
|
||||
|| *c == b'-'
|
||||
|| *c == b'_'
|
||||
|| *c == b'+'
|
||||
|| *c == b'?'
|
||||
|| *c == b'='
|
||||
{
|
||||
continue;
|
||||
if s[0] == b'.' {
|
||||
return Err(Error::InvalidName(s.to_vec(), 0));
|
||||
}
|
||||
|
||||
let mut valid = true;
|
||||
for &c in s {
|
||||
valid = valid && NAME_CHARS[c as usize];
|
||||
}
|
||||
|
||||
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())
|
||||
|
|
Loading…
Reference in a new issue