1use num_traits::{CheckedAdd, One, SaturatingSub};
2
3use crate::{Range, RangeEnd};
4
5pub trait RangeExt<Idx = usize>: crate::RangeStart<Idx>
28where
29 Idx: Clone + Ord,
30{
31 #[must_use]
36 fn end_inclusive(&self) -> Idx;
37
38 #[must_use]
42 fn end_exclusive(&self) -> Option<Idx>;
43
44 #[inline]
50 #[must_use]
51 fn clamp_to(&self, start: impl Into<Idx>, end: impl Into<Idx>) -> std::ops::Range<Idx> {
52 let window_end = end.into();
53
54 let end = match self.end_exclusive() {
57 Some(end) => end.min(window_end),
58 None => window_end,
59 };
60 let start = self.start().max(start.into()).min(end.clone());
61
62 start..end
63 }
64
65 #[inline]
67 #[must_use]
68 fn clamp_right(&self, end: impl Into<Idx>) -> std::ops::Range<Idx> {
69 self.clamp_to(self.start(), end)
70 }
71}
72
73impl<Idx> RangeExt<Idx> for std::ops::Range<Idx>
74where
75 Idx: Clone + Ord + One + SaturatingSub,
76{
77 #[inline]
78 fn end_inclusive(&self) -> Idx {
79 self.end.saturating_sub(&Idx::one())
80 }
81
82 #[inline]
83 fn end_exclusive(&self) -> Option<Idx> {
84 Some(self.end.clone())
85 }
86}
87
88impl<Idx> RangeExt<Idx> for std::ops::RangeInclusive<Idx>
92where
93 Idx: Clone + Ord + One + CheckedAdd,
94{
95 #[inline]
96 fn end_inclusive(&self) -> Idx {
97 self.end().clone()
98 }
99
100 #[inline]
101 fn end_exclusive(&self) -> Option<Idx> {
102 if self.is_empty() {
103 Some(self.start().clone())
104 } else {
105 self.end().checked_add(&Idx::one())
106 }
107 }
108}
109
110impl<Idx> RangeExt<Idx> for std::ops::RangeTo<Idx>
111where
112 Idx: Clone + Ord + num_traits::Zero + One + SaturatingSub,
113{
114 #[inline]
115 fn end_inclusive(&self) -> Idx {
116 self.end.saturating_sub(&Idx::one())
117 }
118
119 #[inline]
120 fn end_exclusive(&self) -> Option<Idx> {
121 Some(self.end.clone())
122 }
123}
124
125impl<Idx> RangeExt<Idx> for std::ops::RangeToInclusive<Idx>
126where
127 Idx: Clone + Ord + num_traits::Zero + One + CheckedAdd,
128{
129 #[inline]
130 fn end_inclusive(&self) -> Idx {
131 self.end.clone()
132 }
133
134 #[inline]
135 fn end_exclusive(&self) -> Option<Idx> {
136 self.end.checked_add(&Idx::one())
137 }
138}
139
140impl<Idx> RangeExt<Idx> for Range<Idx>
141where
142 Idx: Clone + Ord + One + CheckedAdd + SaturatingSub,
143{
144 #[inline]
145 fn end_inclusive(&self) -> Idx {
146 match &self.end {
147 RangeEnd::Inclusive(end) => end.clone(),
148 RangeEnd::Exclusive(end) => end.saturating_sub(&Idx::one()),
149 }
150 }
151
152 #[inline]
153 fn end_exclusive(&self) -> Option<Idx> {
154 match &self.end {
155 RangeEnd::Inclusive(end) => end.checked_add(&Idx::one()),
156 RangeEnd::Exclusive(end) => Some(end.clone()),
157 }
158 }
159}
160
161impl<Idx, T> RangeExt<Idx> for &T
162where
163 Idx: Clone + Ord,
164 T: RangeExt<Idx>,
165{
166 #[inline]
167 fn end_inclusive(&self) -> Idx {
168 (*self).end_inclusive()
169 }
170
171 #[inline]
172 fn end_exclusive(&self) -> Option<Idx> {
173 (*self).end_exclusive()
174 }
175}
176
177impl<Idx, T> RangeExt<Idx> for &mut T
178where
179 Idx: Clone + Ord,
180 T: RangeExt<Idx>,
181{
182 #[inline]
183 fn end_inclusive(&self) -> Idx {
184 (**self).end_inclusive()
185 }
186
187 #[inline]
188 fn end_exclusive(&self) -> Option<Idx> {
189 (**self).end_exclusive()
190 }
191}