safe_graph/
edge.rs

1//! Graph Edge related constructs.
2
3use self::Direction::{Incoming, Outgoing};
4use crate::graph::{Directed, Graph, Undirected};
5use crate::node::NodeTrait;
6use crate::traverse::Neighbors;
7use indexmap::map::Iter as IndexMapIter;
8use indexmap::IndexMap;
9use std::marker::PhantomData;
10
11/// A graph's edge type determines whether is has directed edges or not.
12pub trait EdgeType {
13    fn is_directed() -> bool;
14}
15
16impl EdgeType for Directed {
17    #[inline]
18    fn is_directed() -> bool {
19        true
20    }
21}
22
23impl EdgeType for Undirected {
24    #[inline]
25    fn is_directed() -> bool {
26        false
27    }
28}
29
30pub struct Edges<'a, N, E: 'a, Ty>
31where
32    N: 'a + NodeTrait,
33    Ty: EdgeType,
34{
35    from: N,
36    edges: &'a IndexMap<(N, N), E>,
37    iter: Neighbors<'a, N, Ty>,
38}
39
40impl<'a, N, E, Ty> Edges<'a, N, E, Ty>
41where
42    N: 'a + NodeTrait,
43    Ty: EdgeType,
44{
45    pub fn new(from: N, edges: &'a IndexMap<(N, N), E>, iter: Neighbors<'a, N, Ty>) -> Self {
46        Self { from, edges, iter }
47    }
48}
49
50impl<'a, N, E, Ty> Iterator for Edges<'a, N, E, Ty>
51where
52    N: 'a + NodeTrait,
53    E: 'a,
54    Ty: EdgeType,
55{
56    type Item = (N, N, &'a E);
57    fn next(&mut self) -> Option<Self::Item> {
58        match self.iter.next() {
59            None => None,
60            Some(b) => {
61                let a = self.from;
62                match self.edges.get(&Graph::<N, E, Ty>::edge_key(a, b)) {
63                    None => unreachable!(),
64                    Some(edge) => Some((a, b, edge)),
65                }
66            }
67        }
68    }
69}
70
71pub struct AllEdges<'a, N, E: 'a, Ty> {
72    inner: IndexMapIter<'a, (N, N), E>,
73    ty: PhantomData<Ty>,
74}
75
76impl<'a, N, E, Ty> AllEdges<'a, N, E, Ty>
77where
78    N: 'a + NodeTrait,
79{
80    pub fn new(inner: IndexMapIter<'a, (N, N), E>, ty: PhantomData<Ty>) -> Self {
81        Self { inner, ty }
82    }
83}
84
85impl<'a, N, E, Ty> Iterator for AllEdges<'a, N, E, Ty>
86where
87    N: 'a + NodeTrait,
88    E: 'a,
89    Ty: EdgeType,
90{
91    type Item = (N, N, &'a E);
92
93    /// Advances the iterator and returns the next value.
94    fn next(&mut self) -> Option<Self::Item> {
95        match self.inner.next() {
96            None => None,
97            Some((&(a, b), v)) => Some((a, b, v)),
98        }
99    }
100
101    /// Returns the bounds on the remaining length of the iterator.
102    ///
103    /// Specifically, `size_hint()` returns a tuple where the first element
104    /// is the lower bound, and the second element is the upper bound.
105    ///
106    /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`.
107    /// A [`None`] here means that either there is no known upper bound, or the
108    /// upper bound is larger than [`usize`].
109    ///
110    /// # Examples
111    ///
112    /// Basic usage:
113    ///
114    /// ```
115    /// use indexmap::IndexMap;
116    /// use safe_graph::edge::AllEdges;
117    /// use safe_graph::graph::Directed;
118    /// use std::marker::PhantomData;
119    ///
120    /// let edges = IndexMap::new();
121    /// let all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
122    ///
123    /// assert_eq!(all_edges.size_hint(), (0, Some(0)));
124    /// ```
125    fn size_hint(&self) -> (usize, Option<usize>) {
126        self.inner.size_hint()
127    }
128
129    /// Consumes the iterator, counting the number of iterations and returning it.
130    fn count(self) -> usize {
131        self.inner.count()
132    }
133
134    /// Returns the `n`th element of the iterator.
135    ///
136    /// Like most indexing operations, the count starts from zero, so `nth(0)`
137    /// returns the first value, `nth(1)` the second, and so on.
138    ///
139    /// Note that all preceding elements, as well as the returned element, will be
140    /// consumed from the iterator. That means that the preceding elements will be
141    /// discarded, and also that calling `nth(0)` multiple times on the same iterator
142    /// will return different elements.
143    ///
144    /// `nth()` will return [`None`] if `n` is greater than or equal to the length of the
145    /// iterator.
146    fn nth(&mut self, n: usize) -> Option<Self::Item> {
147        self.inner
148            .nth(n)
149            .map(|(&(n1, n2), weight)| (n1, n2, weight))
150    }
151
152    /// Consumes the iterator, returning the last element.
153    fn last(self) -> Option<Self::Item> {
154        self.inner
155            .last()
156            .map(|(&(n1, n2), weight)| (n1, n2, weight))
157    }
158}
159
160impl<'a, N, E, Ty> DoubleEndedIterator for AllEdges<'a, N, E, Ty>
161where
162    N: 'a + NodeTrait,
163    E: 'a,
164    Ty: EdgeType,
165{
166    /// Removes and returns an element from the end of the iterator.
167    ///
168    /// Returns `None` when there are no more elements.
169    fn next_back(&mut self) -> Option<Self::Item> {
170        self.inner
171            .next_back()
172            .map(|(&(n1, n2), weight)| (n1, n2, weight))
173    }
174}
175
176/// Convert an element like `(i, j)` or `(i, j, w)` into a triple of source, target, edge weight.
177///
178/// For `Graph::from_edges`.
179pub trait IntoWeightedEdge<E> {
180    type NodeId;
181    fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
182}
183
184/// Convert an element like `(i, j)` into a triple of source, target, edge weight.
185impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
186where
187    E: Default,
188{
189    type NodeId = Ix;
190
191    fn into_weighted_edge(self) -> (Ix, Ix, E) {
192        let (s, t) = self;
193        (s, t, E::default())
194    }
195}
196
197/// Convert an element like `(i, j, w)` into a triple of source, target, edge weight.
198///
199/// Meaning do no change, just return.
200impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E) {
201    type NodeId = Ix;
202
203    fn into_weighted_edge(self) -> (Ix, Ix, E) {
204        self
205    }
206}
207
208/// Convert an element like `(i, j, w)` into a triple of source, target, edge weight.
209///
210/// Clone the edge weight from the reference.
211impl<'a, Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &'a E)
212where
213    E: Clone,
214{
215    type NodeId = Ix;
216
217    fn into_weighted_edge(self) -> (Ix, Ix, E) {
218        let (a, b, c) = self;
219        (a, b, c.clone())
220    }
221}
222
223/// Convert an element like `&(i, j)` into a triple of source, target, edge weight.
224///
225/// See that the element `&(i, j)` is a reference.
226impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix)
227where
228    Ix: Copy,
229    E: Default,
230{
231    type NodeId = Ix;
232
233    fn into_weighted_edge(self) -> (Ix, Ix, E) {
234        let (s, t) = *self;
235        (s, t, E::default())
236    }
237}
238
239/// Convert an element like `&(i, j, w)` into a triple of source, target, edge weight.
240///
241/// Clone the edge weight from the reference.
242/// See that the element `&(i, j, w)` is a reference.
243impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix, E)
244where
245    Ix: Copy,
246    E: Clone,
247{
248    type NodeId = Ix;
249    fn into_weighted_edge(self) -> (Ix, Ix, E) {
250        self.clone()
251    }
252}
253
254/// Edge direction.
255#[derive(Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
256#[repr(usize)]
257pub enum Direction {
258    /// An `Outgoing` edge is an outward edge *from* the current node.
259    Outgoing = 0,
260    /// An `Incoming` edge is an inbound edge *to* the current node.
261    Incoming = 1,
262}
263
264copyclone!(Direction);
265
266impl Direction {
267    /// Return the opposite `Direction`.
268    #[inline]
269    pub fn opposite(self) -> Direction {
270        match self {
271            Outgoing => Incoming,
272            Incoming => Outgoing,
273        }
274    }
275
276    /// Return `0` for `Outgoing` and `1` for `Incoming`.
277    #[inline]
278    pub fn index(self) -> usize {
279        (self as usize) & 0x1
280    }
281}
282
283/// Non-repr(usize) version of `Direction`.
284#[derive(Copy, Clone, Debug, PartialEq)]
285pub enum CompactDirection {
286    Outgoing,
287    Incoming,
288}
289
290impl From<Direction> for CompactDirection {
291    fn from(d: Direction) -> Self {
292        match d {
293            Outgoing => CompactDirection::Outgoing,
294            Incoming => CompactDirection::Incoming,
295        }
296    }
297}
298
299impl PartialEq<Direction> for CompactDirection {
300    fn eq(&self, rhs: &Direction) -> bool {
301        (*self as usize) == (*rhs as usize)
302    }
303}
304
305#[cfg(test)]
306mod tests {
307    use crate::edge::{AllEdges, CompactDirection, Direction, EdgeType, Edges, IntoWeightedEdge};
308    use crate::graph::{Directed, Undirected};
309    use crate::traverse::Neighbors;
310    use indexmap::IndexMap;
311    use std::cmp::PartialEq;
312    use std::marker::PhantomData;
313
314    #[test]
315    fn edge_type_is_directed() {
316        assert_eq!(Directed::is_directed(), true);
317        assert_eq!(Undirected::is_directed(), false);
318    }
319
320    #[test]
321    fn edges_new() {
322        // Prepare arguments.
323        let from: u32 = 1;
324        let edges: IndexMap<(u32, u32), f32> = IndexMap::new();
325        let node_neighbors: Vec<(u32, CompactDirection)> = vec![];
326        let iter = node_neighbors.iter();
327        let neighbors: Neighbors<u32, Directed> = Neighbors::new(iter, PhantomData);
328
329        // Test `Edges` struct creation.
330        Edges::new(from, &edges, neighbors);
331    }
332
333    #[test]
334    fn edges_next() {
335        // Prepare arguments.
336        let from: u32 = 1;
337        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
338        edges.insert((2, 1), 2.0);
339        edges.insert((1, 3), 3.0);
340        edges.insert((1, 4), 4.0);
341        let node_neighbors: Vec<(u32, CompactDirection)> = vec![
342            (2, CompactDirection::Incoming),
343            (3, CompactDirection::Outgoing),
344            (4, CompactDirection::Outgoing),
345        ];
346        let neighbors: Neighbors<u32, Directed> =
347            Neighbors::new(node_neighbors.iter(), PhantomData);
348
349        // Construct edges from `1`.
350        // The edge (2, 1) is being filtered out as the edges are directed.
351        let mut edges = Edges::new(from, &edges, neighbors);
352
353        // Test all existing edges from `1`.
354        assert_eq!(edges.next(), Some((1, 3, &3.0)));
355        assert_eq!(edges.next(), Some((1, 4, &4.0)));
356
357        // Test the end of iteration.
358        assert_eq!(edges.next(), None);
359    }
360
361    #[test]
362    #[should_panic]
363    fn edges_next_unreachable() {
364        // Prepare arguments.
365        let from: u32 = 1;
366        let edges: IndexMap<(u32, u32), f32> = IndexMap::new();
367        let node_neighbors: Vec<(u32, CompactDirection)> = vec![(2, CompactDirection::Incoming)];
368        let neighbors: Neighbors<u32, Directed> =
369            Neighbors::new(node_neighbors.iter(), PhantomData);
370
371        // Construct edges.
372        let mut edges = Edges::new(from, &edges, neighbors);
373
374        assert_eq!(edges.next(), Some((1, 2, &0.0)));
375    }
376
377    #[test]
378    fn all_edges_new() {
379        let _all_edges: AllEdges<u32, f32, Directed> =
380            AllEdges::new(IndexMap::new().iter(), PhantomData);
381    }
382
383    #[test]
384    fn all_edges_next() {
385        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
386        edges.insert((2, 1), 2.0);
387        edges.insert((1, 3), 3.0);
388        edges.insert((1, 4), 4.0);
389
390        let mut all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
391
392        assert_eq!(all_edges.next(), Some((2, 1, &2.0)));
393        assert_eq!(all_edges.next(), Some((1, 3, &3.0)));
394        assert_eq!(all_edges.next(), Some((1, 4, &4.0)));
395        assert_eq!(all_edges.next(), None);
396    }
397
398    #[test]
399    fn all_edges_size_hint() {
400        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
401        edges.insert((2, 1), 2.0);
402        edges.insert((1, 3), 3.0);
403        edges.insert((1, 4), 4.0);
404        let mut all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
405
406        assert_eq!(all_edges.size_hint(), (3, Some(3)));
407
408        // Lower the length of the iterator.
409        all_edges.next();
410
411        assert_eq!(all_edges.size_hint(), (2, Some(2)));
412
413        // Lower the length of the iterator.
414        all_edges.next();
415
416        assert_eq!(all_edges.size_hint(), (1, Some(1)));
417
418        // Lower the length of the iterator.
419        all_edges.next();
420
421        assert_eq!(all_edges.size_hint(), (0, Some(0)));
422    }
423
424    #[test]
425    fn all_edges_count() {
426        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
427        edges.insert((2, 1), 2.0);
428        edges.insert((1, 3), 3.0);
429        edges.insert((1, 4), 4.0);
430        let all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
431
432        assert_eq!(all_edges.count(), 3);
433    }
434
435    #[test]
436    fn all_edges_nth() {
437        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
438        edges.insert((2, 1), 2.0);
439        edges.insert((1, 3), 3.0);
440        edges.insert((1, 4), 4.0);
441        let mut all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
442
443        assert_eq!(all_edges.nth(2), Some((1, 4, &4.0)));
444        assert_eq!(all_edges.nth(0), None);
445    }
446
447    #[test]
448    fn all_edges_last() {
449        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
450        edges.insert((2, 1), 2.0);
451        edges.insert((1, 3), 3.0);
452        edges.insert((1, 4), 4.0);
453        let all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
454
455        assert_eq!(all_edges.last(), Some((1, 4, &4.0)));
456    }
457
458    #[test]
459    fn all_edges_next_back() {
460        let mut edges: IndexMap<(u32, u32), f32> = IndexMap::with_capacity(3);
461        edges.insert((2, 1), 2.0);
462        edges.insert((1, 3), 3.0);
463        edges.insert((1, 4), 4.0);
464
465        let mut all_edges: AllEdges<u32, f32, Directed> = AllEdges::new(edges.iter(), PhantomData);
466
467        // Iterate backwards.
468        assert_eq!(all_edges.next_back(), Some((1, 4, &4.0)));
469        assert_eq!(all_edges.next_back(), Some((1, 3, &3.0)));
470        assert_eq!(all_edges.next_back(), Some((2, 1, &2.0)));
471        assert_eq!(all_edges.next_back(), None);
472    }
473
474    #[test]
475    fn into_weighted_edge() {
476        // Test with tuple.
477        assert_eq!((1, 2).into_weighted_edge(), (1, 2, f32::default()));
478
479        // Test with triple.
480        assert_eq!((1, 2, 3).into_weighted_edge(), (1, 2, 3));
481
482        // Test with triple having edge weight as reference.
483        assert_eq!((1, 2, &3).into_weighted_edge(), (1, 2, 3));
484
485        // Test with tuple as reference.
486        assert_eq!((&(1, 2)).into_weighted_edge(), (1, 2, f32::default()));
487
488        // Test with triple as reference.
489        assert_eq!((&(1, 2, 3)).into_weighted_edge(), (1, 2, 3));
490    }
491
492    #[test]
493    fn direction_opposite() {
494        assert_eq!(Direction::Incoming.opposite(), Direction::Outgoing);
495        assert_eq!(Direction::Outgoing.opposite(), Direction::Incoming);
496    }
497
498    #[test]
499    fn direction_index() {
500        assert_eq!(Direction::Incoming.index(), Direction::Incoming as usize);
501        assert_eq!(Direction::Outgoing.index(), Direction::Outgoing as usize);
502    }
503
504    #[test]
505    fn direction_clone() {
506        assert_eq!(Direction::Incoming.clone(), Direction::Incoming);
507        assert_eq!(Direction::Outgoing.clone(), Direction::Outgoing);
508    }
509
510    #[test]
511    fn compact_direction_from() {
512        assert_eq!(
513            CompactDirection::from(Direction::Incoming),
514            CompactDirection::Incoming
515        );
516        assert_eq!(
517            CompactDirection::from(Direction::Outgoing),
518            CompactDirection::Outgoing
519        );
520    }
521
522    #[test]
523    fn compact_direction_partial_equal_with_direction() {
524        assert_eq!(CompactDirection::Incoming.eq(&Direction::Incoming), true);
525        assert_eq!(CompactDirection::Incoming.eq(&Direction::Outgoing), false);
526
527        assert_eq!(CompactDirection::Outgoing.eq(&Direction::Outgoing), true);
528        assert_eq!(CompactDirection::Outgoing.eq(&Direction::Incoming), false);
529    }
530}