binius_examples/
snapshot.rs1use std::{env, fs, path::PathBuf};
4
5use anyhow::{Context, Result};
6use binius_frontend::{Circuit, CircuitStat};
7
8fn workspace_root() -> Result<PathBuf> {
10 let manifest_dir = env::var("CARGO_MANIFEST_DIR").context(
11 "CARGO_MANIFEST_DIR environment variable not set. \
12 Please run this command via 'cargo run -p binius-examples' or 'cargo test'.",
13 )?;
14
15 let workspace_root = PathBuf::from(manifest_dir)
17 .parent()
18 .and_then(|p| p.parent())
19 .context("Failed to determine workspace root from CARGO_MANIFEST_DIR")?
20 .to_path_buf();
21
22 Ok(workspace_root)
23}
24
25pub fn snapshot_path(circuit_name: &str) -> Result<PathBuf> {
27 let root = workspace_root()?;
28 Ok(root.join(format!("crates/examples/snapshots/{}.snap", circuit_name)))
29}
30
31pub fn format_circuit_stats(circuit_name: &str, circuit: &Circuit) -> String {
33 let mut output = String::new();
34 output.push_str(&format!("{} circuit\n", circuit_name));
35 output.push_str("--\n");
36
37 let stat = CircuitStat::collect(circuit);
38 output.push_str(&format!("{}", stat));
39 output
40}
41
42pub fn check_snapshot(circuit_name: &str, circuit: &Circuit) -> Result<()> {
44 let snapshot_path = snapshot_path(circuit_name)?;
45
46 if !snapshot_path.exists() {
47 anyhow::bail!(
48 "Snapshot file not found at {}\n\
49 Run 'binius-examples {} bless-snapshot' to create it.",
50 snapshot_path.display(),
51 circuit_name
52 );
53 }
54
55 let expected = fs::read_to_string(&snapshot_path)
56 .with_context(|| format!("Failed to read snapshot file: {}", snapshot_path.display()))?;
57
58 let actual = format_circuit_stats(circuit_name, circuit);
59
60 if expected != actual {
61 print_snapshot_diff(&expected, &actual, circuit_name);
62 anyhow::bail!("Circuit statistics do not match snapshot");
63 }
64
65 println!("✓ Circuit statistics match snapshot");
66 Ok(())
67}
68
69pub fn bless_snapshot(circuit_name: &str, circuit: &Circuit) -> Result<()> {
71 let snapshot_path = snapshot_path(circuit_name)?;
72
73 if let Some(parent) = snapshot_path.parent() {
75 fs::create_dir_all(parent).with_context(|| {
76 format!("Failed to create snapshot directory: {}", parent.display())
77 })?;
78 }
79
80 let output = format_circuit_stats(circuit_name, circuit);
81
82 fs::write(&snapshot_path, &output)
83 .with_context(|| format!("Failed to write snapshot file: {}", snapshot_path.display()))?;
84
85 println!("✓ Snapshot updated at {}", snapshot_path.display());
86 Ok(())
87}
88
89fn print_snapshot_diff(expected: &str, actual: &str, circuit_name: &str) {
91 eprintln!("Error: Circuit statistics do not match snapshot!");
92 eprintln!("\n--- Expected (from snapshot) ---");
93 eprintln!("{}", expected);
94 eprintln!("\n--- Actual ---");
95 eprintln!("{}", actual);
96 eprintln!("\n--- Diff ---");
97
98 let expected_lines: Vec<_> = expected.lines().collect();
100 let actual_lines: Vec<_> = actual.lines().collect();
101
102 let max_lines = expected_lines.len().max(actual_lines.len());
103 for i in 0..max_lines {
104 let exp_line = expected_lines.get(i).unwrap_or(&"");
105 let act_line = actual_lines.get(i).unwrap_or(&"");
106
107 if exp_line != act_line {
108 eprintln!("Line {}: - {}", i + 1, exp_line);
109 eprintln!("Line {}: + {}", i + 1, act_line);
110 }
111 }
112
113 eprintln!("\nRun 'binius-examples {} bless-snapshot' to update the snapshot.", circuit_name);
114}