sim-nest 0.1.25

The SIM constellation umbrella facade: one crate that re-exports the runtime kernel, codecs, number domains, and libraries behind features.
use std::{fs, path::Path};

use super::support::repo_root;

const REEXPORT_AND_WIRING: &[&str] = &[
    "src/bin/sim.rs",
    "src/femm_exports.rs",
    "src/lib.rs",
    "src/loaders.rs",
    "src/loaders/registry.rs",
    "src/numbers_exports.rs",
    "src/roadmap11_exports.rs",
    "src/runtime.rs",
    "src/standard_exports.rs",
];

const AUTHORING_HELPERS: &[&str] = &[
    "src/classes.rs",
    "src/classes/",
    "src/compat.rs",
    "src/functions.rs",
    "src/macros.rs",
    "src/macros/",
    "src/music_stack.rs",
    "src/shapes.rs",
];

const RUNTIME_BEHAVIOR_ALLOWLIST: &[&str] = &[
    "src/runtime/browse.rs",
    "src/runtime/browse/",
    "src/runtime/capabilities.rs",
    "src/runtime/cookbook_directory.rs",
    "src/runtime/cookbook_directory/",
    "src/runtime/cookbook_discovery.rs",
    "src/runtime/eval_policy.rs",
    "src/runtime/glasses.rs",
    "src/runtime/glasses/",
    "src/runtime/help.rs",
    "src/runtime/install.rs",
    "src/runtime/install/",
    "src/runtime/lambda.rs",
    "src/runtime/lists.rs",
    "src/runtime/realize.rs",
    "src/runtime/reference_device.rs",
    "src/runtime/reference_device/",
    "src/runtime/watch.rs",
    "src/runtime/watch/",
    "src/runtime/shape_ops.rs",
    "src/runtime/shape_ops_impl.rs",
    "src/runtime/shape_ops_impl/",
    "src/runtime/tables.rs",
    "src/runtime/tables/",
    "src/runtime/test_runs.rs",
    "src/runtime/testing.rs",
];

const TEST_SUPPORT: &[&str] = &[
    "src/codec_matrix_tests.rs",
    "src/codec_matrix_tests/",
    "src/feature_contract_tests.rs",
    "src/feature_contract_tests/",
    "src/loaders/tests.rs",
    "src/loaders/tests/",
    "src/music_stack_tests.rs",
    "src/runtime/tests.rs",
    "src/runtime/tests/",
    "src/skill_tests.rs",
];

const EXTRACTED_LOADER_BEHAVIOR: &[&str] = &[
    "src/loaders/binary_pack.rs",
    "src/loaders/reexport.rs",
    "src/loaders/shared.rs",
    "src/loaders/source.rs",
    "src/loaders/source/compile.rs",
];

const LOADER_WIRING_FILES: &[&str] = &["src/loaders/registry.rs"];

#[test]
fn facade_sources_match_behavior_allowlist() {
    let root = repo_root();
    let mut unclassified = collect_rust_files(&root.join("src"))
        .into_iter()
        .map(|path| slash_path(path.strip_prefix(&root).unwrap()))
        .filter(|path| !is_test_path(path))
        .filter(|path| !matches_any(path, REEXPORT_AND_WIRING))
        .filter(|path| !matches_any(path, AUTHORING_HELPERS))
        .filter(|path| !matches_any(path, RUNTIME_BEHAVIOR_ALLOWLIST))
        .collect::<Vec<_>>();
    unclassified.sort();

    assert!(
        unclassified.is_empty(),
        "new facade production modules must be classified as wiring or explicit behavior: {unclassified:?}"
    );
}

#[test]
fn loader_behavior_stays_out_of_facade() {
    let root = repo_root();
    let lingering = EXTRACTED_LOADER_BEHAVIOR
        .iter()
        .filter(|path| root.join(path).exists())
        .copied()
        .collect::<Vec<_>>();
    assert!(
        lingering.is_empty(),
        "loader implementation belongs in sim-run-loaders, not the facade: {lingering:?}"
    );

    let loader_files = collect_rust_files(&root.join("src/loaders"))
        .into_iter()
        .map(|path| slash_path(path.strip_prefix(&root).unwrap()))
        .filter(|path| !is_test_path(path))
        .filter(|path| !LOADER_WIRING_FILES.contains(&path.as_str()))
        .collect::<Vec<_>>();
    assert!(
        loader_files.is_empty(),
        "facade loader modules are limited to registry wiring: {loader_files:?}"
    );
}

fn collect_rust_files(dir: &Path) -> Vec<std::path::PathBuf> {
    let Ok(entries) = fs::read_dir(dir) else {
        return Vec::new();
    };
    let mut files = Vec::new();
    for entry in entries.filter_map(Result::ok) {
        let path = entry.path();
        if path.is_dir() {
            files.extend(collect_rust_files(&path));
        } else if path.extension().is_some_and(|ext| ext == "rs") {
            files.push(path);
        }
    }
    files
}

fn matches_any(path: &str, patterns: &[&str]) -> bool {
    patterns.iter().any(|pattern| {
        if pattern.ends_with('/') {
            path.starts_with(pattern)
        } else {
            path == *pattern
        }
    })
}

fn is_test_path(path: &str) -> bool {
    path.ends_with("_tests.rs") || path.ends_with("/tests.rs") || matches_any(path, TEST_SUPPORT)
}

fn slash_path(path: &Path) -> String {
    path.components()
        .map(|component| component.as_os_str().to_string_lossy())
        .collect::<Vec<_>>()
        .join("/")
}