1
use std::slice::SliceIndex;
2

            
3
/// An enum used to indicate an edge or a self loop.
4
pub enum Edge<T> {
5
    Regular(T, T),
6

            
7
    /// For a self loop we only provide a mutable reference to the single state.
8
    Selfloop(T),
9
}
10

            
11
/// Index two locations (from, to) of an edge, returns mutable references to it.
12
pub fn index_edge<T, I: PartialEq + PartialOrd<usize> + SliceIndex<[T], Output = T>>(
13
    slice: &mut [T],
14
    a: I,
15
    b: I,
16
) -> Edge<&mut T> {
17
    if a == b {
18
        assert!(a < slice.len());
19
        Edge::Selfloop(slice.get_mut(a).unwrap())
20
    } else {
21
        assert!(a < slice.len() && b < slice.len());
22

            
23
        // SAFETY: `a` and `b` are in bounds (asserted) and distinct, so the two
24
        // `&mut` borrow disjoint elements and do not alias.
25
        unsafe {
26
            let ar = &mut *(slice.get_unchecked_mut(a) as *mut _);
27
            let br = &mut *(slice.get_unchecked_mut(b) as *mut _);
28
            Edge::Regular(ar, br)
29
        }
30
    }
31
}
32

            
33
#[cfg(kani)]
34
mod verification {
35
    use super::*;
36

            
37
    const LEN: usize = 4;
38

            
39
    #[kani::proof]
40
    fn index_edge_self_loop_returns_selfloop() {
41
        let mut data: [u32; LEN] = kani::any();
42
        let i: usize = kani::any();
43
        kani::assume(i < LEN);
44

            
45
        match index_edge(&mut data, i, i) {
46
            Edge::Selfloop(_) => {}
47
            Edge::Regular(_, _) => panic!("self-loop produced Regular"),
48
        }
49
    }
50

            
51
    #[kani::proof]
52
    fn index_edge_distinct_returns_regular() {
53
        let mut data: [u32; LEN] = kani::any();
54
        let a: usize = kani::any();
55
        let b: usize = kani::any();
56
        kani::assume(a < LEN);
57
        kani::assume(b < LEN);
58
        kani::assume(a != b);
59

            
60
        match index_edge(&mut data, a, b) {
61
            Edge::Regular(_, _) => {}
62
            Edge::Selfloop(_) => panic!("distinct indices produced Selfloop"),
63
        }
64
    }
65

            
66
    #[kani::proof]
67
    fn index_edge_regular_writes_are_independent() {
68
        let mut data: [u32; LEN] = [0; LEN];
69
        let a: usize = kani::any();
70
        let b: usize = kani::any();
71
        kani::assume(a < LEN);
72
        kani::assume(b < LEN);
73
        kani::assume(a != b);
74

            
75
        let va: u32 = kani::any();
76
        let vb: u32 = kani::any();
77

            
78
        if let Edge::Regular(ar, br) = index_edge(&mut data, a, b) {
79
            *ar = va;
80
            *br = vb;
81
        }
82

            
83
        assert_eq!(data[a], va);
84
        assert_eq!(data[b], vb);
85
    }
86
}