Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

digest: Add AsRef<str> #229

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 deletions src/image/digest.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Functionality corresponding to <https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests>.

use std::fmt::{Display, Write};
use std::fmt::Display;
use std::str::FromStr;

/// A digest algorithm; at the current time only SHA-256
Expand Down Expand Up @@ -97,17 +97,25 @@ fn char_is_encoded(c: char) -> bool {

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Digest {
/// The algorithm
/// The algorithm; we need to hold a copy of this
/// right now as we ended up returning a reference
/// from the accessor. It probably would have been
/// better to have both borrowed/owned DigestAlgorithm
/// versions and our accessor just returns a borrowed version.
algorithm: DigestAlgorithm,
/// The digest value
digest: Box<str>,
value: Box<str>,
split: usize,
}

impl AsRef<str> for Digest {
fn as_ref(&self) -> &str {
&self.value
}
}

impl Display for Digest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.algorithm.as_ref())?;
f.write_char(':')?;
f.write_str(&self.digest)
f.write_str(self.as_ref())
}
}

Expand Down Expand Up @@ -143,7 +151,7 @@ impl Digest {
/// is guaranteed to be a valid length with only lowercase hexadecimal
/// characters. For example with SHA-256, the length is 64.
pub fn digest(&self) -> &str {
&self.digest
&self.value[self.split + 1..]
}
}

Expand All @@ -159,6 +167,7 @@ impl TryFrom<String> for Digest {
type Error = crate::OciSpecError;

fn try_from(s: String) -> Result<Self, Self::Error> {
let s = s.into_boxed_str();
let Some(split) = s.find(':') else {
return Err(crate::OciSpecError::Other("missing ':' in digest".into()));
};
Expand Down Expand Up @@ -204,8 +213,11 @@ impl TryFrom<String> for Digest {
)));
}
}
let digest = value.to_owned().into_boxed_str();
Ok(Self { algorithm, digest })
Ok(Self {
algorithm,
value: s,
split,
})
}
}

Expand All @@ -227,7 +239,8 @@ impl From<Sha256Digest> for Digest {
fn from(value: Sha256Digest) -> Self {
Self {
algorithm: DigestAlgorithm::Sha256,
digest: value.digest,
value: format!("sha256:{}", value.digest()).into(),
split: 6,
}
}
}
Expand All @@ -252,7 +265,9 @@ impl FromStr for Sha256Digest {
let v = format!("{alg}:{digest}");
let d = Digest::from_str(&v)?;
match d.algorithm {
DigestAlgorithm::Sha256 => Ok(Self { digest: d.digest }),
DigestAlgorithm::Sha256 => Ok(Self {
digest: d.digest().into(),
}),
o => Err(crate::OciSpecError::Other(format!(
"Expected algorithm sha256 but found {o}",
))),
Expand Down Expand Up @@ -334,6 +349,8 @@ mod tests {
let d = Digest::from_str(VALID_DIGEST_SHA384).unwrap();
assert_eq!(d.algorithm(), &DigestAlgorithm::Sha384);
assert_eq!(d.digest(), expected_value);
// Verify we can cheaply coerce to a string
assert_eq!(d.as_ref(), VALID_DIGEST_SHA384);
let base_digest = Digest::from(d.clone());
assert_eq!(base_digest.digest(), expected_value);
}
Expand Down
Loading