weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! Source-organization contract for Weir's GPU dispatch ABI boundary.
//!
//! `dispatch_decode` is the shared choke point between backend bytes and
//! dataflow facts. It must stay split by responsibility so future primitive
//! work does not reintroduce a god file that mixes packing, input validation,
//! output decoding, and ABI tests.

use std::fs;
use std::path::Path;

#[test]
fn dispatch_decode_is_split_by_gpu_abi_responsibility() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let legacy = root.join("src/dispatch_decode.rs");
    assert!(
        !legacy.exists(),
        "Fix: dispatch_decode must stay a module directory, not a single mixed src/dispatch_decode.rs file."
    );

    for required in [
        "src/dispatch_decode/mod.rs",
        "src/dispatch_decode/schema.rs",
        "src/dispatch_decode/pack.rs",
        "src/dispatch_decode/validate.rs",
        "src/dispatch_decode/unpack.rs",
    ] {
        assert!(
            root.join(required).is_file(),
            "Fix: missing dispatch decode module file {required}."
        );
    }
}

#[test]
fn dispatch_decode_mod_file_preserves_stable_crate_internal_surface() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let source = fs::read_to_string(root.join("src/dispatch_decode/mod.rs"))
        .expect("dispatch_decode/mod.rs must be readable");

    for module in ["mod pack;", "mod schema;", "mod validate;", "mod unpack;"] {
        assert!(
            source.contains(module),
            "Fix: dispatch_decode/mod.rs must declare {module}."
        );
    }
    for required_api in [
        "pack_u32",
        "pack_exact_u32_slots_into",
        "DispatchU32Schema",
        "U32_BITS_PER_WORD",
        "require_bitset_words",
        "require_csr_shape",
        "require_output_count",
        "unpack_only_exact_u32_into",
        "unpack_exact_u32_scalar",
    ] {
        assert!(
            source.contains(required_api),
            "Fix: dispatch_decode/mod.rs must re-export crate-internal API {required_api}."
        );
    }
}

#[test]
fn dispatch_decode_submodules_do_one_kind_of_work() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let pack_source = fs::read_to_string(root.join("src/dispatch_decode/pack.rs"))
        .expect("dispatch_decode/pack.rs must be readable");
    let schema_source = fs::read_to_string(root.join("src/dispatch_decode/schema.rs"))
        .expect("dispatch_decode/schema.rs must be readable");
    let validate_source = fs::read_to_string(root.join("src/dispatch_decode/validate.rs"))
        .expect("dispatch_decode/validate.rs must be readable");
    let unpack_source = fs::read_to_string(root.join("src/dispatch_decode/unpack.rs"))
        .expect("dispatch_decode/unpack.rs must be readable");
    let pack = production_source(&pack_source);
    let schema = production_source(&schema_source);
    let validate = production_source(&validate_source);
    let unpack = production_source(&unpack_source);

    assert!(
        pack.contains("fn try_pack_u32_into")
            && pack.contains("fn pack_repeated_u32_into")
            && !pack.contains("fn unpack_exact_u32"),
        "Fix: pack.rs must own byte packing only, not output decoding."
    );
    assert!(
        schema.contains("struct DispatchU32Schema")
            && schema.contains("fn require_input_words")
            && schema.contains("fn require_output_bytes")
            && !schema.contains("fn try_pack_u32_into")
            && !schema.contains("fn unpack_exact_u32_into")
            && !schema.contains("fn require_csr_shape"),
        "Fix: schema.rs must own shared ABI schema and exact diagnostics, not packing, decoding, or graph validation."
    );
    assert!(
        validate.contains("fn require_bitset_words")
            && validate.contains("fn require_csr_offsets_targets")
            && !validate.contains("fn pack_u32")
            && !validate.contains("fn unpack_exact_u32"),
        "Fix: validate.rs must own shape/domain validation only."
    );
    assert!(
        unpack.contains("fn require_output_count")
            && unpack.contains("fn unpack_exact_u32_into")
            && !unpack.contains("fn pack_u32")
            && !unpack.contains("fn require_csr_shape"),
        "Fix: unpack.rs must own output-count and byte-decoding ABI checks only."
    );
}

fn production_source(source: &str) -> &str {
    source
        .split("#[cfg(test)]")
        .next()
        .expect("source must have a production prefix")
}