oxgraph_topology/lib.rs
1//! Storage-agnostic traits for discrete topology views.
2//!
3//! `oxgraph-topology` defines the minimal vocabulary shared by graph,
4//! hypergraph, snapshot, and layout crates. It does not define concrete node,
5//! edge, vertex, hyperedge, incidence, storage, or role types. Implementations
6//! provide those through associated types.
7//!
8//! This crate defines read-view capabilities. Mutation belongs in explicit
9//! capability traits that define identity stability, deletion, compaction, and
10//! stale-handle semantics.
11//!
12//! A topology view is any value that exposes topology through these traits. The
13//! view decides its own boundary: an entire snapshot, one layout section, a
14//! generated projection, a page-sized window, or an overlay can all be views if
15//! they provide the requested capabilities.
16#![no_std]
17
18#[cfg(kani)]
19extern crate kani;
20
21/// Marker trait for compact topology identity handles.
22///
23/// IDs are handles into topology storage, not the storage itself. They are
24/// passed by value so traversal APIs can remain simple and static-dispatch
25/// friendly. A logical element, relation, or incidence can have different ID
26/// representations at different layers. Implementations should document which
27/// identity layer each ID type represents and how it maps to other exposed
28/// identity layers.
29///
30/// # Performance
31///
32/// Implementations are expected to be small `Copy` handles. Copying,
33/// comparing, ordering, hashing, and formatting for debug should be `O(1)`.
34pub trait TopologyId: Copy + Eq + Ord + core::fmt::Debug + core::hash::Hash {}
35
36/// Blanket implementation for compact ID handle types.
37///
38/// Any type satisfying the `TopologyId` bounds is a valid topology ID. This
39/// keeps the crate trait-based without requiring implementations to write empty
40/// marker impls for every local handle type.
41///
42/// # Performance
43///
44/// `perf: unspecified`; performance is inherited from the concrete ID type.
45impl<T> TopologyId for T where T: Copy + Eq + Ord + core::fmt::Debug + core::hash::Hash {}
46
47/// Common element and relation identity vocabulary for a topology view.
48///
49/// The associated ID types deliberately avoid graph- or hypergraph-specific
50/// names. Graph crates can map elements to nodes and relations to edges;
51/// hypergraph crates can map elements to vertices and relations to hyperedges.
52///
53/// # Performance
54///
55/// Associated ID values should be compact `O(1)` handles. Arbitrary relation or
56/// element payloads should be exposed by separate traits keyed by the associated
57/// ID types.
58pub trait TopologyBase {
59 /// Identity of a topology element.
60 ///
61 /// # Performance
62 ///
63 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
64 type ElementId: TopologyId;
65
66 /// Identity of a topology relation.
67 ///
68 /// # Performance
69 ///
70 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
71 type RelationId: TopologyId;
72}
73
74/// Substrate-neutral alias for a topology view's element ID type.
75///
76/// # Performance
77///
78/// `perf: unspecified`; performance is inherited from the underlying
79/// [`TopologyBase::ElementId`] type.
80pub type ElementId<T> = <T as TopologyBase>::ElementId;
81
82/// Substrate-neutral alias for a topology view's relation ID type.
83///
84/// # Performance
85///
86/// `perf: unspecified`; performance is inherited from the underlying
87/// [`TopologyBase::RelationId`] type.
88pub type RelationId<T> = <T as TopologyBase>::RelationId;
89
90/// Optional total weight capability for topology elements.
91///
92/// A view implements this trait only when every visible element has a weight
93/// representation. The topology layer does not interpret the value: it is not a
94/// probability, cost, distance, count, or property name. Algorithms state their
95/// own numeric contracts when they consume a selected weight capability.
96///
97/// # Performance
98///
99/// Lookup should be `O(1)` unless an implementation documents a weaker
100/// contract.
101pub trait ElementWeight: TopologyBase {
102 /// Copyable weight representation attached to each visible element.
103 ///
104 /// # Performance
105 ///
106 /// Values should be `O(1)` to copy.
107 type Weight: Copy;
108
109 /// Returns the weight attached to `element`.
110 ///
111 /// # Performance
112 ///
113 /// Expected `O(1)` unless the implementation documents otherwise.
114 fn element_weight(&self, element: Self::ElementId) -> Self::Weight;
115}
116
117/// Optional total weight capability for topology relations.
118///
119/// A view implements this trait only when every visible relation has a weight
120/// representation. The topology layer does not interpret the value; algorithms
121/// define any finite, non-negative, additive, ordered, or normalization
122/// requirements separately.
123///
124/// # Performance
125///
126/// Lookup should be `O(1)` unless an implementation documents a weaker
127/// contract.
128pub trait RelationWeight: TopologyBase {
129 /// Copyable weight representation attached to each visible relation.
130 ///
131 /// # Performance
132 ///
133 /// Values should be `O(1)` to copy.
134 type Weight: Copy;
135
136 /// Returns the weight attached to `relation`.
137 ///
138 /// # Performance
139 ///
140 /// Expected `O(1)` unless the implementation documents otherwise.
141 fn relation_weight(&self, relation: Self::RelationId) -> Self::Weight;
142}
143
144/// Optional local-to-canonical element identity capability.
145///
146/// Views implement this trait only when they guarantee a stable canonical ID for
147/// every visible element in the view's documented identity scope. The canonical
148/// ID is a substrate identity, not a Python label or domain identifier.
149///
150/// # Performance
151///
152/// Lookup should be `O(1)` unless an implementation documents a weaker
153/// contract.
154pub trait CanonicalElementIdentity: TopologyBase {
155 /// Canonical element ID guaranteed by this view.
156 ///
157 /// # Performance
158 ///
159 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
160 type CanonicalElementId: TopologyId;
161
162 /// Returns the canonical ID for a visible local `element`.
163 ///
164 /// # Performance
165 ///
166 /// Expected `O(1)` unless the implementation documents otherwise.
167 fn canonical_element_id(&self, element: Self::ElementId) -> Self::CanonicalElementId;
168}
169
170/// Optional canonical-to-local element identity capability.
171///
172/// This reverse lookup is separate from [`CanonicalElementIdentity`] because it
173/// may require extra memory or may be partial for filtered and projected views.
174///
175/// # Performance
176///
177/// Lookup should be `O(1)` unless an implementation documents a weaker
178/// contract.
179pub trait LocalElementIdentity: CanonicalElementIdentity {
180 /// Returns the visible local element for `canonical`, if present.
181 ///
182 /// # Performance
183 ///
184 /// Expected `O(1)` unless the implementation documents otherwise.
185 fn local_element_id(&self, canonical: Self::CanonicalElementId) -> Option<Self::ElementId>;
186}
187
188/// Optional local-to-canonical relation identity capability.
189///
190/// Views implement this trait only when they guarantee a stable canonical ID for
191/// every visible relation in the view's documented identity scope.
192///
193/// # Performance
194///
195/// Lookup should be `O(1)` unless an implementation documents a weaker
196/// contract.
197pub trait CanonicalRelationIdentity: TopologyBase {
198 /// Canonical relation ID guaranteed by this view.
199 ///
200 /// # Performance
201 ///
202 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
203 type CanonicalRelationId: TopologyId;
204
205 /// Returns the canonical ID for a visible local `relation`.
206 ///
207 /// # Performance
208 ///
209 /// Expected `O(1)` unless the implementation documents otherwise.
210 fn canonical_relation_id(&self, relation: Self::RelationId) -> Self::CanonicalRelationId;
211}
212
213/// Optional canonical-to-local relation identity capability.
214///
215/// This reverse lookup is separate from [`CanonicalRelationIdentity`] because it
216/// may require extra memory or may be partial for filtered and projected views.
217///
218/// # Performance
219///
220/// Lookup should be `O(1)` unless an implementation documents a weaker
221/// contract.
222pub trait LocalRelationIdentity: CanonicalRelationIdentity {
223 /// Returns the visible local relation for `canonical`, if present.
224 ///
225 /// # Performance
226 ///
227 /// Expected `O(1)` unless the implementation documents otherwise.
228 fn local_relation_id(&self, canonical: Self::CanonicalRelationId) -> Option<Self::RelationId>;
229}
230
231/// Incidence identity and role vocabulary for topology views with incidences.
232///
233/// Incidence support is separate from [`TopologyBase`] so graph-only views can
234/// expose nodes and edges without inventing endpoint identities or roles. Views
235/// that support relation-to-element participation records implement this trait.
236///
237/// # Performance
238///
239/// Associated ID values should be compact `O(1)` handles. `Role` describes how
240/// an element participates in a relation. Arbitrary incidence payloads should be
241/// exposed by separate traits keyed by [`Self::IncidenceId`].
242pub trait IncidenceBase: TopologyBase {
243 /// Identity of one element's participation in one relation.
244 ///
245 /// # Performance
246 ///
247 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
248 type IncidenceId: TopologyId;
249
250 /// Implementation-defined participation role.
251 ///
252 /// A role is a topology-level label for an incidence. Rich metadata can be
253 /// attached by separate payload traits or storage layers keyed by
254 /// [`Self::IncidenceId`], [`Self::RelationId`], or [`Self::ElementId`].
255 ///
256 /// The `Copy + Eq + Debug` bound lets role-aware generic algorithms compare,
257 /// copy, and debug-format roles without each consumer restating the bound;
258 /// the role's *meaning* stays implementation-defined.
259 ///
260 /// # Performance
261 ///
262 /// `perf: unspecified`. Implementations should prefer structural role
263 /// values or compact role handles; rich metadata should be reached through
264 /// separate payload access traits.
265 type Role: Copy + Eq + core::fmt::Debug;
266}
267
268/// Optional total weight capability for topology incidences.
269///
270/// A view implements this trait only when every visible incidence has a weight
271/// representation. The topology layer does not interpret the value; algorithms
272/// define their own numeric contracts separately.
273///
274/// # Performance
275///
276/// Lookup should be `O(1)` unless an implementation documents a weaker
277/// contract.
278pub trait IncidenceWeight: IncidenceBase {
279 /// Copyable weight representation attached to each visible incidence.
280 ///
281 /// # Performance
282 ///
283 /// Values should be `O(1)` to copy.
284 type Weight: Copy;
285
286 /// Returns the weight attached to `incidence`.
287 ///
288 /// # Performance
289 ///
290 /// Expected `O(1)` unless the implementation documents otherwise.
291 fn incidence_weight(&self, incidence: Self::IncidenceId) -> Self::Weight;
292}
293
294/// Optional local-to-canonical incidence identity capability.
295///
296/// Views implement this trait only when they guarantee a stable canonical ID for
297/// every visible incidence in the view's documented identity scope.
298///
299/// # Performance
300///
301/// Lookup should be `O(1)` unless an implementation documents a weaker
302/// contract.
303pub trait CanonicalIncidenceIdentity: IncidenceBase {
304 /// Canonical incidence ID guaranteed by this view.
305 ///
306 /// # Performance
307 ///
308 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
309 type CanonicalIncidenceId: TopologyId;
310
311 /// Returns the canonical ID for a visible local `incidence`.
312 ///
313 /// # Performance
314 ///
315 /// Expected `O(1)` unless the implementation documents otherwise.
316 fn canonical_incidence_id(&self, incidence: Self::IncidenceId) -> Self::CanonicalIncidenceId;
317}
318
319/// Optional canonical-to-local incidence identity capability.
320///
321/// This reverse lookup is separate from [`CanonicalIncidenceIdentity`] because
322/// it may require extra memory or may be partial for filtered and projected
323/// views.
324///
325/// # Performance
326///
327/// Lookup should be `O(1)` unless an implementation documents a weaker
328/// contract.
329pub trait LocalIncidenceIdentity: CanonicalIncidenceIdentity {
330 /// Returns the visible local incidence for `canonical`, if present.
331 ///
332 /// # Performance
333 ///
334 /// Expected `O(1)` unless the implementation documents otherwise.
335 fn local_incidence_id(
336 &self,
337 canonical: Self::CanonicalIncidenceId,
338 ) -> Option<Self::IncidenceId>;
339}
340
341/// Count capability for a topology view.
342///
343/// This trait is separated from [`TopologyBase`] because counts are a capability.
344/// Some views can report global counts cheaply; others expose only local,
345/// paged, generated, or filtered topology and should define counts only when the
346/// result is meaningful for that view.
347///
348/// # Performance
349///
350/// Methods should be `O(1)` unless an implementation documents a weaker
351/// contract.
352pub trait TopologyCounts: TopologyBase {
353 /// Returns the number of elements visible in this topology view.
354 ///
355 /// # Performance
356 ///
357 /// Expected `O(1)` unless the implementation documents otherwise.
358 fn element_count(&self) -> usize;
359
360 /// Returns the number of relations visible in this topology view.
361 ///
362 /// # Performance
363 ///
364 /// Expected `O(1)` unless the implementation documents otherwise.
365 fn relation_count(&self) -> usize;
366}
367
368/// Count capability for incidence-capable topology views.
369///
370/// This trait is separated from [`TopologyCounts`] because not every topology
371/// view exposes incidence records. Graph-only views can count nodes and edges
372/// without defining endpoint-incidence identities.
373///
374/// # Performance
375///
376/// Methods should be `O(1)` unless an implementation documents a weaker
377/// contract.
378pub trait IncidenceCounts: IncidenceBase {
379 /// Returns the number of incidences visible in this topology view.
380 ///
381 /// # Performance
382 ///
383 /// Expected `O(1)` unless the implementation documents otherwise.
384 fn incidence_count(&self) -> usize;
385}
386
387/// Dense element-index capability for topology views.
388///
389/// This capability maps visible element IDs to compact array indexes usable by
390/// algorithms that need visited sets, distance arrays, parent arrays, or other
391/// per-element scratch storage. The index is a property of the view, not the ID
392/// type itself: a view may expose opaque IDs while also providing a dense index
393/// mapping.
394///
395/// `element_bound` is an allocation bound, not necessarily the exact visible
396/// element count. Immutable compact layouts usually have `element_bound() ==
397/// element_count()`. Mutable layouts with tombstones, overlays, or stable slots
398/// may have `element_bound() >= element_count()`.
399///
400/// Implementations must ensure every valid visible element maps to an index less
401/// than `element_bound`, distinct visible elements map to distinct indexes, and
402/// indexes remain stable for the lifetime of the view operation using them.
403///
404/// # Performance
405///
406/// Methods should be `O(1)` unless an implementation documents a weaker
407/// contract.
408pub trait ElementIndex: TopologyBase {
409 /// Returns the exclusive upper bound for element indexes in this view.
410 ///
411 /// # Performance
412 ///
413 /// Expected `O(1)` unless the implementation documents otherwise.
414 fn element_bound(&self) -> usize;
415
416 /// Returns the dense index for `element` in this view.
417 ///
418 /// # Performance
419 ///
420 /// Expected `O(1)` unless the implementation documents otherwise.
421 fn element_index(&self, element: Self::ElementId) -> usize;
422}
423
424/// Dense relation-index capability for topology views.
425///
426/// This capability maps visible relation IDs to compact array indexes usable by
427/// algorithms that need per-relation scratch storage. The index is a property of
428/// the view, not the ID type itself.
429///
430/// `relation_bound` is an allocation bound, not necessarily the exact visible
431/// relation count. Immutable compact layouts usually have `relation_bound() ==
432/// relation_count()`. Mutable layouts may expose a larger bound.
433///
434/// Implementations must ensure every valid visible relation maps to an index
435/// less than `relation_bound`, distinct visible relations map to distinct
436/// indexes, and indexes remain stable for the lifetime of the view operation
437/// using them.
438///
439/// # Performance
440///
441/// Methods should be `O(1)` unless an implementation documents a weaker
442/// contract.
443pub trait RelationIndex: TopologyBase {
444 /// Returns the exclusive upper bound for relation indexes in this view.
445 ///
446 /// # Performance
447 ///
448 /// Expected `O(1)` unless the implementation documents otherwise.
449 fn relation_bound(&self) -> usize;
450
451 /// Returns the dense index for `relation` in this view.
452 ///
453 /// # Performance
454 ///
455 /// Expected `O(1)` unless the implementation documents otherwise.
456 fn relation_index(&self, relation: Self::RelationId) -> usize;
457}
458
459/// Dense incidence-index capability for topology views.
460///
461/// This capability maps visible incidence IDs to compact array indexes usable by
462/// algorithms that need per-incidence scratch storage. Views that do not expose
463/// incidences do not implement this trait.
464///
465/// `incidence_bound` is an allocation bound, not necessarily the exact visible
466/// incidence count. Immutable compact layouts usually have `incidence_bound() ==
467/// incidence_count()`. Mutable layouts may expose a larger bound.
468///
469/// Implementations must ensure every valid visible incidence maps to an index
470/// less than `incidence_bound`, distinct visible incidences map to distinct
471/// indexes, and indexes remain stable for the lifetime of the view operation
472/// using them.
473///
474/// # Performance
475///
476/// Methods should be `O(1)` unless an implementation documents a weaker
477/// contract.
478pub trait IncidenceIndex: IncidenceBase {
479 /// Returns the exclusive upper bound for incidence indexes in this view.
480 ///
481 /// # Performance
482 ///
483 /// Expected `O(1)` unless the implementation documents otherwise.
484 fn incidence_bound(&self) -> usize;
485
486 /// Returns the dense index for `incidence` in this view.
487 ///
488 /// # Performance
489 ///
490 /// Expected `O(1)` unless the implementation documents otherwise.
491 fn incidence_index(&self, incidence: Self::IncidenceId) -> usize;
492}
493
494/// Element-ID containment capability for a topology view.
495///
496/// This capability answers whether an element ID is valid and visible in this
497/// view at the time of the call. It is intentionally separate from
498/// [`ElementIndex`]: an index bound is an allocation bound, while containment is
499/// an ID-validity predicate. Mutable, filtered, tombstoned, or overlay views may
500/// have indexes below the bound that are not visible elements.
501///
502/// # Performance
503///
504/// Expected `O(1)` unless the implementation documents otherwise.
505pub trait ContainsElement: TopologyBase {
506 /// Returns whether `element` is valid and visible in this view.
507 ///
508 /// # Performance
509 ///
510 /// Expected `O(1)` unless the implementation documents otherwise.
511 fn contains_element(&self, element: Self::ElementId) -> bool;
512}
513
514/// Relation-ID containment capability for a topology view.
515///
516/// This capability answers whether a relation ID is valid and visible in this
517/// view at the time of the call. It does not answer graph-specific questions
518/// such as whether an edge between two nodes exists, nor hypergraph-specific
519/// questions such as whether a vertex participates in a hyperedge.
520///
521/// # Performance
522///
523/// Expected `O(1)` unless the implementation documents otherwise.
524pub trait ContainsRelation: TopologyBase {
525 /// Returns whether `relation` is valid and visible in this view.
526 ///
527 /// # Performance
528 ///
529 /// Expected `O(1)` unless the implementation documents otherwise.
530 fn contains_relation(&self, relation: Self::RelationId) -> bool;
531}
532
533/// Incidence-ID containment capability for an incidence-capable topology view.
534///
535/// This capability answers whether an incidence ID is valid and visible in this
536/// view at the time of the call.
537///
538/// # Performance
539///
540/// Expected `O(1)` unless the implementation documents otherwise.
541pub trait ContainsIncidence: IncidenceBase {
542 /// Returns whether `incidence` is valid and visible in this view.
543 ///
544 /// # Performance
545 ///
546 /// Expected `O(1)` unless the implementation documents otherwise.
547 fn contains_incidence(&self, incidence: Self::IncidenceId) -> bool;
548}
549
550/// Capability for traversing incidences attached to a relation.
551///
552/// The generic associated iterator type lets each backend return its own
553/// concrete iterator without allocating or using dynamic dispatch.
554///
555/// # Performance
556///
557/// Creating the iterator should be `O(1)` unless an implementation documents a
558/// weaker contract. Yielding `k` incidences should be `O(k)` because the output
559/// itself has length `k`.
560pub trait RelationIncidences: IncidenceBase {
561 /// Iterator over incidence IDs for one relation.
562 ///
563 /// # Performance
564 ///
565 /// Advancing the iterator should be amortized `O(1)` unless an
566 /// implementation documents otherwise.
567 type Incidences<'view>: Iterator<Item = Self::IncidenceId>
568 where
569 Self: 'view;
570
571 /// Returns incidences attached to `relation`.
572 ///
573 /// # Performance
574 ///
575 /// Expected `O(1)` to create the iterator; yielding `k` incidences is
576 /// expected `O(k)`.
577 fn relation_incidences(&self, relation: Self::RelationId) -> Self::Incidences<'_>;
578}
579
580/// Capability for traversing incidences attached to an element.
581///
582/// This is the topology-general form of asking which relations mention an
583/// element.
584///
585/// # Performance
586///
587/// Creating the iterator should be `O(1)` unless an implementation documents a
588/// weaker contract. Yielding `k` incidences should be `O(k)` because the output
589/// itself has length `k`.
590pub trait ElementIncidences: IncidenceBase {
591 /// Iterator over incidence IDs for one element.
592 ///
593 /// # Performance
594 ///
595 /// Advancing the iterator should be amortized `O(1)` unless an
596 /// implementation documents otherwise.
597 type Incidences<'view>: Iterator<Item = Self::IncidenceId>
598 where
599 Self: 'view;
600
601 /// Returns incidences attached to `element`.
602 ///
603 /// # Performance
604 ///
605 /// Expected `O(1)` to create the iterator; yielding `k` incidences is
606 /// expected `O(k)`.
607 fn element_incidences(&self, element: Self::ElementId) -> Self::Incidences<'_>;
608}
609
610/// Capability for resolving the element side of an incidence.
611///
612/// # Performance
613///
614/// Lookup should be `O(1)` unless an implementation documents a weaker
615/// contract.
616pub trait IncidenceElement: IncidenceBase {
617 /// Returns the element participating through `incidence`.
618 ///
619 /// # Performance
620 ///
621 /// Expected `O(1)` unless the implementation documents otherwise.
622 fn incidence_element(&self, incidence: Self::IncidenceId) -> Self::ElementId;
623}
624
625/// Capability for resolving the relation side of an incidence.
626///
627/// # Performance
628///
629/// Lookup should be `O(1)` unless an implementation documents a weaker
630/// contract.
631pub trait IncidenceRelation: IncidenceBase {
632 /// Returns the relation containing `incidence`.
633 ///
634 /// # Performance
635 ///
636 /// Expected `O(1)` unless the implementation documents otherwise.
637 fn incidence_relation(&self, incidence: Self::IncidenceId) -> Self::RelationId;
638}
639
640/// Capability for resolving a role attached to an incidence.
641///
642/// Roles are implementation-defined topology labels. The core never
643/// interprets them.
644///
645/// # Performance
646///
647/// Lookup should be `O(1)` unless an implementation documents a weaker
648/// contract.
649pub trait IncidenceRole: IncidenceBase {
650 /// Returns the role for `incidence`.
651 ///
652 /// # Performance
653 ///
654 /// Expected `O(1)` unless the implementation documents otherwise.
655 fn incidence_role(&self, incidence: Self::IncidenceId) -> Self::Role;
656}
657
658/// Exact relation-incidence count capability.
659///
660/// This pairs with [`RelationIncidences`] for backends that can report a
661/// relation's incidence count without traversal. The trait does not require
662/// traversal support by itself.
663///
664/// # Performance
665///
666/// Expected `O(1)` unless the implementation documents otherwise.
667pub trait RelationIncidenceCount: IncidenceBase {
668 /// Returns the number of incidences attached to `relation`.
669 ///
670 /// # Performance
671 ///
672 /// Expected `O(1)` unless the implementation documents otherwise.
673 fn relation_incidence_count(&self, relation: Self::RelationId) -> usize;
674}
675
676/// Exact element-incidence count capability.
677///
678/// This pairs with [`ElementIncidences`] for backends that can report an
679/// element's incidence count without traversal. The trait does not require
680/// traversal support by itself.
681///
682/// # Performance
683///
684/// Expected `O(1)` unless the implementation documents otherwise.
685pub trait ElementIncidenceCount: IncidenceBase {
686 /// Returns the number of incidences attached to `element`.
687 ///
688 /// # Performance
689 ///
690 /// Expected `O(1)` unless the implementation documents otherwise.
691 fn element_incidence_count(&self, element: Self::ElementId) -> usize;
692}
693
694/// Convenience trait for views that can resolve complete incidence records.
695///
696/// This trait has no methods of its own. It names the common capability bundle
697/// needed by generic code that wants to traverse relations and inspect each
698/// incidence's element, relation, and role.
699///
700/// # Performance
701///
702/// `perf: unspecified`; performance is inherited from the component traits.
703pub trait IncidenceView:
704 RelationIncidences + IncidenceElement + IncidenceRelation + IncidenceRole
705{
706}
707
708/// Blanket implementation for complete incidence views.
709///
710/// Any type that can traverse relation incidences and resolve each incidence's
711/// element, relation, and role automatically implements [`IncidenceView`].
712///
713/// # Performance
714///
715/// `perf: unspecified`; performance is inherited from the component traits.
716impl<T> IncidenceView for T where
717 T: RelationIncidences + IncidenceElement + IncidenceRelation + IncidenceRole
718{
719}
720
721/// Capability for expanding an element to its directed successor elements.
722///
723/// This is the substrate-neutral form of "follow outgoing connections from
724/// this element." For binary graphs the successors are the targets of
725/// outgoing edges; for hypergraphs they are the vertices reachable through
726/// outgoing hyperedges. Substrate-agnostic algorithms (forward BFS, forward
727/// reachability) bind on this trait so the same code drives any topology
728/// view that can answer the question.
729///
730/// Implementations define whether parallel connections produce repeated
731/// successor elements. Implementations that preserve multiplicity should
732/// document that behavior; consumers that need set semantics should
733/// deduplicate at their own level.
734///
735/// # Performance
736///
737/// Creating the iterator should be `O(1)` unless an implementation documents a
738/// weaker contract. Yielding `k` successors should be `O(k)` and should not
739/// allocate unless the implementation documents otherwise.
740pub trait ElementSuccessors: TopologyBase {
741 /// Iterator over successor element IDs reached from one element.
742 ///
743 /// # Performance
744 ///
745 /// Advancing the iterator should be amortized `O(1)` unless an
746 /// implementation documents otherwise.
747 type Successors<'view>: Iterator<Item = Self::ElementId>
748 where
749 Self: 'view;
750
751 /// Returns elements reachable through outgoing connections from `element`.
752 ///
753 /// # Performance
754 ///
755 /// Expected `O(1)` to create the iterator; yielding `k` successors is
756 /// expected `O(k)`.
757 fn element_successors(&self, element: Self::ElementId) -> Self::Successors<'_>;
758}
759
760/// Capability for expanding an element to its directed predecessor elements.
761///
762/// This is the substrate-neutral form of "follow incoming connections to this
763/// element." For binary graphs the predecessors are the sources of incoming
764/// edges; for hypergraphs they are the vertices that reach this vertex
765/// through outgoing hyperedges. Substrate-agnostic algorithms (reverse BFS,
766/// reverse reachability) bind on this trait so the same code drives any
767/// topology view that can answer the question.
768///
769/// Implementations define whether parallel connections produce repeated
770/// predecessor elements. Implementations that preserve multiplicity should
771/// document that behavior; consumers that need set semantics should
772/// deduplicate at their own level.
773///
774/// # Performance
775///
776/// Creating the iterator should be `O(1)` unless an implementation documents a
777/// weaker contract. Yielding `k` predecessors should be `O(k)` and should not
778/// allocate unless the implementation documents otherwise.
779pub trait ElementPredecessors: TopologyBase {
780 /// Iterator over predecessor element IDs reaching one element.
781 ///
782 /// # Performance
783 ///
784 /// Advancing the iterator should be amortized `O(1)` unless an
785 /// implementation documents otherwise.
786 type Predecessors<'view>: Iterator<Item = Self::ElementId>
787 where
788 Self: 'view;
789
790 /// Returns elements that reach `element` through outgoing connections.
791 ///
792 /// # Performance
793 ///
794 /// Expected `O(1)` to create the iterator; yielding `k` predecessors is
795 /// expected `O(k)`.
796 fn element_predecessors(&self, element: Self::ElementId) -> Self::Predecessors<'_>;
797}