1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! A bounded graph implementation that enforces edge count constraints on nodes.
//!
//! This crate provides a wrapper around [`petgraph::Graph`] and [`petgraph::stable_graph::StableGraph`] that ensures nodes cannot exceed
//! their defined edge limits when adding connections. All edge addition operations check the
//! bounds before modifying the graph.
//!
//! # Features
//!
//! - **Flexible constraint system**: Define custom edge constraints via the [`BoundedNode`] trait
//! - **Simple edge bounds**: Use [`EdgeBounds`] + [`SimpleEdgeBounds`] for basic numeric limits
//! - **Convenience types**: Use [`FixedEdgeCount`] or [`SymmetricFixedEdgeCount`] for quick node creation with fixed limits
//! - **Petgraph compatible**: Implements most petgraph traits for seamless integration
//! - **Acyclic graphs**: Specialized [`BoundedAcyclicGraph`] variants that combines edge bounds enforcement from this crate with acyclicity enforcement built into petgraph
//! - **Type-safe error handling**: Returns [`BoundedGraphError`] or [`BoundedAcyclicGraphError`] instead of panicking
//!
//! # Quick Start Example
//!
//! [`SymmetricFixedEdgeCount`] provides a simple way to create nodes with the same maximum
//! number of incoming and outgoing edges:
//! ```
//! use bounded_graph::{BoundedGraph, SymmetricFixedEdgeCount};
//!
//! // Create a graph where each node can have at most 2 edges (both incoming and outgoing)
//! let mut graph = BoundedGraph::<SymmetricFixedEdgeCount<2>, ()>::new();
//! let n1 = graph.add_node(SymmetricFixedEdgeCount::empty());
//! let n2 = graph.add_node(SymmetricFixedEdgeCount::empty());
//! let n3 = graph.add_node(SymmetricFixedEdgeCount::empty());
//!
//! // These succeed
//! assert!(graph.add_edge(n1, n2, ()).is_ok());
//! assert!(graph.add_edge(n1, n3, ()).is_ok());
//!
//! // This fails - n1 already has 2 outgoing edges
//! let n4 = graph.add_node(SymmetricFixedEdgeCount::empty());
//! assert!(graph.add_edge(n1, n4, ()).is_err());
//! ```
//!
//! # Asymmetric Edge Limits
//!
//! [`FixedEdgeCount`] supports different limits for incoming and outgoing edges:
//!
//! ```
//! use bounded_graph::{BoundedGraph, FixedEdgeCount};
//!
//! // Create nodes with 2 max incoming, 5 max outgoing edges
//! let mut graph = BoundedGraph::<FixedEdgeCount<2, 5>, ()>::new();
//! let hub = graph.add_node(FixedEdgeCount::empty());
//! let spoke1 = graph.add_node(FixedEdgeCount::empty());
//! let spoke2 = graph.add_node(FixedEdgeCount::empty());
//!
//! // Hub can send to many spokes
//! assert!(graph.add_edge(hub, spoke1, ()).is_ok());
//! assert!(graph.add_edge(hub, spoke2, ()).is_ok());
//! // ... up to 5 outgoing edges
//! ```
//!
//! # Custom Edge Bounds
//!
//! For more control, implement [`EdgeBounds`] directly:
//!
//! ```
//! use bounded_graph::{BoundedGraph, EdgeBounds, SimpleEdgeBounds};
//! use petgraph::graph::DefaultIx;
//!
//! #[derive(Default)]
//! struct TwiceLimitedNode {
//! max_in: usize,
//! max_out: usize,
//! }
//!
//! impl EdgeBounds for TwiceLimitedNode {
//! fn max_incoming_edges(&self) -> DefaultIx {
//! 2 * self.max_in as DefaultIx
//! }
//!
//! fn max_outgoing_edges(&self) -> DefaultIx {
//! 2 * self.max_out as DefaultIx
//! }
//! }
//!
//! impl SimpleEdgeBounds for TwiceLimitedNode {}
//!
//! let mut graph = BoundedGraph::<TwiceLimitedNode, ()>::new();
//! let n1 = graph.add_node(TwiceLimitedNode { max_in: 2, max_out: 2 });
//! let n2 = graph.add_node(TwiceLimitedNode { max_in: 2, max_out: 2 });
//!
//! // This will succeed
//! assert!(graph.add_edge(n1, n2, ()).is_ok());
//! ```
//!
//! For complete control with custom logic, implement [`BoundedNode`] directly:
//!
//! ```
//! use bounded_graph::{BoundedGraph, BoundedNode};
//! use petgraph::Direction;
//!
//! #[derive(Clone, PartialEq)]
//! enum Color { Red, Blue, Green }
//!
//! struct ColoredNode {
//! color: Color,
//! }
//!
//! impl BoundedNode for ColoredNode {
//! fn can_add_edge(&self, _dir: Direction, _count: usize, other: &Self) -> bool {
//! // Only allow edges between nodes of the same color
//! self.color == other.color
//! }
//! }
//!
//! let mut graph = BoundedGraph::<ColoredNode, ()>::new();
//! let red1 = graph.add_node(ColoredNode { color: Color::Red });
//! let red2 = graph.add_node(ColoredNode { color: Color::Red });
//! let blue = graph.add_node(ColoredNode { color: Color::Blue });
//!
//! // Same color - succeeds
//! assert!(graph.add_edge(red1, red2, ()).is_ok());
//! // Different colors - fails
//! assert!(graph.add_edge(red1, blue, ()).is_err());
//! ```
// Re-export public API
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
// Re-export commonly used petgraph types for ergonomics
pub use ;
pub use ;