feat(tvix/nix-compat/narinfo): don't allocate error field names

We know these names statically, so we can just use &'static str.

Change-Id: I81cb7ecc4d7553f57baca74464c120a143586fe6
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12941
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
This commit is contained in:
edef 2025-01-01 15:49:34 +00:00
parent 54f72afcda
commit bee52c2579

View file

@ -90,6 +90,19 @@ bitflags! {
} }
} }
const TAG_STOREPATH: &str = "StorePath";
const TAG_URL: &str = "URL";
const TAG_COMPRESSION: &str = "Compression";
const TAG_FILEHASH: &str = "FileHash";
const TAG_FILESIZE: &str = "FileSize";
const TAG_NARHASH: &str = "NarHash";
const TAG_NARSIZE: &str = "NarSize";
const TAG_REFERENCES: &str = "References";
const TAG_SYSTEM: &str = "System";
const TAG_DERIVER: &str = "Deriver";
const TAG_SIG: &str = "Sig";
const TAG_CA: &str = "CA";
impl<'a> NarInfo<'a> { impl<'a> NarInfo<'a> {
pub fn parse(input: &'a str) -> Result<Self, Error> { pub fn parse(input: &'a str) -> Result<Self, Error> {
let mut flags = Flags::empty(); let mut flags = Flags::empty();
@ -116,7 +129,7 @@ impl<'a> NarInfo<'a> {
.ok_or_else(|| Error::InvalidLine(line.to_string()))?; .ok_or_else(|| Error::InvalidLine(line.to_string()))?;
match tag { match tag {
"StorePath" => { TAG_STOREPATH => {
let val = val let val = val
.strip_prefix("/nix/store/") .strip_prefix("/nix/store/")
.ok_or(Error::InvalidStorePath( .ok_or(Error::InvalidStorePath(
@ -126,51 +139,51 @@ impl<'a> NarInfo<'a> {
.map_err(Error::InvalidStorePath)?; .map_err(Error::InvalidStorePath)?;
if store_path.replace(val).is_some() { if store_path.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_STOREPATH));
} }
} }
"URL" => { TAG_URL => {
if val.is_empty() { if val.is_empty() {
return Err(Error::EmptyField(tag.to_string())); return Err(Error::EmptyField(TAG_URL));
} }
if url.replace(val).is_some() { if url.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_URL));
} }
} }
"Compression" => { TAG_COMPRESSION => {
if val.is_empty() { if val.is_empty() {
return Err(Error::EmptyField(tag.to_string())); return Err(Error::EmptyField(TAG_COMPRESSION));
} }
if compression.replace(val).is_some() { if compression.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_COMPRESSION));
} }
} }
"FileHash" => { TAG_FILEHASH => {
let val = val let val = val
.strip_prefix("sha256:") .strip_prefix("sha256:")
.ok_or_else(|| Error::MissingPrefixForHash(tag.to_string()))?; .ok_or(Error::MissingPrefixForHash(TAG_FILEHASH))?;
let val = nixbase32::decode_fixed::<32>(val) let val = nixbase32::decode_fixed::<32>(val)
.map_err(|e| Error::UnableToDecodeHash(tag.to_string(), e))?; .map_err(|e| Error::UnableToDecodeHash(TAG_FILEHASH, e))?;
if file_hash.replace(val).is_some() { if file_hash.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_FILEHASH));
} }
} }
"FileSize" => { TAG_FILESIZE => {
let val = val let val = val
.parse::<u64>() .parse::<u64>()
.map_err(|_| Error::UnableToParseSize(tag.to_string(), val.to_string()))?; .map_err(|_| Error::UnableToParseSize(TAG_FILESIZE, val.to_string()))?;
if file_size.replace(val).is_some() { if file_size.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_FILESIZE));
} }
} }
"NarHash" => { TAG_NARHASH => {
let val = val let val = val
.strip_prefix("sha256:") .strip_prefix("sha256:")
.ok_or_else(|| Error::MissingPrefixForHash(tag.to_string()))?; .ok_or(Error::MissingPrefixForHash(TAG_NARHASH))?;
let val = if val.len() != HEXLOWER.encode_len(32) { let val = if val.len() != HEXLOWER.encode_len(32) {
nixbase32::decode_fixed::<32>(val) nixbase32::decode_fixed::<32>(val)
@ -186,22 +199,22 @@ impl<'a> NarInfo<'a> {
.map(|_| buf) .map(|_| buf)
}; };
let val = val.map_err(|e| Error::UnableToDecodeHash(tag.to_string(), e))?; let val = val.map_err(|e| Error::UnableToDecodeHash(TAG_NARHASH, e))?;
if nar_hash.replace(val).is_some() { if nar_hash.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_NARHASH));
} }
} }
"NarSize" => { TAG_NARSIZE => {
let val = val let val = val
.parse::<u64>() .parse::<u64>()
.map_err(|_| Error::UnableToParseSize(tag.to_string(), val.to_string()))?; .map_err(|_| Error::UnableToParseSize(TAG_NARSIZE, val.to_string()))?;
if nar_size.replace(val).is_some() { if nar_size.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_NARSIZE));
} }
} }
"References" => { TAG_REFERENCES => {
let val: Vec<StorePathRef> = if !val.is_empty() { let val: Vec<StorePathRef> = if !val.is_empty() {
let mut prev = ""; let mut prev = "";
val.split(' ') val.split(' ')
@ -221,26 +234,26 @@ impl<'a> NarInfo<'a> {
}; };
if references.replace(val).is_some() { if references.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_REFERENCES));
} }
} }
"System" => { TAG_SYSTEM => {
if val.is_empty() { if val.is_empty() {
return Err(Error::EmptyField(tag.to_string())); return Err(Error::EmptyField(TAG_SYSTEM));
} }
if system.replace(val).is_some() { if system.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_SYSTEM));
} }
} }
"Deriver" => { TAG_DERIVER => {
match val.strip_suffix(".drv") { match val.strip_suffix(".drv") {
Some(val) => { Some(val) => {
let val = StorePathRef::from_bytes(val.as_bytes()) let val = StorePathRef::from_bytes(val.as_bytes())
.map_err(Error::InvalidDeriverStorePath)?; .map_err(Error::InvalidDeriverStorePath)?;
if deriver.replace(val).is_some() { if deriver.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_DERIVER));
} }
} }
None => { None => {
@ -252,18 +265,18 @@ impl<'a> NarInfo<'a> {
} }
}; };
} }
"Sig" => { TAG_SIG => {
let val = SignatureRef::parse(val) let val = SignatureRef::parse(val)
.map_err(|e| Error::UnableToParseSignature(signatures.len(), e))?; .map_err(|e| Error::UnableToParseSignature(signatures.len(), e))?;
signatures.push(val); signatures.push(val);
} }
"CA" => { TAG_CA => {
let val = CAHash::from_nix_hex_str(val) let val = CAHash::from_nix_hex_str(val)
.ok_or_else(|| Error::UnableToParseCA(val.to_string()))?; .ok_or_else(|| Error::UnableToParseCA(val.to_string()))?;
if ca.replace(val).is_some() { if ca.replace(val).is_some() {
return Err(Error::DuplicateField(tag.to_string())); return Err(Error::DuplicateField(TAG_CA));
} }
} }
_ => { _ => {
@ -376,7 +389,7 @@ impl Display for NarInfo<'_> {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("duplicate field: {0}")] #[error("duplicate field: {0}")]
DuplicateField(String), DuplicateField(&'static str),
#[error("missing field: {0}")] #[error("missing field: {0}")]
MissingField(&'static str), MissingField(&'static str),
@ -388,10 +401,10 @@ pub enum Error {
InvalidStorePath(crate::store_path::Error), InvalidStorePath(crate::store_path::Error),
#[error("field {0} may not be empty string")] #[error("field {0} may not be empty string")]
EmptyField(String), EmptyField(&'static str),
#[error("invalid {0}: {1}")] #[error("invalid {0}: {1}")]
UnableToParseSize(String, String), UnableToParseSize(&'static str, String),
#[error("unable to parse #{0} reference: {1}")] #[error("unable to parse #{0} reference: {1}")]
InvalidReference(usize, crate::store_path::Error), InvalidReference(usize, crate::store_path::Error),
@ -403,10 +416,10 @@ pub enum Error {
InvalidDeriverStorePathMissingSuffix, InvalidDeriverStorePathMissingSuffix,
#[error("missing prefix for {0}")] #[error("missing prefix for {0}")]
MissingPrefixForHash(String), MissingPrefixForHash(&'static str),
#[error("unable to decode {0}: {1}")] #[error("unable to decode {0}: {1}")]
UnableToDecodeHash(String, data_encoding::DecodeError), UnableToDecodeHash(&'static str, data_encoding::DecodeError),
#[error("unable to parse signature #{0}: {1}")] #[error("unable to parse signature #{0}: {1}")]
UnableToParseSignature(usize, SignatureError), UnableToParseSignature(usize, SignatureError),