vyre-libs 0.6.3

vyre Category A library ecosystem - pure-IR compositions over vyre-ops hardware primitives
Documentation
use std::fs;
use std::path::{Path, PathBuf};

#[cfg(feature = "c-parser")]
pub(crate) mod gpu_if_expression;
#[cfg(feature = "c-parser")]
pub(crate) mod gpu_pipeline_filter;

pub(crate) fn crate_file(path: &str) -> String {
    let manifest = Path::new(env!("CARGO_MANIFEST_DIR"));
    fs::read_to_string(manifest.join(path)).unwrap_or_else(|error| {
        panic!("failed to read {path}: {error}");
    })
}

pub(crate) fn assert_byte_lru_core_tracks_resident_bytes() {
    let byte_lru_cache = crate_file("src/parsing/c/preprocess/gpu_pipeline/byte_lru_cache.rs");
    assert!(
        byte_lru_cache.contains("bytes: usize") && byte_lru_cache.contains("max_bytes: usize"),
        "Fix: shared GPU preprocessor cache core must track resident bytes and byte limit."
    );
}

pub(crate) fn assert_byte_lru_core_rejects_and_accounts() {
    let byte_lru_cache = crate_file("src/parsing/c/preprocess/gpu_pipeline/byte_lru_cache.rs");
    assert!(
        byte_lru_cache.contains("entry_bytes > self.max_bytes")
            && byte_lru_cache.contains(".checked_add(entry_bytes)")
            && byte_lru_cache.contains("checked_sub(entry.bytes)"),
        "Fix: shared GPU preprocessor cache core must reject oversized entries, evict to byte budget, and update byte accounting."
    );
}

pub(crate) fn assert_contains_all(source: &str, needles: &[&str], message: &str) {
    let missing = needles
        .iter()
        .copied()
        .filter(|needle| !source.contains(needle))
        .collect::<Vec<_>>();
    assert!(
        missing.is_empty(),
        "{message} Missing required source fragment(s): {}",
        missing.join(" | ")
    );
}

pub(crate) fn assert_contains_none(source: &str, needles: &[&str], message: &str) {
    let present = needles
        .iter()
        .copied()
        .filter(|needle| source.contains(needle))
        .collect::<Vec<_>>();
    assert!(
        present.is_empty(),
        "{message} Forbidden source fragment(s): {}",
        present.join(" | ")
    );
}

pub(crate) fn assert_no_cpu_named_api_exports(
    relative_root: &str,
    read_context: &str,
    extra_trait_markers: &[&str],
    failure_message: &str,
) {
    let root = Path::new(env!("CARGO_MANIFEST_DIR")).join(relative_root);
    let mut files = Vec::new();
    collect_rs_files(&root, read_context, &mut files);

    let mut offenders = Vec::new();
    for path in files {
        let source = fs::read_to_string(&path)
            .unwrap_or_else(|error| panic!("read {read_context} source file: {error}"));
        for (line_idx, line) in source.lines().enumerate() {
            if is_cpu_named_api_export(line, extra_trait_markers) {
                offenders.push(format!("{}:{}: {line}", path.display(), line_idx + 1));
            }
        }
    }

    assert!(
        offenders.is_empty(),
        "{failure_message}:\n{}",
        offenders.join("\n")
    );
}

fn collect_rs_files(dir: &Path, read_context: &str, files: &mut Vec<PathBuf>) {
    for entry in fs::read_dir(dir)
        .unwrap_or_else(|error| panic!("read {read_context} source directory: {error}"))
    {
        let entry =
            entry.unwrap_or_else(|error| panic!("read {read_context} source entry: {error}"));
        let path = entry.path();
        if path.is_dir() {
            collect_rs_files(&path, read_context, files);
        } else if path.extension().is_some_and(|ext| ext == "rs") {
            files.push(path);
        }
    }
}

fn is_cpu_named_api_export(line: &str, extra_trait_markers: &[&str]) -> bool {
    let has_cpu_name = line.contains("_cpu") || line.contains("cpu_");
    let public_cpu_fn = line.contains("pub fn ") && has_cpu_name;
    let public_cpu_reexport = line.contains("pub use ") && has_cpu_name;
    let trait_marker = line.trim_start().starts_with("fn ")
        && extra_trait_markers
            .iter()
            .any(|marker| line.contains(marker));

    public_cpu_fn || public_cpu_reexport || trait_marker
}