rs_graph/
builder.rs

1/*
2 * Copyright (c) 2017-2022 Frank Fischer <frank-fischer@shadow-soft.de>
3 *
4 * This program is free software: you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see  <http://www.gnu.org/licenses/>
16 */
17
18//! Traits for constructing graphs.
19
20/// A trait to construct graphs.
21///
22/// In general graphs are static objects. In order to build a graph,
23/// one should use a graph builder and, once the construction is
24/// complete, convert it into a graph.
25///
26/// This 2-level approach is used because some graph implementations
27/// be unstable if the graph is modified (e.g., the node numbers might
28/// change). The builder approach allows to separate construction and
29/// use of a graph.
30pub trait Builder
31where
32    Self: Sized,
33{
34    /// The graph type produced by this builder.
35    type Graph;
36
37    /// The type of a nodes.
38    type Node: Copy + Eq;
39
40    /// The type of an edge.
41    type Edge: Copy + Eq;
42
43    /// Create a new, empty builder.
44    fn new() -> Self {
45        Self::with_capacities(0, 0)
46    }
47
48    /// Create a new, empty builder.
49    ///
50    /// The builder might be passed a guess of the number of nodes and
51    /// edges. This might be used to reserve the appropriate internal
52    /// memory, but is no strict requirement for the number of nodes
53    /// and edges to be added to the graph.
54    fn with_capacities(nnodes: usize, nedges: usize) -> Self;
55
56    /// Reserve memory for a certain number of nodes and edges.
57    fn reserve(&mut self, nnodes: usize, nedges: usize);
58
59    /// Return the current number of nodes.
60    fn num_nodes(&self) -> usize;
61
62    /// Return the current number of nodes.
63    fn num_edges(&self) -> usize;
64
65    /// Add a new node.
66    fn add_node(&mut self) -> Self::Node;
67
68    /// Add `n` new nodes.
69    fn add_nodes(&mut self, n: usize) -> Vec<Self::Node> {
70        (0..n).map(|_| self.add_node()).collect()
71    }
72
73    /// Add a new edge.
74    fn add_edge(&mut self, u: Self::Node, v: Self::Node) -> Self::Edge;
75
76    /// Return a unique id of a node.
77    fn node2id(&self, u: Self::Node) -> usize;
78
79    /// Return a unique id of an edge.
80    fn edge2id(&self, e: Self::Edge) -> usize;
81
82    /// Return the node with a certain id.
83    fn id2node(&self, uid: usize) -> Self::Node;
84
85    /// Return the edge with a certain id.
86    fn id2edge(&self, eid: usize) -> Self::Edge;
87
88    /// Turn the builder into a graph.
89    fn into_graph(self) -> Self::Graph;
90}
91
92/// A graph with a default builder.
93pub trait Buildable
94where
95    Self: Sized,
96{
97    type Builder: Builder<Graph = Self>;
98
99    /// Create a new builder for this graph type.
100    fn new_builder() -> Self::Builder {
101        Self::Builder::new()
102    }
103
104    /// Create a new graph by passing the builder to the callback `f`.
105    ///
106    /// # Example
107    ///
108    /// ```
109    /// use rs_graph::{Buildable, Builder, LinkedListGraph};
110    /// use rs_graph::traits::FiniteGraph;
111    ///
112    /// let g = LinkedListGraph::<usize>::new_with(|b| {
113    ///     let u = b.add_node();
114    ///     let v = b.add_node();
115    ///     b.add_edge(u, v);
116    /// });
117    ///
118    /// assert_eq!(g.num_nodes(), 2);
119    /// assert_eq!(g.num_edges(), 1);
120    /// ```
121    fn new_with<F>(f: F) -> Self
122    where
123        F: FnOnce(&mut Self::Builder),
124    {
125        let mut b = Self::new_builder();
126        f(&mut b);
127        b.into_graph()
128    }
129}