use blake2::Blake2s256;
use sha2::{Digest, Sha256};
const LITERAL: char = '0';
const SHA256: char = '1';
const BLAKE2: char = '2';
#[derive(Debug, Clone)]
pub enum Label {
Literal(String),
Sha256(String),
Blake2(String),
}
impl Label {
pub fn literal(s: &str) -> Self {
Self::Literal(s.to_string())
}
pub fn sha256(data: &[u8]) -> Self {
let mut hasher = Sha256::new();
hasher.update(data);
let hash = hasher.finalize();
Self::Sha256(format!("{:x}", hash))
}
pub fn blake2(data: &[u8]) -> Self {
let mut hasher = Blake2s256::new();
hasher.update(data);
let hash = hasher.finalize();
Self::Sha256(format!("{:x}", hash))
}
pub fn serialize(&self) -> String {
match self {
Self::Literal(s) => format!("{}{}", LITERAL, s),
Self::Sha256(hash) => format!("{}{}", SHA256, hash),
Self::Blake2(hash) => format!("{}{}", BLAKE2, hash),
}
}
pub fn deserialize(s: &str) -> Result<Self, LabelError> {
if s.starts_with(LITERAL) {
Ok(Self::Literal(s[1..].to_string()))
} else if s.starts_with(SHA256) {
Ok(Self::Sha256(s[1..].to_string()))
} else {
Err(LabelError::UnknownType(s.to_string()))
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum LabelChecksumKind {
Blake2,
Sha256,
}
impl LabelChecksumKind {
pub fn from(s: &str) -> Result<Self, LabelError> {
if s == "sha256" {
Ok(Self::Sha256)
} else if s == "blake2" {
Ok(Self::Blake2)
} else {
Err(LabelError::UnknownType(s.to_string()))
}
}
pub fn serialize(self) -> &'static str {
match self {
Self::Sha256 => "sha256",
Self::Blake2 => "blake2",
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum LabelError {
#[error("Unknown label: {0:?}")]
UnknownType(String),
}
#[cfg(test)]
mod test {
use super::{Label, LabelChecksumKind};
#[test]
fn roundtrip_literal() {
let label = Label::literal("dummy data");
let serialized = label.serialize();
let de = Label::deserialize(&serialized).unwrap();
let seri2 = de.serialize();
assert_eq!(serialized, seri2);
}
#[test]
fn roundtrip_sha256() {
let label = Label::sha256(b"dummy data");
let serialized = label.serialize();
let de = Label::deserialize(&serialized).unwrap();
let seri2 = de.serialize();
assert_eq!(serialized, seri2);
}
#[test]
fn roundtrip_checksum_kind() {
for kind in [LabelChecksumKind::Sha256, LabelChecksumKind::Blake2] {
assert_eq!(LabelChecksumKind::from(kind.serialize()).unwrap(), kind);
}
}
}