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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
use super::*;
use self::Operations::*;

///
/// Defines mutating operations that can be executed on a graph.
///
pub enum Operations<V,W>
	where
		V: Vertex,
		W: Weight,
{
	AddVertex(V),
	AddEdge(BaseEdge<V,W>),
	RemoveVertex(V),
	RemoveEdge(BaseEdge<V,W>),
}

///
/// Handles execution of a set of mutating operations on a given graph
/// 'atomically', in the sense that constraints are only verified after
/// all the operation have been executed.
///
/// The operations are executed lazily, i.e. only when `constrain()` is called.
///
///
pub struct Unconstrainer<'a,V,W,Vi,Ei,G>
	where
		V: Vertex,
		W: Weight,
		Vi: VertexIter<V>,
		Ei: EdgeIter<V,W>,
		<Vi as IntoIterator>::IntoIter: ExactSizeIterator,
		<Ei as IntoIterator>::IntoIter: ExactSizeIterator,
		G: 'a + ConstrainedGraph<Vertex=V,Weight=W,VertexIter=Vi,EdgeIter=Ei>
{
	graph: &'a mut G,
	operations: Vec<Operations<V,W>>,
}

impl<'a,V,W,Vi,Ei,G> Unconstrainer<'a,V,W,Vi,Ei,G>
	where
		V: Vertex,
		W: Weight,
		Vi: VertexIter<V>,
		Ei: EdgeIter<V,W>,
		<Vi as IntoIterator>::IntoIter: ExactSizeIterator,
		<Ei as IntoIterator>::IntoIter: ExactSizeIterator,
		G: ConstrainedGraph<Vertex=V,Weight=W,VertexIter=Vi,EdgeIter=Ei>
{
	
	pub fn new(g: &'a mut G) -> Self{
		Unconstrainer{graph:g, operations: Vec::new()}
	}
	
	///
	/// Enqueues an addition of the given vertex to the list of operations.
	///
	pub fn add_vertex(mut self, v: V) -> Self{
		self.operations.push(Operations::AddVertex(v));
		self
	}
	
	///
	/// Enqueues a removal of the given vertex to the list of operations.
	///
	pub fn remove_vertex(mut self, v:V) -> Self{
		self.operations.push(Operations::RemoveVertex(v));
		self
	}
	
	///
	/// Enqueues an addition of the given edge to the list of operations.
	///
	pub fn add_edge(mut self, e: BaseEdge<V,W>) -> Self{
		self.operations.push(Operations::AddEdge(e));
		self
	}
	
	///
	/// Enqueues a removal of the given edge to the list of operations.
	///
	pub fn remove_edge(mut self, e: BaseEdge<V,W>) -> Self{
		self.operations.push(Operations::RemoveEdge(e));
		self
	}
	
	///
	/// Executes all operations in the list, ensuring that each one isn't rejected
	/// and then checks the invariant of the graph.
	///
	/// If any operation is rejected, or the invariant of the graph does not hold after
	/// all operations are executed, any change made is rolled back, and `Err` is returned.
	///
	/// Guarantees that if `Ok` is returned, then the graph upholds its constraint invariant.
	///
	///
	pub fn constrain(mut self) -> Result<(),()> {
		match self.execute_unconstrained_operations(){
			Err(ops) =>{
				// One of the operations failed, therefore roll back changes
				self.rollback_operations(ops);
				Err(())
			}
			Ok(()) =>{
				// All operations accepted, test invariant
				if self.graph.invariant_holds() {
					Ok(())
				}else{
					let op_count = self.operations.len();
					self.rollback_operations(op_count);
					Err(())
				}
			}
		}
	}
	
	fn rollback_operations(&mut self, rollback_count:usize) {
		let ref operations = self.operations;
		let ref mut graph = self.graph;
		
		for j in (0..(rollback_count)).rev(){
			unsafe{
				match operations[j] {
					AddVertex(v) => graph.uncon_remove_vertex(v),
					AddEdge(e) => graph.uncon_remove_edge(e),
					RemoveVertex(v) => graph.uncon_add_vertex(v),
					RemoveEdge(e) => graph.uncon_add_edge(e),
				}.unwrap()
			}
		}
	}
	
	fn execute_unconstrained_operations(&mut self) -> Result<(),usize>{
		let ref operations = self.operations;
		let ref mut graph = self.graph;
		
		let mut i = 0;
		while i < operations.len() {
			match unsafe {
				match operations[i] {
					AddVertex(v) => graph.uncon_add_vertex(v),
					AddEdge(e) => graph.uncon_add_edge(e),
					RemoveVertex(v) => graph.uncon_remove_vertex(v),
					RemoveEdge(e) => graph.uncon_remove_edge(e),
				}
			}{
				Err(()) =>{
					/* Operation i failed
					 */
					// Rollback all operations that executed before the (i+1)'th
					return Err(i);
				}
				Ok(())	=> i += 1,
			}
		}
		Ok(())
	}
}

///
/// Defines a graph which has some constraint on how it is mutated.
///
/// An example could be a graph which prohibits duplicate edges, ignoring wrights, called a
/// unique graph. Such a graph must then be implemented such that adding an edge
/// checks for duplicates and rejects any such.
///
/// More specifically, to uphold the contract of this trait the following must hold:
///
/// - The implementation of `BaseGraph` on the type must uphold the specified constraint. In our example
///  `add_graph()` must reject any edge which is already in the graph.
/// - The methods of this trait must be implemented.
///
/// The following methods must be implemented for this trait:
///
/// - `invariant_holds`: checks the constraint invariant on the current state of the graph
/// and returns whether it holds. In our example, it will go though all edges, and return false
/// if any duplicate is found.
///
/// - `uncon_add_vertex`: Tries to add a vertex without upholding the invariant.
///
/// - `uncon_remove_vertex`: Tries to remove a vertex without upholding the invariant.
///
/// - `uncon_add_edge`: Tries to add an edge without upholding the invariant. In our example, it
/// will add the edge without checking for duplicates. This means that when the call terminates, the
/// graph may not uphold the invariant of no duplicates.
///
/// - `uncon_remove_edge`: Tries to remove an edge without upholding the invariant.
///
/// The `uncon_...` methods are intentionally `unsafe` as they may result in a graph state which
/// does not uphold its own invariant, and should therefore not be used lightly. The real use case
/// for them come from the `unconstrained` default method. By using it, and the `Unconstrainer`
/// it returns, the user can try executing multiple mutating operations at once, and only after
/// that ensure that the graph still upholds its invariant Example:
///
/// ```
/// use graphene::core::*;
/// use graphene::core::constraint::*;
/// use graphene::common::*;
///
/// let mut g = UniqueGraph::<AdjListGraph<u32,()>>::graph(vec![1,2], vec![]).unwrap();
/// let e = BaseEdge::new(1,2,());
///
/// assert!(g.add_edge(e).is_ok());
/// assert!(g.add_edge(e).is_err());
/// assert!(g.unconstrained().add_edge(e).constrain().is_err());
/// assert!(g.unconstrained()
/// 			.add_edge(e)
/// 			.remove_edge(e)
/// 			.constrain()
/// 			.is_ok());
/// ```
/// We can see here that the same edge cannot be added twice with `g.add_edge(e)`.
/// When using `unconstrained()` we first add the edge, and then remove it again. This
/// means the graph will in the end again only have a single edge, which upholds the invariant.
///
///
pub trait ConstrainedGraph: BaseGraph
where
	Self: Sized,
	<Self::VertexIter as IntoIterator>::IntoIter: ExactSizeIterator,
	<Self::EdgeIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
	///
	/// Checks whether the current state of the graph upholds the constraint invariant.
	///
	fn invariant_holds(&self) -> bool;
	
	///
	/// Adds the given vertex to the graph without upholding the constraint invariant.
	///
	/// The only constraint upheld is that of the `BaseGraph` which states no vertex
	/// value duplicates.
	///
	unsafe fn uncon_add_vertex(&mut self, v: Self::Vertex) -> Result<(),()>;
	
	///
	/// Removes the given vertex from the graph without upholding the constraint invariant.
	///
	/// The only constraint upheld is that of the `BaseGraph` which states all edges
	/// must be incident on valid vertices.
	///
	unsafe fn uncon_remove_vertex(&mut self, v: Self::Vertex) -> Result<(),()>;
	
	///
	/// Adds the given edge to the graph without upholding the constraint invariant.
	///
	/// The only constraint upheld is that of the `BaseGraph` which states all edges
	/// must be incident on valid vertices.
	///
	unsafe fn uncon_add_edge(&mut self, e: BaseEdge<Self::Vertex,Self::Weight>) -> Result<(),()>;
	
	///
	/// Removes the given edge from the graph without upholding the constraint invariant.
	///
	///
	unsafe fn uncon_remove_edge(&mut self, e: BaseEdge<Self::Vertex,Self::Weight>) -> Result<(),()>;
	
	///
	/// Returns an `Unconstrainer` connected to the graph.
	///
	fn unconstrained<'a>(&'a mut self) -> Unconstrainer<
		Self::Vertex, Self::Weight, Self::VertexIter, Self::EdgeIter, Self>{
		Unconstrainer::new(self)
	}
	
	
}