oxgraph_graph/lib.rs
1//! Storage-agnostic traits for binary graph views.
2//!
3//! `oxgraph-graph` is the binary graph specialization above `oxgraph-topology`. Use it
4//! to write generic graph consumers over node/edge vocabulary: endpoint lookup,
5//! outgoing traversal, incoming traversal, and degree queries.
6//!
7//! Graph views use topology elements as nodes and topology relations as edges.
8//! Implement concrete layouts, snapshots, builders, mutation systems, payloads,
9//! and algorithms in higher-level crates by implementing these read-view
10//! capabilities.
11//!
12//! # Performance contract
13//!
14//! Most of the traits and aliases in this crate are graph-vocabulary shadows of
15//! topology traits. Unless a specific item documents otherwise, every method,
16//! iterator, and alias inherits its performance contract from the underlying
17//! topology trait it shadows: `O(1)` for accessors, `O(1)` to construct an
18//! iterator plus `O(k)` to yield `k` items, and `perf: unspecified` for
19//! capability-bundle marker traits and blanket impls.
20#![no_std]
21
22#[cfg(kani)]
23extern crate kani;
24
25pub use oxgraph_topology::{
26 CanonicalElementIdentity, CanonicalIncidenceIdentity, CanonicalRelationIdentity,
27 ContainsElement, ContainsIncidence, ContainsRelation, DenseElementIndex, DenseIncidenceIndex,
28 DenseRelationIndex, ElementIncidenceCount, ElementIncidences, ElementPredecessors,
29 ElementSuccessors, ElementWeight, IncidenceBase, IncidenceCounts, IncidenceElement,
30 IncidenceRelation, IncidenceRole, IncidenceWeight, LocalElementIdentity,
31 LocalIncidenceIdentity, LocalRelationIdentity, RelationIncidenceCount, RelationIncidences,
32 RelationWeight, TopologyBase, TopologyCounts, TopologyId,
33};
34
35/// Graph-facing alias for a topology element ID (binary graph node).
36pub type NodeId<G> = <G as TopologyBase>::ElementId;
37
38/// Graph-facing alias for a topology relation ID (binary graph edge).
39pub type EdgeId<G> = <G as TopologyBase>::RelationId;
40
41/// Graph-facing alias for a topology incidence ID (binary graph endpoint).
42///
43/// A binary graph endpoint participation is represented as a topology incidence
44/// only when a graph view exposes incidence capabilities.
45pub type EndpointId<G> = <G as IncidenceBase>::IncidenceId;
46
47/// Graph-facing alias for a topology role used to distinguish source and
48/// target endpoint participation on graph views that expose incidences.
49pub type EndpointRole<G> = <G as IncidenceBase>::Role;
50
51/// Base capability for graph views over topology storage.
52///
53/// Graph-facing name for [`TopologyBase`]. Bundles the associated `ElementId`
54/// and `RelationId` types under graph vocabulary so generic code can require a
55/// graph base contract without naming topology traits directly.
56pub trait GraphBase: TopologyBase {}
57
58impl<T> GraphBase for T where T: TopologyBase {}
59
60/// Count capability for a graph view.
61///
62/// Graph-facing name for [`TopologyCounts`].
63pub trait GraphCounts: TopologyCounts {
64 /// Returns the number of nodes visible in this graph view.
65 fn node_count(&self) -> usize {
66 self.element_count()
67 }
68
69 /// Returns the number of edges visible in this graph view.
70 fn edge_count(&self) -> usize {
71 self.relation_count()
72 }
73}
74
75impl<T> GraphCounts for T where T: TopologyCounts {}
76
77/// Dense node-index capability for graph views.
78///
79/// Graph-facing name for [`DenseElementIndex`]. Lets graph algorithms allocate
80/// per-node scratch storage such as visited sets or distance arrays.
81pub trait DenseNodeIndex: DenseElementIndex {
82 /// Returns the exclusive upper bound for node indexes in this graph view.
83 fn node_bound(&self) -> usize {
84 self.element_bound()
85 }
86
87 /// Returns the dense index for `node` in this graph view.
88 fn node_index(&self, node: Self::ElementId) -> usize {
89 self.element_index(node)
90 }
91}
92
93impl<T> DenseNodeIndex for T where T: DenseElementIndex {}
94
95/// Dense edge-index capability for graph views.
96///
97/// Graph-facing name for [`DenseRelationIndex`].
98pub trait DenseEdgeIndex: DenseRelationIndex {
99 /// Returns the exclusive upper bound for edge indexes in this graph view.
100 fn edge_bound(&self) -> usize {
101 self.relation_bound()
102 }
103
104 /// Returns the dense index for `edge` in this graph view.
105 fn edge_index(&self, edge: Self::RelationId) -> usize {
106 self.relation_index(edge)
107 }
108}
109
110impl<T> DenseEdgeIndex for T where T: DenseRelationIndex {}
111
112/// Dense endpoint-index capability for graph views with incidences.
113///
114/// Graph-facing name for [`DenseIncidenceIndex`].
115pub trait DenseEndpointIndex: DenseIncidenceIndex {
116 /// Returns the exclusive upper bound for endpoint indexes in this graph view.
117 fn endpoint_bound(&self) -> usize {
118 self.incidence_bound()
119 }
120
121 /// Returns the dense index for `endpoint` in this graph view.
122 fn endpoint_index(&self, endpoint: Self::IncidenceId) -> usize {
123 self.incidence_index(endpoint)
124 }
125}
126
127impl<T> DenseEndpointIndex for T where T: DenseIncidenceIndex {}
128
129/// Node-ID containment capability for graph views.
130///
131/// Graph-facing name for [`ContainsElement`].
132pub trait ContainsNode: ContainsElement {
133 /// Returns whether `node` is valid and visible in this graph view.
134 fn contains_node(&self, node: Self::ElementId) -> bool {
135 self.contains_element(node)
136 }
137}
138
139impl<T> ContainsNode for T where T: ContainsElement {}
140
141/// Edge-ID containment capability for graph views.
142///
143/// Graph-facing name for [`ContainsRelation`].
144pub trait ContainsEdge: ContainsRelation {
145 /// Returns whether `edge` is valid and visible in this graph view.
146 fn contains_edge(&self, edge: Self::RelationId) -> bool {
147 self.contains_relation(edge)
148 }
149}
150
151impl<T> ContainsEdge for T where T: ContainsRelation {}
152
153/// Endpoint-ID containment capability for graph views with incidences.
154///
155/// Graph-facing name for [`ContainsIncidence`].
156pub trait ContainsEndpoint: ContainsIncidence {
157 /// Returns whether `endpoint` is valid and visible in this graph view.
158 fn contains_endpoint(&self, endpoint: Self::IncidenceId) -> bool {
159 self.contains_incidence(endpoint)
160 }
161}
162
163impl<T> ContainsEndpoint for T where T: ContainsIncidence {}
164
165/// Capability for resolving directed edge sources.
166///
167/// Separated from [`EdgeTargetGraph`] because some layouts (e.g. outgoing-only
168/// CSR) can resolve targets cheaply but need extra indexing for sources.
169pub trait EdgeSourceGraph: TopologyBase {
170 /// Returns the source node of `edge`. `edge` must be a valid edge ID.
171 fn source(&self, edge: Self::RelationId) -> Self::ElementId;
172}
173
174/// Capability for resolving directed edge targets.
175///
176/// The endpoint capability needed by outgoing traversal: an outgoing edge ID
177/// can be mapped to the node it reaches without requiring the backend to
178/// support reverse source lookup.
179pub trait EdgeTargetGraph: TopologyBase {
180 /// Returns the target node of `edge`. `edge` must be a valid edge ID.
181 fn target(&self, edge: Self::RelationId) -> Self::ElementId;
182}
183
184/// Capability for resolving both directed edge endpoints.
185///
186/// Binary graph form of complete relation endpoint lookup. Implementations may
187/// back it with an edge table, compact arrays, generated edges, or validated
188/// snapshot sections.
189pub trait EdgeEndpointGraph: EdgeSourceGraph + EdgeTargetGraph {
190 /// Returns `(source, target)` for `edge`. `edge` must be a valid edge ID.
191 fn endpoints(&self, edge: Self::RelationId) -> (Self::ElementId, Self::ElementId) {
192 (self.source(edge), self.target(edge))
193 }
194}
195
196impl<T> EdgeEndpointGraph for T where T: EdgeSourceGraph + EdgeTargetGraph {}
197
198/// Capability for traversing outgoing edges from a source node.
199///
200/// The generic associated iterator type lets each backend return its own
201/// concrete iterator without allocation or dynamic dispatch.
202pub trait OutgoingGraph: TopologyBase {
203 /// Iterator over edge IDs leaving one source node.
204 type OutEdges<'view>: Iterator<Item = Self::RelationId>
205 where
206 Self: 'view;
207
208 /// Returns edges whose source is `node`.
209 fn outgoing_edges(&self, node: Self::ElementId) -> Self::OutEdges<'_>;
210}
211
212/// Capability for traversing incoming edges to a target node.
213///
214/// Separate from [`OutgoingGraph`] because many layouts only provide one
215/// direction cheaply.
216pub trait IncomingGraph: TopologyBase {
217 /// Iterator over edge IDs entering one target node.
218 type InEdges<'view>: Iterator<Item = Self::RelationId>
219 where
220 Self: 'view;
221
222 /// Returns edges whose target is `node`.
223 fn incoming_edges(&self, node: Self::ElementId) -> Self::InEdges<'_>;
224}
225
226/// Capability for traversing directly reachable outgoing neighbor nodes.
227///
228/// Graph-facing name for [`ElementSuccessors`]. Answers `node -> successor
229/// nodes` without requiring callers to materialize outgoing edge IDs and
230/// resolve each edge target. Implementations define whether parallel edges
231/// produce repeated neighbor nodes; those that preserve graph edge order and
232/// multiplicity should document that behavior.
233pub trait OutgoingNeighborsGraph: ElementSuccessors {
234 /// Iterator over nodes directly reachable from one source node.
235 type OutNeighbors<'view>: Iterator<Item = Self::ElementId>
236 where
237 Self: 'view;
238
239 /// Returns neighbor nodes reached by outgoing edges from `node`.
240 fn outgoing_neighbors(&self, node: Self::ElementId) -> Self::OutNeighbors<'_>;
241}
242
243impl<T> OutgoingNeighborsGraph for T
244where
245 T: ElementSuccessors,
246{
247 type OutNeighbors<'view>
248 = <T as ElementSuccessors>::Successors<'view>
249 where
250 T: 'view;
251
252 fn outgoing_neighbors(&self, node: Self::ElementId) -> Self::OutNeighbors<'_> {
253 <Self as ElementSuccessors>::element_successors(self, node)
254 }
255}
256
257/// Capability for traversing directly preceding incoming neighbor nodes.
258///
259/// Graph-facing name for [`ElementPredecessors`]. Answers `node ->
260/// predecessor nodes` without requiring callers to materialize incoming edge
261/// IDs and resolve each edge source.
262pub trait IncomingNeighborsGraph: ElementPredecessors {
263 /// Iterator over nodes that have incoming edges to one target node.
264 type InNeighbors<'view>: Iterator<Item = Self::ElementId>
265 where
266 Self: 'view;
267
268 /// Returns predecessor nodes with incoming edges to `node`.
269 fn incoming_neighbors(&self, node: Self::ElementId) -> Self::InNeighbors<'_>;
270}
271
272impl<T> IncomingNeighborsGraph for T
273where
274 T: ElementPredecessors,
275{
276 type InNeighbors<'view>
277 = <T as ElementPredecessors>::Predecessors<'view>
278 where
279 T: 'view;
280
281 fn incoming_neighbors(&self, node: Self::ElementId) -> Self::InNeighbors<'_> {
282 <Self as ElementPredecessors>::element_predecessors(self, node)
283 }
284}
285
286/// Exact outgoing-edge count capability.
287///
288/// Pairs with [`OutgoingGraph`] for backends that can report out-degree
289/// without traversal; does not require outgoing traversal support by itself.
290pub trait OutgoingEdgeCount: TopologyBase {
291 /// Returns the number of edges leaving `node`.
292 fn out_degree(&self, node: Self::ElementId) -> usize;
293}
294
295/// Exact incoming-edge count capability.
296///
297/// Pairs with [`IncomingGraph`] for backends that can report in-degree
298/// without traversal; does not require incoming traversal support by itself.
299pub trait IncomingEdgeCount: TopologyBase {
300 /// Returns the number of edges entering `node`.
301 fn in_degree(&self, node: Self::ElementId) -> usize;
302}
303
304/// Convenience marker bundling endpoint resolution and both traversal
305/// directions. One-direction layouts should implement the smaller capability
306/// traits they can provide instead.
307pub trait DirectedGraph: EdgeEndpointGraph + OutgoingGraph + IncomingGraph {}
308
309impl<T> DirectedGraph for T where T: EdgeEndpointGraph + OutgoingGraph + IncomingGraph {}
310
311/// Convenience marker for forward directed graph traversal (target lookup +
312/// outgoing edge iteration).
313pub trait ForwardGraph: EdgeTargetGraph + OutgoingGraph {}
314
315impl<T> ForwardGraph for T where T: EdgeTargetGraph + OutgoingGraph {}
316
317/// Convenience marker for reverse directed graph traversal (source lookup +
318/// incoming edge iteration). Expected to be provided by CSC-backed views.
319pub trait ReverseGraph: EdgeSourceGraph + IncomingGraph {}
320
321impl<T> ReverseGraph for T where T: EdgeSourceGraph + IncomingGraph {}