weavatrix-graph 0.6.3

Deterministic, evidence-carrying graph core for Weavatrix repository intelligence
Documentation
use crate::String;
use core::fmt::{Display, Formatter};

#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum GraphError {
    EmptyNodeId,
    InvalidKind {
        category: &'static str,
        value: String,
    },
    ConflictingNode {
        id: String,
    },
    MissingEdgeSource {
        id: String,
    },
    MissingEdgeTarget {
        id: String,
    },
    EmptyExtractor,
    InvalidSpan {
        file: String,
        reason: &'static str,
    },
    IndexCapacityExceeded {
        category: &'static str,
        count: usize,
    },
    InvalidTopologyEndpoint {
        edge: usize,
        node: usize,
        node_count: usize,
    },
    ArithmeticOverflow {
        operation: &'static str,
    },
    InvalidNodeIndex {
        node: usize,
        node_count: usize,
    },
    InvalidProbability {
        numerator: u64,
        denominator: u64,
    },
    InvalidAlgorithmParameter {
        algorithm: &'static str,
        parameter: &'static str,
        value: String,
    },
    NegativeCycle {
        algorithm: &'static str,
    },
    CyclicGraph {
        algorithm: &'static str,
    },
    InvalidFormat {
        format: &'static str,
        reason: String,
    },
    UnsupportedGraphFeature {
        format: &'static str,
        feature: &'static str,
    },
    PayloadCountMismatch {
        category: &'static str,
        expected: usize,
        actual: usize,
    },
    InvalidStableKey {
        category: &'static str,
        slot: u32,
        generation: u32,
    },
    MissingKeyedNode {
        endpoint: &'static str,
    },
    CycleWouldBeCreated,
}

impl Display for GraphError {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::EmptyNodeId => formatter.write_str("node id must not be empty"),
            Self::InvalidKind { category, value } => {
                write!(formatter, "invalid {category} kind: {value:?}")
            }
            Self::ConflictingNode { id } => {
                write!(formatter, "node id {id} has conflicting definitions")
            }
            Self::MissingEdgeSource { id } => {
                write!(formatter, "edge source does not exist: {id}")
            }
            Self::MissingEdgeTarget { id } => {
                write!(formatter, "edge target does not exist: {id}")
            }
            Self::EmptyExtractor => formatter.write_str("provenance extractor must not be empty"),
            Self::InvalidSpan { file, reason } => {
                write!(formatter, "invalid source span for {file:?}: {reason}")
            }
            Self::IndexCapacityExceeded { category, count } => {
                write!(
                    formatter,
                    "{category} count {count} exceeds u32 index capacity"
                )
            }
            Self::InvalidTopologyEndpoint {
                edge,
                node,
                node_count,
            } => write!(
                formatter,
                "edge {edge} references node index {node}, but node count is {node_count}"
            ),
            Self::ArithmeticOverflow { operation } => {
                write!(formatter, "arithmetic overflow while computing {operation}")
            }
            Self::InvalidNodeIndex { node, node_count } => {
                write!(
                    formatter,
                    "node index {node} is outside matrix node count {node_count}"
                )
            }
            Self::InvalidProbability {
                numerator,
                denominator,
            } => write!(
                formatter,
                "probability {numerator}/{denominator} must have a nonzero denominator and be at most one"
            ),
            Self::InvalidAlgorithmParameter {
                algorithm,
                parameter,
                value,
            } => write!(formatter, "invalid {parameter} for {algorithm}: {value}"),
            Self::NegativeCycle { algorithm } => {
                write!(formatter, "{algorithm} found a reachable negative cycle")
            }
            Self::CyclicGraph { algorithm } => {
                write!(formatter, "{algorithm} requires an acyclic graph")
            }
            Self::InvalidFormat { format, reason } => {
                write!(formatter, "invalid {format} input: {reason}")
            }
            Self::UnsupportedGraphFeature { format, feature } => {
                write!(formatter, "{format} does not support {feature}")
            }
            Self::PayloadCountMismatch {
                category,
                expected,
                actual,
            } => write!(
                formatter,
                "{category} payload count {actual} does not match topology count {expected}"
            ),
            Self::InvalidStableKey {
                category,
                slot,
                generation,
            } => write!(
                formatter,
                "{category} key at slot {slot}, generation {generation} is stale or invalid"
            ),
            Self::MissingKeyedNode { endpoint } => {
                write!(formatter, "keyed graph {endpoint} node does not exist")
            }
            Self::CycleWouldBeCreated => {
                formatter.write_str("mutation would violate the acyclic graph invariant")
            }
        }
    }
}

impl core::error::Error for GraphError {}

pub type Result<T> = core::result::Result<T, GraphError>;