ranges 0.4.0

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, ops::Bound};

use super::{Domain, Iterable};

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

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

        big - small == 2
    }
}

impl Iterable for isize {
    type Output = Self;

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

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

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

    #[test]
    fn shares_neighbour_with() {
        // self-distance
        assert!(!isize::MIN.shares_neighbour_with(&isize::MIN));

        // "normal" value
        assert!(!42_isize.shares_neighbour_with(&45));
        assert!(!45_isize.shares_neighbour_with(&42));

        assert!(42_isize.shares_neighbour_with(&44));
        assert!(44_isize.shares_neighbour_with(&42));

        // boundary check
        assert!(!isize::MIN.shares_neighbour_with(&isize::MAX));
        assert!(!isize::MAX.shares_neighbour_with(&isize::MIN));
    }
}