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 /// # Performance
257 ///
258 /// `perf: unspecified`. Implementations should prefer structural role
259 /// values or compact role handles; rich metadata should be reached through
260 /// separate payload access traits.
261 type Role;
262}
263
264/// Optional total weight capability for topology incidences.
265///
266/// A view implements this trait only when every visible incidence has a weight
267/// representation. The topology layer does not interpret the value; algorithms
268/// define their own numeric contracts separately.
269///
270/// # Performance
271///
272/// Lookup should be `O(1)` unless an implementation documents a weaker
273/// contract.
274pub trait IncidenceWeight: IncidenceBase {
275 /// Copyable weight representation attached to each visible incidence.
276 ///
277 /// # Performance
278 ///
279 /// Values should be `O(1)` to copy.
280 type Weight: Copy;
281
282 /// Returns the weight attached to `incidence`.
283 ///
284 /// # Performance
285 ///
286 /// Expected `O(1)` unless the implementation documents otherwise.
287 fn incidence_weight(&self, incidence: Self::IncidenceId) -> Self::Weight;
288}
289
290/// Optional local-to-canonical incidence identity capability.
291///
292/// Views implement this trait only when they guarantee a stable canonical ID for
293/// every visible incidence in the view's documented identity scope.
294///
295/// # Performance
296///
297/// Lookup should be `O(1)` unless an implementation documents a weaker
298/// contract.
299pub trait CanonicalIncidenceIdentity: IncidenceBase {
300 /// Canonical incidence ID guaranteed by this view.
301 ///
302 /// # Performance
303 ///
304 /// Values should be `O(1)` to copy, compare, order, hash, and debug-format.
305 type CanonicalIncidenceId: TopologyId;
306
307 /// Returns the canonical ID for a visible local `incidence`.
308 ///
309 /// # Performance
310 ///
311 /// Expected `O(1)` unless the implementation documents otherwise.
312 fn canonical_incidence_id(&self, incidence: Self::IncidenceId) -> Self::CanonicalIncidenceId;
313}
314
315/// Optional canonical-to-local incidence identity capability.
316///
317/// This reverse lookup is separate from [`CanonicalIncidenceIdentity`] because
318/// it may require extra memory or may be partial for filtered and projected
319/// views.
320///
321/// # Performance
322///
323/// Lookup should be `O(1)` unless an implementation documents a weaker
324/// contract.
325pub trait LocalIncidenceIdentity: CanonicalIncidenceIdentity {
326 /// Returns the visible local incidence for `canonical`, if present.
327 ///
328 /// # Performance
329 ///
330 /// Expected `O(1)` unless the implementation documents otherwise.
331 fn local_incidence_id(
332 &self,
333 canonical: Self::CanonicalIncidenceId,
334 ) -> Option<Self::IncidenceId>;
335}
336
337/// Count capability for a topology view.
338///
339/// This trait is separated from [`TopologyBase`] because counts are a capability.
340/// Some views can report global counts cheaply; others expose only local,
341/// paged, generated, or filtered topology and should define counts only when the
342/// result is meaningful for that view.
343///
344/// # Performance
345///
346/// Methods should be `O(1)` unless an implementation documents a weaker
347/// contract.
348pub trait TopologyCounts: TopologyBase {
349 /// Returns the number of elements visible in this topology view.
350 ///
351 /// # Performance
352 ///
353 /// Expected `O(1)` unless the implementation documents otherwise.
354 fn element_count(&self) -> usize;
355
356 /// Returns the number of relations visible in this topology view.
357 ///
358 /// # Performance
359 ///
360 /// Expected `O(1)` unless the implementation documents otherwise.
361 fn relation_count(&self) -> usize;
362}
363
364/// Count capability for incidence-capable topology views.
365///
366/// This trait is separated from [`TopologyCounts`] because not every topology
367/// view exposes incidence records. Graph-only views can count nodes and edges
368/// without defining endpoint-incidence identities.
369///
370/// # Performance
371///
372/// Methods should be `O(1)` unless an implementation documents a weaker
373/// contract.
374pub trait IncidenceCounts: IncidenceBase {
375 /// Returns the number of incidences visible in this topology view.
376 ///
377 /// # Performance
378 ///
379 /// Expected `O(1)` unless the implementation documents otherwise.
380 fn incidence_count(&self) -> usize;
381}
382
383/// Dense element-index capability for topology views.
384///
385/// This capability maps visible element IDs to compact array indexes usable by
386/// algorithms that need visited sets, distance arrays, parent arrays, or other
387/// per-element scratch storage. The index is a property of the view, not the ID
388/// type itself: a view may expose opaque IDs while also providing a dense index
389/// mapping.
390///
391/// `element_bound` is an allocation bound, not necessarily the exact visible
392/// element count. Immutable compact layouts usually have `element_bound() ==
393/// element_count()`. Mutable layouts with tombstones, overlays, or stable slots
394/// may have `element_bound() >= element_count()`.
395///
396/// Implementations must ensure every valid visible element maps to an index less
397/// than `element_bound`, distinct visible elements map to distinct indexes, and
398/// indexes remain stable for the lifetime of the view operation using them.
399///
400/// # Performance
401///
402/// Methods should be `O(1)` unless an implementation documents a weaker
403/// contract.
404pub trait ElementIndex: TopologyBase {
405 /// Returns the exclusive upper bound for element indexes in this view.
406 ///
407 /// # Performance
408 ///
409 /// Expected `O(1)` unless the implementation documents otherwise.
410 fn element_bound(&self) -> usize;
411
412 /// Returns the dense index for `element` in this view.
413 ///
414 /// # Performance
415 ///
416 /// Expected `O(1)` unless the implementation documents otherwise.
417 fn element_index(&self, element: Self::ElementId) -> usize;
418}
419
420/// Dense relation-index capability for topology views.
421///
422/// This capability maps visible relation IDs to compact array indexes usable by
423/// algorithms that need per-relation scratch storage. The index is a property of
424/// the view, not the ID type itself.
425///
426/// `relation_bound` is an allocation bound, not necessarily the exact visible
427/// relation count. Immutable compact layouts usually have `relation_bound() ==
428/// relation_count()`. Mutable layouts may expose a larger bound.
429///
430/// Implementations must ensure every valid visible relation maps to an index
431/// less than `relation_bound`, distinct visible relations map to distinct
432/// indexes, and indexes remain stable for the lifetime of the view operation
433/// using them.
434///
435/// # Performance
436///
437/// Methods should be `O(1)` unless an implementation documents a weaker
438/// contract.
439pub trait RelationIndex: TopologyBase {
440 /// Returns the exclusive upper bound for relation indexes in this view.
441 ///
442 /// # Performance
443 ///
444 /// Expected `O(1)` unless the implementation documents otherwise.
445 fn relation_bound(&self) -> usize;
446
447 /// Returns the dense index for `relation` in this view.
448 ///
449 /// # Performance
450 ///
451 /// Expected `O(1)` unless the implementation documents otherwise.
452 fn relation_index(&self, relation: Self::RelationId) -> usize;
453}
454
455/// Dense incidence-index capability for topology views.
456///
457/// This capability maps visible incidence IDs to compact array indexes usable by
458/// algorithms that need per-incidence scratch storage. Views that do not expose
459/// incidences do not implement this trait.
460///
461/// `incidence_bound` is an allocation bound, not necessarily the exact visible
462/// incidence count. Immutable compact layouts usually have `incidence_bound() ==
463/// incidence_count()`. Mutable layouts may expose a larger bound.
464///
465/// Implementations must ensure every valid visible incidence maps to an index
466/// less than `incidence_bound`, distinct visible incidences map to distinct
467/// indexes, and indexes remain stable for the lifetime of the view operation
468/// using them.
469///
470/// # Performance
471///
472/// Methods should be `O(1)` unless an implementation documents a weaker
473/// contract.
474pub trait IncidenceIndex: IncidenceBase {
475 /// Returns the exclusive upper bound for incidence indexes in this view.
476 ///
477 /// # Performance
478 ///
479 /// Expected `O(1)` unless the implementation documents otherwise.
480 fn incidence_bound(&self) -> usize;
481
482 /// Returns the dense index for `incidence` in this view.
483 ///
484 /// # Performance
485 ///
486 /// Expected `O(1)` unless the implementation documents otherwise.
487 fn incidence_index(&self, incidence: Self::IncidenceId) -> usize;
488}
489
490/// Element-ID containment capability for a topology view.
491///
492/// This capability answers whether an element ID is valid and visible in this
493/// view at the time of the call. It is intentionally separate from
494/// [`ElementIndex`]: an index bound is an allocation bound, while containment is
495/// an ID-validity predicate. Mutable, filtered, tombstoned, or overlay views may
496/// have indexes below the bound that are not visible elements.
497///
498/// # Performance
499///
500/// Expected `O(1)` unless the implementation documents otherwise.
501pub trait ContainsElement: TopologyBase {
502 /// Returns whether `element` is valid and visible in this view.
503 ///
504 /// # Performance
505 ///
506 /// Expected `O(1)` unless the implementation documents otherwise.
507 fn contains_element(&self, element: Self::ElementId) -> bool;
508}
509
510/// Relation-ID containment capability for a topology view.
511///
512/// This capability answers whether a relation ID is valid and visible in this
513/// view at the time of the call. It does not answer graph-specific questions
514/// such as whether an edge between two nodes exists, nor hypergraph-specific
515/// questions such as whether a vertex participates in a hyperedge.
516///
517/// # Performance
518///
519/// Expected `O(1)` unless the implementation documents otherwise.
520pub trait ContainsRelation: TopologyBase {
521 /// Returns whether `relation` is valid and visible in this view.
522 ///
523 /// # Performance
524 ///
525 /// Expected `O(1)` unless the implementation documents otherwise.
526 fn contains_relation(&self, relation: Self::RelationId) -> bool;
527}
528
529/// Incidence-ID containment capability for an incidence-capable topology view.
530///
531/// This capability answers whether an incidence ID is valid and visible in this
532/// view at the time of the call.
533///
534/// # Performance
535///
536/// Expected `O(1)` unless the implementation documents otherwise.
537pub trait ContainsIncidence: IncidenceBase {
538 /// Returns whether `incidence` is valid and visible in this view.
539 ///
540 /// # Performance
541 ///
542 /// Expected `O(1)` unless the implementation documents otherwise.
543 fn contains_incidence(&self, incidence: Self::IncidenceId) -> bool;
544}
545
546/// Capability for traversing incidences attached to a relation.
547///
548/// The generic associated iterator type lets each backend return its own
549/// concrete iterator without allocating or using dynamic dispatch.
550///
551/// # Performance
552///
553/// Creating the iterator should be `O(1)` unless an implementation documents a
554/// weaker contract. Yielding `k` incidences should be `O(k)` because the output
555/// itself has length `k`.
556pub trait RelationIncidences: IncidenceBase {
557 /// Iterator over incidence IDs for one relation.
558 ///
559 /// # Performance
560 ///
561 /// Advancing the iterator should be amortized `O(1)` unless an
562 /// implementation documents otherwise.
563 type Incidences<'view>: Iterator<Item = Self::IncidenceId>
564 where
565 Self: 'view;
566
567 /// Returns incidences attached to `relation`.
568 ///
569 /// # Performance
570 ///
571 /// Expected `O(1)` to create the iterator; yielding `k` incidences is
572 /// expected `O(k)`.
573 fn relation_incidences(&self, relation: Self::RelationId) -> Self::Incidences<'_>;
574}
575
576/// Capability for traversing incidences attached to an element.
577///
578/// This is the topology-general form of asking which relations mention an
579/// element.
580///
581/// # Performance
582///
583/// Creating the iterator should be `O(1)` unless an implementation documents a
584/// weaker contract. Yielding `k` incidences should be `O(k)` because the output
585/// itself has length `k`.
586pub trait ElementIncidences: IncidenceBase {
587 /// Iterator over incidence IDs for one element.
588 ///
589 /// # Performance
590 ///
591 /// Advancing the iterator should be amortized `O(1)` unless an
592 /// implementation documents otherwise.
593 type Incidences<'view>: Iterator<Item = Self::IncidenceId>
594 where
595 Self: 'view;
596
597 /// Returns incidences attached to `element`.
598 ///
599 /// # Performance
600 ///
601 /// Expected `O(1)` to create the iterator; yielding `k` incidences is
602 /// expected `O(k)`.
603 fn element_incidences(&self, element: Self::ElementId) -> Self::Incidences<'_>;
604}
605
606/// Capability for resolving the element side of an incidence.
607///
608/// # Performance
609///
610/// Lookup should be `O(1)` unless an implementation documents a weaker
611/// contract.
612pub trait IncidenceElement: IncidenceBase {
613 /// Returns the element participating through `incidence`.
614 ///
615 /// # Performance
616 ///
617 /// Expected `O(1)` unless the implementation documents otherwise.
618 fn incidence_element(&self, incidence: Self::IncidenceId) -> Self::ElementId;
619}
620
621/// Capability for resolving the relation side of an incidence.
622///
623/// # Performance
624///
625/// Lookup should be `O(1)` unless an implementation documents a weaker
626/// contract.
627pub trait IncidenceRelation: IncidenceBase {
628 /// Returns the relation containing `incidence`.
629 ///
630 /// # Performance
631 ///
632 /// Expected `O(1)` unless the implementation documents otherwise.
633 fn incidence_relation(&self, incidence: Self::IncidenceId) -> Self::RelationId;
634}
635
636/// Capability for resolving a role attached to an incidence.
637///
638/// Roles are implementation-defined topology labels. The core never
639/// interprets them.
640///
641/// # Performance
642///
643/// Lookup should be `O(1)` unless an implementation documents a weaker
644/// contract.
645pub trait IncidenceRole: IncidenceBase {
646 /// Returns the role for `incidence`.
647 ///
648 /// # Performance
649 ///
650 /// Expected `O(1)` unless the implementation documents otherwise.
651 fn incidence_role(&self, incidence: Self::IncidenceId) -> Self::Role;
652}
653
654/// Exact relation-incidence count capability.
655///
656/// This pairs with [`RelationIncidences`] for backends that can report a
657/// relation's incidence count without traversal. The trait does not require
658/// traversal support by itself.
659///
660/// # Performance
661///
662/// Expected `O(1)` unless the implementation documents otherwise.
663pub trait RelationIncidenceCount: IncidenceBase {
664 /// Returns the number of incidences attached to `relation`.
665 ///
666 /// # Performance
667 ///
668 /// Expected `O(1)` unless the implementation documents otherwise.
669 fn relation_incidence_count(&self, relation: Self::RelationId) -> usize;
670}
671
672/// Exact element-incidence count capability.
673///
674/// This pairs with [`ElementIncidences`] for backends that can report an
675/// element's incidence count without traversal. The trait does not require
676/// traversal support by itself.
677///
678/// # Performance
679///
680/// Expected `O(1)` unless the implementation documents otherwise.
681pub trait ElementIncidenceCount: IncidenceBase {
682 /// Returns the number of incidences attached to `element`.
683 ///
684 /// # Performance
685 ///
686 /// Expected `O(1)` unless the implementation documents otherwise.
687 fn element_incidence_count(&self, element: Self::ElementId) -> usize;
688}
689
690/// Convenience trait for views that can resolve complete incidence records.
691///
692/// This trait has no methods of its own. It names the common capability bundle
693/// needed by generic code that wants to traverse relations and inspect each
694/// incidence's element, relation, and role.
695///
696/// # Performance
697///
698/// `perf: unspecified`; performance is inherited from the component traits.
699pub trait IncidenceView:
700 RelationIncidences + IncidenceElement + IncidenceRelation + IncidenceRole
701{
702}
703
704/// Blanket implementation for complete incidence views.
705///
706/// Any type that can traverse relation incidences and resolve each incidence's
707/// element, relation, and role automatically implements [`IncidenceView`].
708///
709/// # Performance
710///
711/// `perf: unspecified`; performance is inherited from the component traits.
712impl<T> IncidenceView for T where
713 T: RelationIncidences + IncidenceElement + IncidenceRelation + IncidenceRole
714{
715}
716
717/// Capability for expanding an element to its directed successor elements.
718///
719/// This is the substrate-neutral form of "follow outgoing connections from
720/// this element." For binary graphs the successors are the targets of
721/// outgoing edges; for hypergraphs they are the vertices reachable through
722/// outgoing hyperedges. Substrate-agnostic algorithms (forward BFS, forward
723/// reachability) bind on this trait so the same code drives any topology
724/// view that can answer the question.
725///
726/// Implementations define whether parallel connections produce repeated
727/// successor elements. Implementations that preserve multiplicity should
728/// document that behavior; consumers that need set semantics should
729/// deduplicate at their own level.
730///
731/// # Performance
732///
733/// Creating the iterator should be `O(1)` unless an implementation documents a
734/// weaker contract. Yielding `k` successors should be `O(k)` and should not
735/// allocate unless the implementation documents otherwise.
736pub trait ElementSuccessors: TopologyBase {
737 /// Iterator over successor element IDs reached from one element.
738 ///
739 /// # Performance
740 ///
741 /// Advancing the iterator should be amortized `O(1)` unless an
742 /// implementation documents otherwise.
743 type Successors<'view>: Iterator<Item = Self::ElementId>
744 where
745 Self: 'view;
746
747 /// Returns elements reachable through outgoing connections from `element`.
748 ///
749 /// # Performance
750 ///
751 /// Expected `O(1)` to create the iterator; yielding `k` successors is
752 /// expected `O(k)`.
753 fn element_successors(&self, element: Self::ElementId) -> Self::Successors<'_>;
754}
755
756/// Capability for expanding an element to its directed predecessor elements.
757///
758/// This is the substrate-neutral form of "follow incoming connections to this
759/// element." For binary graphs the predecessors are the sources of incoming
760/// edges; for hypergraphs they are the vertices that reach this vertex
761/// through outgoing hyperedges. Substrate-agnostic algorithms (reverse BFS,
762/// reverse reachability) bind on this trait so the same code drives any
763/// topology view that can answer the question.
764///
765/// Implementations define whether parallel connections produce repeated
766/// predecessor elements. Implementations that preserve multiplicity should
767/// document that behavior; consumers that need set semantics should
768/// deduplicate at their own level.
769///
770/// # Performance
771///
772/// Creating the iterator should be `O(1)` unless an implementation documents a
773/// weaker contract. Yielding `k` predecessors should be `O(k)` and should not
774/// allocate unless the implementation documents otherwise.
775pub trait ElementPredecessors: TopologyBase {
776 /// Iterator over predecessor element IDs reaching one element.
777 ///
778 /// # Performance
779 ///
780 /// Advancing the iterator should be amortized `O(1)` unless an
781 /// implementation documents otherwise.
782 type Predecessors<'view>: Iterator<Item = Self::ElementId>
783 where
784 Self: 'view;
785
786 /// Returns elements that reach `element` through outgoing connections.
787 ///
788 /// # Performance
789 ///
790 /// Expected `O(1)` to create the iterator; yielding `k` predecessors is
791 /// expected `O(k)`.
792 fn element_predecessors(&self, element: Self::ElementId) -> Self::Predecessors<'_>;
793}