vyre-megakernel 0.7.2

Backend-neutral compiler for canonical Vyre megakernel artifacts
Documentation
use vyre_foundation::ir::{ProgramGraph, ValueLifetime};

use crate::{
    ensure_node_dag, failure, ArtifactNodeId, ArtifactValueId, CompileError, CompilerFailureKind,
    DependencyEdge, DependencyEndpoint, DependencyKind,
};

#[derive(Debug)]
pub(crate) struct NormalizedGraph {
    pub(crate) dependencies: Vec<DependencyEdge>,
}

pub(crate) fn normalize(graph: &ProgramGraph) -> Result<NormalizedGraph, CompileError> {
    let mut dependencies = Vec::new();
    for value in graph.values() {
        let value_id = ArtifactValueId(value.id.0);
        if let Some(producer) = value.producer {
            let from = ArtifactNodeId(producer.0);
            for consumer in &value.consumers {
                dependencies.push(DependencyEdge {
                    from: DependencyEndpoint::Node(from),
                    to: DependencyEndpoint::Node(ArtifactNodeId(consumer.0)),
                    kind: DependencyKind::Data,
                    value: Some(value_id),
                });
            }
            if matches!(
                value.contract.lifetime,
                ValueLifetime::Output | ValueLifetime::Retained
            ) {
                dependencies.push(DependencyEdge {
                    from: DependencyEndpoint::Node(from),
                    to: DependencyEndpoint::Value(value_id),
                    kind: DependencyKind::Materialization,
                    value: Some(value_id),
                });
            }
        }
        if let (Some(prior), Some(successor_node)) = (value.retained_successor_of, value.producer) {
            let prior = graph.values().get(prior.0 as usize).ok_or_else(|| {
                failure(
                    CompilerFailureKind::InvalidProgram,
                    format!("graph.values[{}].retained_successor_of", value.id.0),
                    format!("retained predecessor {} does not exist", prior.0),
                    "repair the validated ProgramGraph retained transition",
                )
            })?;
            let from = prior
                .producer
                .map(|node| DependencyEndpoint::Node(ArtifactNodeId(node.0)))
                .unwrap_or_else(|| DependencyEndpoint::Value(ArtifactValueId(prior.id.0)));
            dependencies.push(DependencyEdge {
                from,
                to: DependencyEndpoint::Node(ArtifactNodeId(successor_node.0)),
                kind: DependencyKind::Retained,
                value: Some(value_id),
            });
        }
    }
    dependencies.sort();
    dependencies.dedup();
    ensure_node_dag(
        graph.nodes().len(),
        &dependencies,
        CompilerFailureKind::DependencyCycle,
    )?;
    Ok(NormalizedGraph { dependencies })
}