use semver::Version;
const PREFIX: &str = "<!-- Installed by provenance ";
const HASH_PREFIX: &str = "; content hash fnv1a64:";
const SUFFIX: &str = " -->";
const HASH_LENGTH: usize = 16;
pub fn header(content: &str) -> String {
format!(
"{PREFIX}{}{HASH_PREFIX}{}{SUFFIX}",
env!("CARGO_PKG_VERSION"),
fnv1a64(content)
)
}
#[derive(Debug, PartialEq, Eq)]
pub struct SkillStamp<'a> {
pub version: Version,
pub hash: &'a str,
}
pub fn parse_header(header: &str) -> Option<SkillStamp<'_>> {
let header = header.strip_prefix(PREFIX)?;
let (version, hash) = header.split_once(HASH_PREFIX)?;
let hash = hash.strip_suffix(SUFFIX)?;
let version = Version::parse(version).ok()?;
(hash.len() == HASH_LENGTH
&& hash
.bytes()
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)))
.then_some(SkillStamp { version, hash })
}
pub fn header_hash(header: &str) -> Option<&str> {
parse_header(header).map(|stamp| stamp.hash)
}
pub fn fnv1a64(content: &str) -> String {
let mut hash = 0xcbf2_9ce4_8422_2325_u64;
for byte in content.as_bytes() {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
format!("{hash:016x}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_reader_takes_back_apart_what_the_writer_wrote() {
for content in ["", "---\nname: old\n---\npayload\n", "é 日本語\r\n"] {
let stamp = header(content);
assert_eq!(header_hash(&stamp), Some(fnv1a64(content).as_str()));
}
}
#[test]
fn the_stamp_keeps_its_published_shape() {
assert_eq!(
header("payload\n"),
format!(
"<!-- Installed by provenance {}; content hash fnv1a64:acb27c196e1c811d -->",
env!("CARGO_PKG_VERSION")
)
);
}
}