Documentation updates #6

Merged
warrence merged 8 commits from release-0.2.3 into main 2026-07-17 11:16:49 +02:00
Showing only changes of commit 7345684f00 - Show all commits
+209
View File
@@ -2,35 +2,244 @@ use crate::maps::{EdgeMap, VertexMap};
// TODO: Add functions to reserve memory for vertices and edges.
// TODO: Split out GraphTopologyAddition trait.
/// A trait representing an undirected graph topology.
///
/// An undirected graph is a set of vertices and undirected edges, where each edge connects either
/// exactly two vertices or one vertex with itself (loop edge). This trait provides methods for
/// querying a graph topology, iterating over vertices and edges, and adding new vertices and edges.
///
/// # Vertices and Edges
///
/// Vertices and edges are identified by opaque handles ([`Vertex`] and [`Edge`]) that implement
/// [`Copy`] and [`Eq`]. Handles remain valid for the lifetime of the graph unless the graph also
/// implements [`GraphTopologyDeletion`] and the item identified by the handle is explicitly
/// deleted.
///
/// Methods accepting vertices or edges as parameters panic if the handle was invalidated by a
/// deletion, and return incorrect results if the handle was not produced by this graph instance.
///
/// # Deletion
///
/// This trait covers graph construction and querying only. To delete vertices and edges, see
/// [`GraphTopologyDeletion`].
///
/// [`Edge`]: GraphTopology::Edge
/// [`Vertex`]: GraphTopology::Vertex
pub trait GraphTopology {
/// An opaque, stable handle identifying a vertex.
type Vertex: Copy + Eq;
/// An opaque, stable handle identifying an edge.
type Edge: Copy + Eq;
/// A resumable position in the incidence list of a vertex.
///
/// Prefer [`incidences`](Self::incidences) for straightforward iteration. A cursor is useful
/// when an algorithm needs to pause traversal, perform other graph queries or mutations, and
/// then continue from where it left off. This cursor type can be obtained via
/// [`incidence_cursor`](Self::incidence_cursor).
type IncidenceCursor: IncidenceCursor<Self> + Copy;
/// Returns the number of vertices in the graph.
fn vertex_count(&self) -> usize;
/// Returns the total number of vertices the graph can hold without reallocating.
fn vertex_capacity(&self) -> usize;
/// Creates and returns a [`VertexMap`] with every slot initialised to `default`.
///
/// # Examples
///
/// ```
/// # use grapherity::prelude::*;
/// # use grapherity::models::Graph;
/// let mut graph = Graph::new();
/// let v1 = graph.add_vertex();
/// let mut labels = graph.vertex_map("z");
/// assert_eq!(labels[v1], "z");
/// labels[v1] = "a";
/// assert_eq!(labels[v1], "a");
///
/// // A new vertex is immediately available for read and write.
/// let v2 = graph.add_vertex();
/// assert_eq!(labels[v2], "z");
/// labels[v2] = "b";
/// assert_eq!(labels[v2], "b");
/// ```
fn vertex_map<T: Clone>(&self, default: T) -> VertexMap<Self::Vertex, T>;
/// Returns the number of edges in the graph.
fn edge_count(&self) -> usize;
/// Returns the total number of edges the graph can hold without reallocating.
fn edge_capacity(&self) -> usize;
/// Creates and returns an [`EdgeMap`] with every slot initialised to `default`.
///
/// # Examples
///
/// ```
/// # use grapherity::prelude::*;
/// # use grapherity::models::Graph;
/// let mut graph = Graph::new();
/// let v1 = graph.add_vertex();
/// let v2 = graph.add_vertex();
/// let e1 = graph.add_edge(v1, v2);
/// let mut weights = graph.edge_map(5);
/// assert_eq!(weights[e1], 5);
/// weights[e1] = 1;
/// assert_eq!(weights[e1], 1);
///
/// // A new edge is immediately available for read and write.
/// let e2 = graph.add_edge(v1, v2);
/// assert_eq!(weights[e2], 5);
/// weights[e2] = 2;
/// assert_eq!(weights[e2], 2);
/// ```
fn edge_map<T: Clone>(&self, default: T) -> EdgeMap<Self::Edge, T>;
/// Returns the degree of `v`, i.e. the number of incident edges, where each loop contributes 2.
///
/// # Panics
///
/// Panics if `v` is not a valid vertex of this graph.
fn degree(&self, v: Self::Vertex) -> usize;
/// Returns `true` if there is at least one edge between `v1` and `v2`, and `false` otherwise.
///
/// A vertex is adjacent to itself if and only if it has a loop edge.
///
/// # Panics
///
/// Panics if `v1` or `v2` is not a valid vertex of this graph.
fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool;
/// Returns an iterator over all vertices in the graph.
fn vertices(&self) -> impl Iterator<Item = Self::Vertex>;
/// Returns an iterator over all vertices adjacent to `v`.
///
/// Algorithms may prefer this over [`incidences`](Self::incidences) if the edges are not
/// required, since implementors may be able to provide an iterator faster than the trivial
/// mapping. The complexity of this method must not exceed that of
/// [`incidences`](Self::incidences).
///
/// # Panics
///
/// Panics if `v` is not a valid vertex of this graph.
fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex>;
/// Returns the two endpoints of edge `e`, which are identical if and only if `e` is a loop
/// edge.
///
/// # Panics
///
/// Panics if `e` is not a valid edge of this graph.
fn incident_vertices(&self, e: Self::Edge) -> (Self::Vertex, Self::Vertex);
/// Returns an iterator over all edges in the graph.
fn edges(&self) -> impl Iterator<Item = Self::Edge>;
/// Returns an iterator over all edges incident to `v`.
///
/// Algorithms may prefer this over [`incidences`](Self::incidences) if the vertices are not
/// required, since implementors may be able to provide an iterator faster than the trivial
/// mapping. The complexity of this method must not exceed that of
/// [`incidences`](Self::incidences).
///
/// # Panics
///
/// Panics if `v` is not a valid vertex of this graph.
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge>;
/// Returns an iterator over all incidences of `v`, i.e. vertex-edge pairs `(u, e)` such that
/// `u` is adjacent to `v` and `e` is an edge between them.
///
/// Use [`incidence_cursor`](Self::incidence_cursor) instead for a traversal that needs to
/// suspend and resume across other state updates.
///
/// # Panics
///
/// Panics if `v` is not a valid vertex of this graph.
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)>;
/// Returns a cursor over all incidences of `v`, analogously to
/// [`incidences`](Self::incidences), initially positioned before the first one.
///
/// See [`IncidenceCursor`](Self::IncidenceCursor) for when to prefer a cursor over
/// [`incidences`](Self::incidences).
///
/// # Panics
///
/// Panics if `v` is not a valid vertex of this graph.
fn incidence_cursor(&self, v: Self::Vertex) -> Self::IncidenceCursor;
/// Adds a new isolated vertex and returns its handle.
fn add_vertex(&mut self) -> Self::Vertex;
/// Adds a new edge between `v1` and `v2` and returns its handle.
///
/// # Panics
///
/// Panics if `v1` or `v2` is not a valid vertex of this graph.
fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge;
}
/// A trait that adds deletion operations to an undirected graph topology.
///
/// This trait provides methods for deletion of vertices and edges in an undirected graph. These
/// operations will invalidate handles to all deleted vertices and edges. Methods accepting invalid
/// vertices or edges as parameters panic.
pub trait GraphTopologyDeletion: GraphTopology {
/// Deletes the vertex `v` and all its incident edges from the graph. Note that this also
/// invalidates the handles of all edges incident to `v`.
///
/// # Panics
///
/// Panics if `v` is not a valid vertex of this graph.
fn delete_vertex(&mut self, v: Self::Vertex);
/// Deletes the edge `e` from the graph. This operation only invalidates `e` and no other vertex
/// or edge handles.
///
/// # Panics
///
/// Panics if `e` is not a valid edge of this graph.
fn delete_edge(&mut self, e: Self::Edge);
}
/// A cursor for traversing the incidences of a vertex one step at a time.
///
/// Cursors are obtained via [`GraphTopology::incidence_cursor`]. See
/// [`GraphTopology::IncidenceCursor`] for guidance on when to prefer a cursor over
/// [`GraphTopology::incidences`].
pub trait IncidenceCursor<G: GraphTopology + ?Sized> {
/// Advances the cursor and returns the next incidence as `Some((u, e))`, or `None` if the
/// traversal is exhausted.
///
/// # Examples
///
/// ```
/// # use grapherity::prelude::*;
/// # use grapherity::models::Graph;
/// // Constructs a graph with two vertices connected to `v`.
/// let mut graph = Graph::new();
/// let v = graph.add_vertex();
/// for _ in 0..2 {
/// let u = graph.add_vertex();
/// graph.add_edge(u, v);
/// }
///
/// // Iterates over the incidences of `v` with a cursor.
/// let mut c1 = graph.incidence_cursor(v);
/// assert!(c1.next(&graph).is_some());
/// let mut c2 = c1;
/// // Continues iteration with original cursor.
/// assert!(c1.next(&graph).is_some());
/// assert!(c1.next(&graph).is_none());
/// // Iterates over the last incidence again with the copied cursor.
/// assert!(c2.next(&graph).is_some());
/// assert!(c2.next(&graph).is_none());
/// ```
fn next(&mut self, graph: &G) -> Option<(G::Vertex, G::Edge)>;
}