Skip to main content

normalize

Function normalize 

Source
pub fn normalize(root: &Root) -> Result<NormalizeTable, NormalizeError>
Expand description

Normalize every binding group in a parsed tree.

Returns the plans for groups that actually need one. A group with no duplicate static key and no dotted path is NOT recorded — consumers keep their existing path for it, which is what bounds this pass’s blast radius.

§Errors

Returns the first NormalizeError in source order, matching nix’s parse-time rejection.

Examples found in repository?
examples/scan.rs (line 85)
58fn main() {
59    let roots: Vec<PathBuf> = std::env::args().skip(1).map(PathBuf::from).collect();
60    if roots.is_empty() {
61        eprintln!("usage: scan <dir> [<dir>…]");
62        std::process::exit(2);
63    }
64
65    let mut files = Vec::new();
66    for r in &roots {
67        nix_files(r, &mut files);
68    }
69
70    let (mut unparseable, mut clean, mut planned, mut rejected) = (0usize, 0usize, 0usize, 0usize);
71    let mut groups = 0usize;
72    let mut rejects: Vec<(PathBuf, String)> = Vec::new();
73
74    for f in &files {
75        let Ok(src) = std::fs::read_to_string(f) else {
76            continue;
77        };
78        let parse = rnix::Root::parse(&src);
79        if !parse.errors().is_empty() {
80            // rnix could not parse it — not this pass's business, and counted
81            // separately so it can never be mistaken for a clean result.
82            unparseable += 1;
83            continue;
84        }
85        match sui_normalize::normalize(&parse.tree()) {
86            Ok(table) if table.is_empty() => clean += 1,
87            Ok(table) => {
88                planned += 1;
89                groups += table.len();
90            }
91            Err(e) => {
92                rejected += 1;
93                rejects.push((f.clone(), e.to_string()));
94            }
95        }
96    }
97
98    println!("scanned    {}", files.len());
99    println!("  clean      {clean}   (no duplicate key, no dotted path — untouched)");
100    println!("  planned    {planned}   ({groups} binding groups — THE BLAST RADIUS)");
101    println!("  rejected   {rejected}   (each MUST be one `nix-instantiate --parse` also refuses)");
102    println!("  unparseable {unparseable}   (rnix could not read; not this pass's business)");
103
104    for (p, e) in rejects.iter().take(25) {
105        println!("  REJECT {}: {e}", p.display());
106    }
107    if rejects.len() > 25 {
108        println!("  … and {} more", rejects.len() - 25);
109    }
110}