Skip to main content

pedant_graph/
edge.rs

1//! A graph edge, how certain it is, and the evidence that produced it.
2
3use std::sync::Arc;
4
5use pedant_types::ResolutionCertainty;
6use serde::Serialize;
7
8use crate::id::{GraphEdgeId, GraphNodeId, GraphReferenceId};
9use crate::reference::GraphReferenceKind;
10
11/// What relation an edge states.
12#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[serde(rename_all = "snake_case")]
14pub enum GraphEdgeKind {
15    /// The source calls the target.
16    Call,
17    /// The source imports the target.
18    Import,
19    /// The source implements the target.
20    Implementation,
21    /// Any other source relation between the two.
22    Reference,
23    /// The source's build unit depends on the target's build unit.
24    DependsOn,
25}
26
27impl GraphEdgeKind {
28    /// The edge one candidate of a reference produces.
29    ///
30    /// Graph vocabulary answered from graph vocabulary, so every adapter that
31    /// turns a reference's candidates into edges reads the one mapping rather
32    /// than restating it in its own language's terms.
33    pub(crate) fn of_reference(kind: GraphReferenceKind) -> Self {
34        match kind {
35            GraphReferenceKind::Call => Self::Call,
36            GraphReferenceKind::Import => Self::Import,
37            GraphReferenceKind::Implementation => Self::Implementation,
38            GraphReferenceKind::Reference => Self::Reference,
39        }
40    }
41}
42
43/// How much an edge is known.
44///
45/// A projection maps a producer's certainty one for one and never upgrades a
46/// possible answer to a resolved one.
47#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[serde(rename_all = "snake_case")]
49pub enum GraphCertainty {
50    /// Language rules identify this one target without inference.
51    Resolved,
52    /// Source evidence identifies the target, but proof is not available.
53    Possible,
54}
55
56impl GraphCertainty {
57    /// How much one answered candidate is known.
58    ///
59    /// The shared resolution vocabulary maps one for one, so no adapter can
60    /// promote a possible answer on the way into a graph.
61    pub(crate) fn of(certainty: ResolutionCertainty) -> Self {
62        match certainty {
63            ResolutionCertainty::Resolved => Self::Resolved,
64            ResolutionCertainty::Possible => Self::Possible,
65        }
66    }
67}
68
69/// Which dependency table declared a build-unit edge.
70///
71/// Graph-owned vocabulary rather than the consumed build-system enum, so a
72/// second producer cannot widen the wire contract from outside this crate.
73#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
74#[serde(rename_all = "snake_case")]
75pub enum GraphDependencyKind {
76    /// An ordinary dependency edge.
77    Normal,
78    /// A development-only dependency edge.
79    Development,
80    /// A build-time dependency edge.
81    Build,
82}
83
84/// What one build-unit dependency edge retained from its declaration.
85#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
86pub struct DependencyEvidence {
87    alias: Arc<str>,
88    kind: GraphDependencyKind,
89    predicate: Option<Arc<str>>,
90}
91
92impl DependencyEvidence {
93    pub(crate) fn new(
94        alias: Arc<str>,
95        kind: GraphDependencyKind,
96        predicate: Option<Arc<str>>,
97    ) -> Self {
98        Self {
99            alias,
100            kind,
101            predicate,
102        }
103    }
104
105    /// The namespace-local name the declaring unit sees the target under.
106    pub fn alias(&self) -> &str {
107        &self.alias
108    }
109
110    /// Which dependency table declared the edge.
111    pub fn kind(&self) -> GraphDependencyKind {
112        self.kind
113    }
114
115    /// The unevaluated activation predicate, when the edge is conditional.
116    pub fn predicate(&self) -> Option<&str> {
117        self.predicate.as_deref()
118    }
119}
120
121/// Why an edge exists. No edge exists without one of these.
122#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
123#[serde(tag = "kind", rename_all = "snake_case")]
124pub enum GraphEdgeOrigin {
125    /// One candidate of one reference record produced the edge.
126    Reference {
127        /// The record that produced it, for the reverse evidence link.
128        reference: GraphReferenceId,
129    },
130    /// One declared build-unit dependency produced the edge.
131    Dependency {
132        /// What the declaration stated.
133        evidence: DependencyEvidence,
134    },
135}
136
137/// One directed relation between two graph nodes.
138#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
139pub struct GraphEdge {
140    id: GraphEdgeId,
141    source: GraphNodeId,
142    target: GraphNodeId,
143    kind: GraphEdgeKind,
144    certainty: GraphCertainty,
145    origin: GraphEdgeOrigin,
146}
147
148/// Everything a projection states about one edge before it has an identity.
149pub(crate) struct EdgeDraft {
150    /// The node the relation starts at.
151    pub(crate) source: GraphNodeId,
152    /// The node the relation ends at.
153    pub(crate) target: GraphNodeId,
154    /// What relation the edge states.
155    pub(crate) kind: GraphEdgeKind,
156    /// How much the relation is known.
157    pub(crate) certainty: GraphCertainty,
158    /// Why the edge exists.
159    pub(crate) origin: GraphEdgeOrigin,
160}
161
162impl GraphEdge {
163    pub(crate) fn new(id: GraphEdgeId, draft: EdgeDraft) -> Self {
164        Self {
165            id,
166            source: draft.source,
167            target: draft.target,
168            kind: draft.kind,
169            certainty: draft.certainty,
170            origin: draft.origin,
171        }
172    }
173
174    /// This edge's dense identity, equal to its position in the graph.
175    pub fn id(&self) -> GraphEdgeId {
176        self.id
177    }
178
179    /// The node the relation starts at.
180    pub fn source(&self) -> GraphNodeId {
181        self.source
182    }
183
184    /// The node the relation ends at.
185    pub fn target(&self) -> GraphNodeId {
186        self.target
187    }
188
189    /// What relation this edge states.
190    pub fn kind(&self) -> GraphEdgeKind {
191        self.kind
192    }
193
194    /// How much this relation is known.
195    pub fn certainty(&self) -> GraphCertainty {
196        self.certainty
197    }
198
199    /// Why this edge exists.
200    pub fn origin(&self) -> &GraphEdgeOrigin {
201        &self.origin
202    }
203}