use std::path::{Path, PathBuf};
use crate::snap::Snapshot;
use crate::{EncodingSnapshot, Fingerprint, MechanismSnapshot, Tier};
pub mod cybergraph;
pub mod hemera;
pub mod nebu;
pub mod nox;
pub mod tade;
pub mod zheng;
pub const TIER: Tier = Tier::Gamma;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Fixtures {
Committed,
Fresh,
}
#[derive(Debug, Clone)]
pub struct Context {
pub stack: PathBuf,
pub conformance: PathBuf,
pub fixtures: Fixtures,
}
impl Context {
pub fn from_manifest_dir(fixtures: Fixtures) -> Self {
let rs = Path::new(env!("CARGO_MANIFEST_DIR"));
let conformance = rs.parent().expect("conformance dir").to_path_buf();
let stack = conformance.parent().and_then(Path::parent).expect("stack dir").to_path_buf();
Context { stack, conformance, fixtures }
}
pub fn fixture(&self, rel: &str) -> PathBuf {
self.conformance.join("fixtures").join(rel)
}
}
#[derive(Debug, Default)]
pub struct Out {
pub snapshot: Snapshot,
pub fixtures: Vec<(String, Vec<u8>)>,
pub failures: Vec<String>,
}
impl Out {
pub fn encoding(&mut self, name: &str, bytes: &[u8]) {
self.snapshot.encodings.push(EncodingSnapshot {
name: name.to_string(),
tier: TIER,
fingerprint: Fingerprint::of(bytes),
});
}
pub fn mechanism(&mut self, mechanism: &str, scenario: &str, bytes: &[u8]) {
debug_assert!(!scenario.contains('"'));
self.snapshot.mechanisms.push(MechanismSnapshot {
mechanism: mechanism.to_string(),
scenario: scenario.to_string(),
tier: TIER,
fingerprint: Fingerprint::of(bytes),
});
}
pub fn fail(&mut self, msg: impl Into<String>) {
self.failures.push(msg.into());
}
}
pub fn generate(ctx: &Context) -> Out {
let mut out = Out::default();
hemera::run(ctx, &mut out);
nebu::run(ctx, &mut out);
nox::run(ctx, &mut out);
zheng::run(ctx, &mut out);
tade::run(ctx, &mut out);
cybergraph::run(ctx, &mut out);
for k in out.snapshot.duplicate_keys() {
out.fail(format!("duplicate snapshot key {k}"));
}
out
}
#[derive(Debug, Default, Clone)]
pub struct Bytes(pub Vec<u8>);
impl Bytes {
pub fn new() -> Self {
Self::default()
}
pub fn u8(&mut self, v: u8) -> &mut Self {
self.0.push(v);
self
}
pub fn u32(&mut self, v: u32) -> &mut Self {
self.0.extend_from_slice(&v.to_le_bytes());
self
}
pub fn u64(&mut self, v: u64) -> &mut Self {
self.0.extend_from_slice(&v.to_le_bytes());
self
}
pub fn raw(&mut self, b: &[u8]) -> &mut Self {
self.0.extend_from_slice(b);
self
}
pub fn lv(&mut self, b: &[u8]) -> &mut Self {
self.u64(b.len() as u64).raw(b)
}
}
pub const EDGES: [u64; 11] = [
0,
1,
2,
7,
0xFFFF_FFFF,
0x1_0000_0000,
0x1_0000_0001,
1 << 63,
0xFFFF_FFFF_0000_0000 - 1, 0xFFFF_FFFF_0000_0000, 0x1234_5678_9ABC_DEF0,
];
pub fn ramp(seed: u64, n: usize) -> Vec<u64> {
let mut x = seed;
(0..n)
.map(|_| {
x = x.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = x;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^= z >> 31;
z % ::nebu::field::P
})
.collect()
}
pub fn list(dir: &Path, ext: &str) -> Result<Vec<String>, String> {
let rd = std::fs::read_dir(dir).map_err(|e| format!("{}: {e}", dir.display()))?;
let mut names: Vec<String> = rd
.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().into_owned())
.filter(|n| n.ends_with(ext))
.collect();
names.sort();
Ok(names)
}