more_errors 0.1.0

Provides reusable errors.
Documentation
use std::{
    fmt::{self, Display},
    ops::{Bound, RangeBounds},
};

/// Error representing a range out of bounds situation.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RangeOutOfBoundsError {
    use_check_to_instantiate: (),
}

impl RangeOutOfBoundsError {
    /// Checks if the given `range` is within bounds of `len`.
    ///
    /// Returns `Ok(())` if `range` is within bounds, otherwise `Err(RangeOutOfBoundsError)`.
    pub fn check<R>(range: &R, len: usize) -> Result<(), Self>
    where
        R: RangeBounds<usize>,
    {
        let start = match range.start_bound() {
            Bound::Included(&start) => start,
            Bound::Excluded(&start) => start.checked_add(1).ok_or(RangeOutOfBoundsError {
                use_check_to_instantiate: (),
            })?,
            Bound::Unbounded => 0,
        };

        let end = match range.end_bound() {
            Bound::Included(&end) => end.checked_add(1).ok_or(RangeOutOfBoundsError {
                use_check_to_instantiate: (),
            })?,
            Bound::Excluded(&end) => end,
            Bound::Unbounded => len,
        };

        if start > end || end > len {
            Err(RangeOutOfBoundsError {
                use_check_to_instantiate: (),
            })
        } else {
            Ok(())
        }
    }
}

impl Display for RangeOutOfBoundsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{self:#?}\n The range was out of bounds: Either the starting point was greater than the end point or the end point was greater than the length.")
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_range_out_of_bounds_error() {
        // Valid case
        assert!(RangeOutOfBoundsError::check(&(0..7), 7).is_ok());

        // Invalid case
        assert!(RangeOutOfBoundsError::check(&(0..8), 7).is_err());
    }
}