rust-split 0.2.1

A parser-based god-file splitter for Rust source.
Documentation
//! Data-loss regressions from the September 2026 gwz-core split.
use std::{collections::BTreeSet, fs, process::Command};

use rust_split::{SplitOutput, explode, split_bin, split_mod};
use syn::visit::Visit;

fn write_output(out: &SplitOutput, dir: &std::path::Path) {
    let mut paths = BTreeSet::new();
    for file in &out.files {
        assert!(paths.insert(&file.path), "duplicate output: {}", file.path);
        let path = dir.join(&file.path);
        fs::create_dir_all(path.parent().unwrap()).unwrap();
        fs::write(path, &file.contents).unwrap();
    }
}

fn compile(dir: &std::path::Path, root: &str, enabled: bool) {
    let mut cmd = Command::new("rustc");
    cmd.current_dir(dir)
        .args(["--edition=2024", "--crate-type=lib", root, "-o", "out.rlib"]);
    if enabled {
        cmd.args(["--cfg", "branch_a"]);
    }
    let output = cmd.output().unwrap();
    assert!(
        output.status.success(),
        "{}",
        String::from_utf8_lossy(&output.stderr)
    );
}

struct BracedConditionalModules;

impl<'ast> Visit<'ast> for BracedConditionalModules {
    fn visit_item_mod(&mut self, item: &'ast syn::ItemMod) {
        if item
            .attrs
            .iter()
            .any(|attr| attr.path().is_ident("cfg") || attr.path().is_ident("cfg_attr"))
        {
            assert!(
                item.content.is_some(),
                "conditional module {} lost its braces",
                item.ident
            );
        }
        syn::visit::visit_item_mod(self, item);
    }
}

fn large_function() -> String {
    format!(
        "/// Keep this declaration intact.\n#[inline(never)]\npub fn oversized() -> Buffer<u8> {{\n{}    Buffer::new()\n}}\n",
        "    // indivisible body\n".repeat(35)
    )
}

#[test]
fn oversized_leaf_survives_at_its_original_scope_in_both_topologies() {
    let leaf = large_function();
    let source = format!("use std::vec::Vec as Buffer;\n{leaf}\npub fn small() {{}}\n");
    let exploded = explode(&source).unwrap();
    for out in [
        split_bin(&exploded, 25, "lib"),
        split_mod(&exploded, 25, "foo"),
    ] {
        assert!(!out.still_oversized.is_empty());
        assert!(
            out.files[0].contents.contains(&leaf),
            "oversized declaration was lost"
        );
        assert!(
            out.files[0]
                .contents
                .contains("use std::vec::Vec as Buffer;")
        );
        let temp = tempfile::tempdir().unwrap();
        write_output(&out, temp.path());
        if out.files[0].path == "foo.rs" {
            fs::write(temp.path().join("lib.rs"), "pub mod foo;\n").unwrap();
        }
        compile(temp.path(), "lib.rs", false);
    }
}

#[test]
fn oversized_nested_leaf_keeps_its_imports_and_preamble() {
    let leaf = large_function();
    let source = format!(
        "pub mod outer {{\n#![deny(unsafe_code)]\nuse std::vec::Vec as Buffer;\n{leaf}\npub fn small() {{}}\n}}\n"
    );
    let out = split_bin(&explode(&source).unwrap(), 25, "lib");
    let root = out.files.iter().find(|f| f.path == "outer/mod.rs").unwrap();
    assert!(
        root.contents.contains(&leaf),
        "nested oversized declaration was lost"
    );
    assert!(root.contents.contains("use std::vec::Vec as Buffer;"));
    assert!(root.contents.starts_with("#![deny(unsafe_code)]"));
    let temp = tempfile::tempdir().unwrap();
    write_output(&out, temp.path());
    compile(temp.path(), "lib.rs", false);
}

#[test]
fn oversized_main_survives() {
    let source = format!("fn main() {{\n{} }}\n", "    // large main\n".repeat(30));
    let out = split_bin(&explode(&source).unwrap(), 20, "main");
    assert!(out.files[0].contents.contains(&source));
}

#[test]
fn conditional_module_bodies_survive_with_explicit_boundaries() {
    let gated = r#"
/// First platform implementation.
#[cfg(branch_a)]
pub mod platform_rename {
    pub fn rename() -> u8 { 1 }
}
// Fallback implementation.
#[cfg_attr(all(), cfg(not(branch_a)))]
pub mod platform_rename {
    pub fn rename() -> u8 { 2 }
}
"#;
    for nested in [false, true] {
        let source = if nested {
            format!(
                "pub mod outer {{\nuse std::vec::Vec as Buffer;\n{gated}\n{}\n}}",
                large_function()
            )
        } else {
            gated.to_owned()
        };
        let out = split_bin(&explode(&source).unwrap(), 25, "lib");
        let combined: String = out.files.iter().map(|f| f.contents.as_str()).collect();
        assert!(
            combined.contains(gated),
            "gated declarations must remain intact"
        );
        for file in &out.files {
            BracedConditionalModules.visit_file(&syn::parse_file(&file.contents).unwrap());
        }
        let temp = tempfile::tempdir().unwrap();
        write_output(&out, temp.path());
        compile(temp.path(), "lib.rs", false);
        compile(temp.path(), "lib.rs", true);
    }
}

#[test]
fn cli_reports_unmet_budget_after_writing_preserved_output() {
    let temp = tempfile::tempdir().unwrap();
    let source = temp.path().join("lib.rs");
    fs::write(&source, large_function()).unwrap();
    let out = temp.path().join("output");
    let result = Command::new(env!("CARGO_BIN_EXE_rust-split"))
        .arg("split")
        .arg(&source)
        .args(["--max-loc", "20", "--out"])
        .arg(&out)
        .output()
        .unwrap();
    assert!(
        !result.status.success(),
        "an unmet budget must not report success"
    );
    assert!(
        fs::read_to_string(out.join("lib.rs"))
            .unwrap()
            .contains(&large_function())
    );
    assert!(String::from_utf8_lossy(&result.stderr).contains("preserved"));
}

#[test]
fn cli_reports_root_overhead_exceeding_budget() {
    let temp = tempfile::tempdir().unwrap();
    let source = temp.path().join("lib.rs");
    fs::write(
        &source,
        (0..15)
            .map(|n| format!("pub fn f{n}() {{}}\n"))
            .collect::<String>(),
    )
    .unwrap();
    let result = Command::new(env!("CARGO_BIN_EXE_rust-split"))
        .arg("split")
        .arg(&source)
        .args(["--max-loc", "15", "--out"])
        .arg(temp.path().join("output"))
        .output()
        .unwrap();
    assert!(!result.status.success(), "root wiring exceeds budget");
}

#[test]
fn cli_succeeds_when_all_output_fits() {
    let temp = tempfile::tempdir().unwrap();
    let source = temp.path().join("lib.rs");
    fs::write(&source, "pub fn small() {}\n").unwrap();
    let result = Command::new(env!("CARGO_BIN_EXE_rust-split"))
        .arg("split")
        .arg(&source)
        .args(["--max-loc", "50", "--out"])
        .arg(temp.path().join("output"))
        .output()
        .unwrap();
    assert!(
        result.status.success(),
        "{}",
        String::from_utf8_lossy(&result.stderr)
    );
}