feat(castore): implement FromStr for trait B3Digest

This provides a canonical way to parse a `B3Digest`, to be used in,
e.g., a CLI like `snix-castore`.

Change-Id: If6c7858c1fcd7645721002be7789f5ce2ff97a5c
Reviewed-on: https://cl.snix.dev/c/snix/+/30303
Reviewed-by: Florian Klink <flokli@flokli.de>
Tested-by: besadii
This commit is contained in:
Yvan Sraka 2025-04-07 10:59:14 +02:00
parent 5b81892ddf
commit f31ef707f8
2 changed files with 22 additions and 0 deletions

View file

@ -1,5 +1,6 @@
use bytes::Bytes;
use data_encoding::BASE64;
use std::str::FromStr;
use thiserror::Error;
#[derive(PartialEq, Eq, Hash)]
@ -15,6 +16,8 @@ impl B3Digest {
pub enum Error {
#[error("invalid digest length: {0}")]
InvalidDigestLen(usize),
#[error("invalid hash type: expected a 'blake3-' prefixed digest")]
InvalidHashType,
}
impl AsRef<[u8; B3Digest::LENGTH]> for B3Digest {
@ -109,3 +112,18 @@ impl std::fmt::Debug for B3Digest {
BASE64.encode_write(&self.0, f)
}
}
impl FromStr for B3Digest {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if !s.starts_with("blake3-") {
return Err(Error::InvalidHashType);
}
let encoded = &s[7..];
let decoded = BASE64
.decode(encoded.as_bytes())
.map_err(|_| Error::InvalidDigestLen(s.len()))?;
decoded.as_slice().try_into()
}
}

View file

@ -27,12 +27,16 @@ pub enum ValidateNodeError {
/// Invalid symlink target
#[error("Invalid symlink target: {0}")]
InvalidSymlinkTarget(SymlinkTargetError),
/// Invalid hash type encountered
#[error("invalid hash type: expected a 'blake3-' prefixed digest")]
InvalidHashType,
}
impl From<crate::digests::Error> for ValidateNodeError {
fn from(e: crate::digests::Error) -> Self {
match e {
crate::digests::Error::InvalidDigestLen(n) => ValidateNodeError::InvalidDigestLen(n),
crate::digests::Error::InvalidHashType => ValidateNodeError::InvalidHashType,
}
}
}