Skip to main content

mtl_foundation/
range.rs

1//! Range type for Foundation.
2//!
3//! Corresponds to `Foundation/NSRange.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace NS {
9//! struct Range {
10//!     static Range Make(UInteger loc, UInteger len);
11//!     Range(UInteger loc, UInteger len);
12//!     bool     Equal(const Range& range) const;
13//!     bool     LocationInRange(UInteger loc) const;
14//!     UInteger Max() const;
15//!     UInteger location;
16//!     UInteger length;
17//! } _NS_PACKED;
18//! }
19//! ```
20
21use crate::types::UInteger;
22
23/// A structure used to describe a portion of a series.
24///
25/// C++ equivalent: `NS::Range`
26#[repr(C, packed)]
27#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
28pub struct Range {
29    /// The start index of the range.
30    pub location: UInteger,
31    /// The number of items in the range.
32    pub length: UInteger,
33}
34
35impl Range {
36    /// Create a new range.
37    ///
38    /// C++ equivalent: `NS::Range::Range(UInteger loc, UInteger len)`
39    #[inline]
40    pub const fn new(location: UInteger, length: UInteger) -> Self {
41        Self { location, length }
42    }
43
44    /// Create a new range (static factory method).
45    ///
46    /// C++ equivalent: `NS::Range::Make(UInteger loc, UInteger len)`
47    #[inline]
48    pub const fn make(location: UInteger, length: UInteger) -> Self {
49        Self::new(location, length)
50    }
51
52    /// Check if two ranges are equal.
53    ///
54    /// C++ equivalent: `NS::Range::Equal(const Range& range) const`
55    #[inline]
56    pub const fn equal(&self, other: &Range) -> bool {
57        self.location == other.location && self.length == other.length
58    }
59
60    /// Check if a location is within this range.
61    ///
62    /// C++ equivalent: `NS::Range::LocationInRange(UInteger loc) const`
63    #[inline]
64    pub const fn location_in_range(&self, loc: UInteger) -> bool {
65        loc >= self.location && (loc - self.location) < self.length
66    }
67
68    /// Get the maximum value in the range (location + length).
69    ///
70    /// C++ equivalent: `NS::Range::Max() const`
71    #[inline]
72    pub const fn max(&self) -> UInteger {
73        self.location + self.length
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_range_new() {
83        let range = Range::new(10, 5);
84        let location = { range.location };
85        let length = { range.length };
86        assert_eq!(location, 10);
87        assert_eq!(length, 5);
88    }
89
90    #[test]
91    fn test_range_equal() {
92        let r1 = Range::new(10, 5);
93        let r2 = Range::new(10, 5);
94        let r3 = Range::new(10, 6);
95
96        assert!(r1.equal(&r2));
97        assert!(!r1.equal(&r3));
98    }
99
100    #[test]
101    fn test_location_in_range() {
102        let range = Range::new(10, 5);
103
104        assert!(!range.location_in_range(9));
105        assert!(range.location_in_range(10));
106        assert!(range.location_in_range(14));
107        assert!(!range.location_in_range(15));
108    }
109
110    #[test]
111    fn test_range_max() {
112        let range = Range::new(10, 5);
113        assert_eq!(range.max(), 15);
114    }
115}