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

use super::{Domain, Iterable};

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

    /// Always returns `Some(self - 1)` unless `self` is `Self::MIN`.
    #[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, clippy::as_conversions)]
    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),
        };

        #[allow(clippy::cast_sign_loss)]
        let big = (big ^ Self::min_value()) as u32;
        #[allow(clippy::cast_sign_loss)]
        let small = (small ^ Self::min_value()) as u32;

        big - small == 2
    }
}

impl Iterable for i32 {
    type Output = Self;

    #[must_use]
    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!(i32::min_value().is_next_to(&(i32::min_value() + 1)));
        assert!((i32::min_value() + 1).is_next_to(&i32::min_value()));
        assert!(!i32::min_value().is_next_to(&(i32::min_value() + 2)));
        assert!(!i32::min_value().is_next_to(&i32::max_value()));
        assert!(!i32::max_value().is_next_to(&i32::min_value()));
    }

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

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

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

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