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
use core::cmp::Ordering;
use core::ops::Bound;

use super::{Domain, Iterable};

impl Domain for u32 {
    const DISCRETE: bool = true;

    /// Always returns `Some(self - 1)` unless `self` is zero.
    #[must_use]
    fn predecessor(&self) -> Option<Self> {
        match *self {
            Self::MIN => None,
            _ => Some(self - 1),
        }
    }

    /// Always returns `Some(self + 1)` unless `self` is `Self::MAX`.
    #[must_use]
    fn successor(&self) -> Option<Self> {
        match *self {
            Self::MAX => None,
            _ => Some(self + 1),
        }
    }

    /// Returns `Included(Self::MIN)`.
    #[must_use]
    fn minimum() -> Bound<Self> {
        Bound::Included(Self::MIN)
    }

    /// Returns `Included(Self::MAX)`.
    #[must_use]
    fn maximum() -> Bound<Self> {
        Bound::Included(Self::MAX)
    }

    #[must_use]
    #[allow(clippy::shadow_reuse, clippy::integer_arithmetic)]
    fn shares_neighbour_with(&self, other: &Self) -> bool {
        let (big, small) = match self.cmp(other) {
            Ordering::Less => (other, self),
            Ordering::Equal => return false,
            Ordering::Greater => (self, other),
        };

        big - small == 2
    }
}

impl Iterable for u32 {
    type Output = Self;

    fn next(&self) -> Option<Self::Output> {
        if *self == Self::max_value() {
            None
        } else {
            #[allow(clippy::integer_arithmetic)]
            Some(*self + 1)
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::Domain;

    #[test]
    fn is_next_to() {
        assert!(u32::min_value().is_next_to(&(u32::min_value() + 1)));
        assert!((u32::min_value() + 1).is_next_to(&u32::min_value()));
        assert!(!u32::min_value().is_next_to(&(u32::min_value() + 2)));
        assert!(!u32::min_value().is_next_to(&u32::max_value()));
        assert!(!u32::max_value().is_next_to(&u32::min_value()));
    }

    #[test]
    fn shares_neighbour_with() {
        // self-distance
        assert_eq!(u32::min_value().shares_neighbour_with(&u32::min_value()), false);

        // "normal" value
        assert_eq!(42_u32.shares_neighbour_with(&45), false);
        assert_eq!(45_u32.shares_neighbour_with(&42), false);

        assert_eq!(42_u32.shares_neighbour_with(&44), true);
        assert_eq!(44_u32.shares_neighbour_with(&42), true);

        // boundary check
        assert_eq!(u32::min_value().shares_neighbour_with(&u32::max_value()), false);
        assert_eq!(u32::max_value().shares_neighbour_with(&u32::min_value()), false);
    }
}