1use num_traits::Zero;
2
3pub trait RangeStart<Idx = usize> {
25 #[must_use]
27 fn start(&self) -> Idx;
28}
29
30impl<Idx: Clone> RangeStart<Idx> for std::ops::Range<Idx> {
31 #[inline]
32 fn start(&self) -> Idx {
33 self.start.clone()
34 }
35}
36
37impl<Idx: Clone> RangeStart<Idx> for std::ops::RangeFrom<Idx> {
38 #[inline]
39 fn start(&self) -> Idx {
40 self.start.clone()
41 }
42}
43
44impl<Idx: Zero> RangeStart<Idx> for std::ops::RangeFull {
45 #[inline]
46 fn start(&self) -> Idx {
47 Idx::zero()
48 }
49}
50
51impl<Idx: Clone> RangeStart<Idx> for std::ops::RangeInclusive<Idx> {
52 #[inline]
53 fn start(&self) -> Idx {
54 self.start().clone()
55 }
56}
57
58impl<Idx: Zero> RangeStart<Idx> for std::ops::RangeTo<Idx> {
59 #[inline]
60 fn start(&self) -> Idx {
61 Idx::zero()
62 }
63}
64
65impl<Idx: Zero> RangeStart<Idx> for std::ops::RangeToInclusive<Idx> {
66 #[inline]
67 fn start(&self) -> Idx {
68 Idx::zero()
69 }
70}
71
72impl<Idx, T> RangeStart<Idx> for Option<T>
73where
74 Idx: Zero,
75 T: RangeStart<Idx>,
76{
77 #[inline]
78 fn start(&self) -> Idx {
79 self.as_ref().map_or_else(Idx::zero, RangeStart::start)
80 }
81}
82
83impl<Idx, T: RangeStart<Idx>> RangeStart<Idx> for &T {
84 #[inline]
85 fn start(&self) -> Idx {
86 (*self).start()
87 }
88}
89
90impl<Idx, T: RangeStart<Idx>> RangeStart<Idx> for &mut T {
91 #[inline]
92 fn start(&self) -> Idx {
93 (**self).start()
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::RangeStart;
100
101 #[test]
102 fn stored_starts_are_reported() {
103 assert_eq!((2usize..8).start(), 2);
104 assert_eq!((2usize..).start(), 2);
105 assert_eq!(RangeStart::start(&(2usize..=8)), 2);
106 }
107
108 #[test]
109 fn end_only_ranges_anchor_at_zero() {
110 assert_eq!(RangeStart::<i32>::start(&(..)), 0);
111 assert_eq!((..8i32).start(), 0);
112 assert_eq!((..=-1i32).start(), 0);
113 }
114
115 #[test]
116 fn none_anchors_at_zero() {
117 assert_eq!(None::<std::ops::Range<usize>>.start(), 0);
118 assert_eq!(Some(2usize..8).start(), 2);
119 }
120
121 #[test]
122 fn references_forward() {
123 fn start_of<Idx, R: RangeStart<Idx>>(range: R) -> Idx {
124 range.start()
125 }
126
127 let mut range = 2usize..8;
128
129 assert_eq!(start_of(&range), 2);
130 assert_eq!(start_of(&mut range), 2);
131 }
132}