use std::fmt;
use sha2::{Digest, Sha256};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Unit {
Word,
Bit,
Line,
}
impl fmt::Display for Unit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Unit::Word => "word",
Unit::Bit => "bit",
Unit::Line => "line",
})
}
}
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
#[error("{bytecode} at {unit} {at}: {detail}")]
pub struct Refusal {
pub bytecode: &'static str,
pub unit: Unit,
pub at: usize,
pub detail: String,
}
impl Refusal {
pub fn new(bytecode: &'static str, unit: Unit, at: usize, detail: impl Into<String>) -> Self {
Self {
bytecode,
unit,
at,
detail: detail.into(),
}
}
pub fn reason(&self) -> &str {
&self.detail
}
pub fn group(&self) -> String {
let mut out = String::with_capacity(self.detail.len());
let mut digits = false;
for c in self.detail.chars() {
if c.is_ascii_digit() {
if !digits {
out.push('N');
}
digits = true;
} else {
out.push(c);
digits = false;
}
}
out
}
}
pub fn source_hash(bytes: &[u8]) -> String {
let digest = Sha256::digest(bytes);
let mut out = String::from("sha256:");
for byte in digest {
out.push_str(&format!("{byte:02x}"));
}
out
}