hara-native 0.1.23

HAL-free native host runtime and package launcher for Hara
Documentation
use std::collections::HashMap;

use super::{module_dependencies, ModuleSource};

/// Returns a stable dependency-first order. Eager namespace edges and
/// `l/script` module requirements participate because both must be materialized
/// before a consumer's macro expansion and artifact execution.
pub(super) fn order_module_sources(sources: &[ModuleSource<'_>]) -> Result<Vec<usize>, String> {
    let positions = sources
        .iter()
        .enumerate()
        .map(|(index, source)| (source.resource, index))
        .collect::<HashMap<_, _>>();
    let dependencies = sources
        .iter()
        .map(|source| {
            let (mut dependencies, script_dependencies) = module_dependencies(source.source)?;
            dependencies.extend(script_dependencies);
            dependencies.sort();
            dependencies.dedup();
            Ok(dependencies)
        })
        .collect::<Result<Vec<_>, String>>()?;
    let mut state = vec![0u8; sources.len()];
    let mut ordered = Vec::with_capacity(sources.len());

    for index in 0..sources.len() {
        visit(
            index,
            sources,
            &positions,
            &dependencies,
            &mut state,
            &mut ordered,
        )?;
    }
    Ok(ordered)
}

fn visit(
    index: usize,
    sources: &[ModuleSource<'_>],
    positions: &HashMap<&str, usize>,
    dependencies: &[Vec<String>],
    state: &mut [u8],
    ordered: &mut Vec<usize>,
) -> Result<(), String> {
    match state[index] {
        2 => return Ok(()),
        1 => {
            return Err(format!(
                "eager namespace dependency cycle at {}",
                sources[index].resource
            ));
        }
        _ => state[index] = 1,
    }
    for dependency in &dependencies[index] {
        if let Some(&dependency_index) = positions.get(dependency.as_str()) {
            visit(
                dependency_index,
                sources,
                positions,
                dependencies,
                state,
                ordered,
            )?;
        }
    }
    state[index] = 2;
    ordered.push(index);
    Ok(())
}