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
use std::error::Error as ErrorTrait;
use std::ops::RangeBounds;
use std::fmt;

use bounds::{Bounds, copy_bound};


/// Trait that provides early returns for failed range checks using the
/// `Result` type.
pub trait Check<R: RangeBounds<Self>>: Sized + PartialOrd + Copy {

    /// Checks whether `self` is within the given range. If it is, re-returns
    /// `self`. Otherwise, returns an `Error` that contains both the value and
    /// the range.
    ///
    /// # Examples
    ///
    /// ```
    /// use range_check::Check;
    ///
    /// assert!(24680.check_range(1..99999).is_ok());
    /// assert!(24680.check_range(1..9999).is_err());
    /// ```
    fn check_range(self, range: R) -> Result<Self, OutOfRangeError<Self>>;
}

impl<T, R> Check<R> for T
where R: RangeBounds<T>,
      T: PartialOrd + Copy,
{
    fn check_range(self, range: R) -> Result<Self, OutOfRangeError<Self>> {
        if range.contains(&self) {
            Ok(self)
        }
        else {
            let bounds = Bounds {
                lower: copy_bound(range.start_bound()),
                upper: copy_bound(range.end_bound()),
            };

            Err(OutOfRangeError { allowed_range: bounds, outside_value: self })
        }
    }
}


/// The error that gets thrown when a `check_range` fails.
#[derive(PartialEq, Debug, Clone)]
pub struct OutOfRangeError<T> {

    /// The bounds of the range that was searched.
    pub allowed_range: Bounds<T>,

    /// The value that lies outside of the range.
    pub outside_value: T,
}

impl<T: fmt::Debug> ErrorTrait for OutOfRangeError<T> {
    fn description(&self) -> &str {
        "value outside of range"
    }
}

impl<T: fmt::Debug> fmt::Display for OutOfRangeError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "value ({:?}) outside of range ({})",
            self.outside_value, self.allowed_range)
    }
}

impl<T> OutOfRangeError<T> {

    /// Converts this error to an error with the same values as another type.
    /// The other type must be `From`-convertible from this one.
    ///
    /// # Examples
    ///
    /// ```
    /// use range_check::{Check, OutOfRangeError};
    ///
    /// let err: OutOfRangeError<i16> = 24680.check_range(1..9999).unwrap_err();
    /// let err: OutOfRangeError<i32> = err.generify();
    /// ```
    pub fn generify<U: From<T>>(self) -> OutOfRangeError<U> {
        OutOfRangeError {
            allowed_range: self.allowed_range.convert(),
            outside_value: self.outside_value.into(),
        }
    }
}