ranges 0.3.3

This crate provides a generic alternative to core/std ranges, set-operations to work with them and a range set that can efficiently store them with the least amount of memory possible.
Documentation
use core::cmp::Ordering;
use core::ops::Bound;

use super::{Domain, Iterable};

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

    /// Always returns `Some(self - 1)` unless `self` is `Self::MIN`.
    #[must_use]
    #[allow(clippy::integer_arithmetic)]
    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]
    #[allow(clippy::integer_arithmetic)]
    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) as u8;
        #[allow(clippy::cast_sign_loss)]
        let small = (small ^ Self::MIN) as u8;

        big - small == 2
    }
}

impl Iterable for i8 {
    type Output = Self;

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

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

    #[test]
    fn is_next_to() {
        assert!(i8::MIN.is_next_to(&(i8::MIN + 1)));
        assert!((i8::MIN + 1).is_next_to(&i8::MIN));
        assert!(!i8::MIN.is_next_to(&(i8::MIN + 2)));
        assert!(!i8::MIN.is_next_to(&i8::MAX));
        assert!(!i8::MAX.is_next_to(&i8::MIN));
    }

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

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

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

        // boundary check
        assert_eq!(i8::MIN.shares_neighbour_with(&i8::MAX), false);
        assert_eq!(i8::MAX.shares_neighbour_with(&i8::MIN), false);
    }
}