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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
use std::cmp::PartialOrd;
use std::marker::PhantomData;
trait Overlaps<T> {
fn overlaps(&self, other: &T) -> bool;
}
trait Contains<T> {
fn contains(&self, other: &T) -> bool;
}
impl<T: PartialOrd> Overlaps<Interval<T>> for Interval<T> {
fn overlaps(&self, other: &Interval<T>) -> bool {
!(self < other || other < self)
}
}
impl<T: PartialOrd> Contains<Interval<T>> for Interval<T> {
fn contains(&self, other: &Interval<T>) -> bool {
self.lb <= other.lb && other.ub <= self.ub
}
}
impl<T: PartialOrd> Contains<T> for Interval<T> {
fn contains(&self, other: &T) -> bool {
self.lb <= *other && *other <= self.ub
}
}
/// The `Interval` struct represents a range of values with a lower bound (`lb`) and an upper bound
/// (`ub`).
///
/// Properties:
///
/// * `lb`: The `lb` property represents the lower bound of the interval. It is of type `T`, which is a
/// generic type that must implement the `PartialOrd` trait. This means that the type `T` must be able
/// to be compared for ordering.
/// * `ub`: The `ub` property represents the upper bound of the interval. It is of type `T`, which is a
/// generic type that must implement the `PartialOrd` trait. The `PartialOrd` trait allows for
/// comparison between values of type `T`.
/// * `_marker`: The `_marker` field is a marker field that is used to indicate that the generic type
/// `T` is used in the struct. It is typically used when you want to associate a type parameter with a
/// struct, but you don't actually need to store any values of that type in the struct.
#[derive(Debug)]
pub struct Interval<T: PartialOrd> {
pub lb: T,
pub ub: T,
pub _marker: PhantomData<T>,
}
impl<T: PartialOrd> Interval<T> {
/// The function `new` creates a new instance of a struct with given lower and upper bounds.
///
/// Arguments:
///
/// * `lb`: The `lb` parameter represents the lower bound value. It is of type `T`, which means it
/// can be any type that implements the necessary traits for the struct.
/// * `ub`: The `ub` parameter represents the upper bound value. It is of type `T`, which means it
/// can be any type that implements the necessary traits for the struct.
///
/// Returns:
///
/// The `new` function is returning an instance of the struct `Self`.
///
/// # Examples
///
/// ```
/// use physdes::interval_ai::Interval;
/// use std::marker::PhantomData;
///
/// assert_eq!(Interval::new(1, 2), Interval { lb: 1, ub: 2, _marker: PhantomData });
/// assert_eq!(Interval::new(2, 1), Interval { lb: 2, ub: 1, _marker: PhantomData });
/// ```
pub fn new(lb: T, ub: T) -> Self {
Self {
lb,
ub,
_marker: PhantomData,
}
}
}
impl<T: PartialOrd> PartialOrd for Interval<T> {
/// The function `partial_cmp` compares the lower bound of `self` with the upper bound of `other`
/// and returns the result as an `Option` of `Ordering`.
///
/// Arguments:
///
/// * `other`: The `other` parameter is a reference to another object of the same type as `self`.
///
/// Returns:
///
/// an `Option` containing a `std::cmp::Ordering` value.
///
/// # Examples
///
/// ```
/// use physdes::interval_ai::Interval;
/// use std::marker::PhantomData;
/// assert_eq!(Interval::new(1, 2).partial_cmp(&Interval::new(2, 3)), Some(std::cmp::Ordering::Less));
/// ```
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.lb.partial_cmp(&other.ub)
}
}
impl<T: PartialOrd> PartialEq for Interval<T> {
/// The function checks if two objects have equal values for their "lb" and "ub" fields.
///
/// Arguments:
///
/// * `other`: The `other` parameter is a reference to another object of the same type as `Self`. In
/// this case, `Self` refers to the type of the object implementing the `eq` method.
///
/// Returns:
///
/// A boolean value is being returned.
///
/// # Examples
///
/// ```
/// use physdes::interval_ai::Interval;
/// assert_eq!(Interval::new(1, 2), Interval::new(1, 2));
/// ```
fn eq(&self, other: &Self) -> bool {
self.lb == other.lb && self.ub == other.ub
}
}
pub fn overlap<T: PartialOrd>(lhs: &Interval<T>, rhs: &Interval<T>) -> bool {
lhs.overlaps(rhs) || rhs.overlaps(lhs) || lhs == rhs
}
pub fn contain<T: PartialOrd>(lhs: &Interval<T>, rhs: &Interval<T>) -> bool {
lhs.contains(rhs) && !rhs.contains(lhs)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_interval() {
let a = Interval::new(4, 8);
let b = Interval::new(5, 6);
assert!(!overlap(&a, &b));
assert!(!overlap(&b, &a));
// assert!(!contain(&a, &b));
assert!(a.contains(&4));
assert!(a.contains(&8));
assert!(a.contains(&b));
assert_eq!(a, a);
assert_eq!(b, b);
assert_ne!(a, b);
assert_ne!(b, a);
assert!(overlap(&a, &a));
assert!(overlap(&b, &b));
assert!(!contain(&a, &a));
assert!(!contain(&b, &b));
// assert!(a.overlaps(&b));
// assert!(b.overlaps(&a));
}
}