1#![no_std]
10
11use core::ops::Range;
12
13pub const fn from_offset_len(offset: u64, len: u64) -> Option<Range<u64>> {
17 match offset.checked_add(len) {
18 Some(end) => Some(offset..end),
19 None => None,
20 }
21}
22
23pub const fn from_offset_len_usize(offset: usize, len: usize) -> Option<Range<usize>> {
27 match offset.checked_add(len) {
28 Some(end) => Some(offset..end),
29 None => None,
30 }
31}
32
33pub fn in_range<T: Ord + Copy>(inner: &Range<T>, outer: &Range<T>) -> bool {
38 inner.start >= outer.start && inner.end <= outer.end && inner.start <= inner.end
39}
40
41pub fn in_range_max(offset: u64, len: u64, max: u64) -> bool {
45 let Some(range) = from_offset_len(offset, len) else {
46 return false;
47 };
48 in_range(&range, &(0..max))
49}
50
51pub fn in_range_min_max(offset: u64, len: u64, min: u64, max: u64) -> bool {
55 let Some(range) = from_offset_len(offset, len) else {
56 return false;
57 };
58 in_range(&range, &(min..max))
59}
60
61pub fn trim_range<T: Ord + Copy>(range: &Range<T>, trim_to_len: T) -> Option<Range<T>> {
66 if range.start > trim_to_len || range.start > range.end {
67 return None;
68 }
69 let end = core::cmp::min(range.end, trim_to_len);
70 Some(range.start..end)
71}
72
73pub fn trim_range_offset_len(offset: u64, len: u64, trim_to_len: u64) -> Option<u64> {
77 let range = from_offset_len(offset, len)?;
78 let trimmed = trim_range(&range, trim_to_len)?;
79 Some(trimmed.end - trimmed.start)
80}
81
82pub fn intersects<T: Ord + Copy>(r1: &Range<T>, r2: &Range<T>) -> bool {
86 r1.start < r1.end && r2.start < r2.end && r1.start < r2.end && r2.start < r1.end
87}
88
89pub fn intersects_offset_len(offset1: u64, len1: u64, offset2: u64, len2: u64) -> bool {
93 let Some(r1) = from_offset_len(offset1, len1) else {
94 return false;
95 };
96 let Some(r2) = from_offset_len(offset2, len2) else {
97 return false;
98 };
99 intersects(&r1, &r2)
100}
101
102pub fn get_intersect<T: Ord + Copy>(r1: &Range<T>, r2: &Range<T>) -> Option<Range<T>> {
105 if !intersects(r1, r2) {
106 return None;
107 }
108 let start = core::cmp::max(r1.start, r2.start);
109 let end = core::cmp::min(r1.end, r2.end);
110 Some(start..end)
111}
112
113pub fn get_intersect_offset_len(
116 offset1: u64,
117 len1: u64,
118 offset2: u64,
119 len2: u64,
120) -> Option<(u64, u64)> {
121 let r1 = from_offset_len(offset1, len1)?;
122 let r2 = from_offset_len(offset2, len2)?;
123 let intersection = get_intersect(&r1, &r2)?;
124 Some((intersection.start, intersection.end - intersection.start))
125}
126
127pub trait RangeExt<T> {
129 fn in_range(&self, outer: &Range<T>) -> bool;
131
132 fn intersects(&self, other: &Range<T>) -> bool;
134
135 fn intersect(&self, other: &Range<T>) -> Option<Range<T>>;
137
138 fn trim(&self, trim_to_len: T) -> Option<Range<T>>;
140}
141
142impl<T: Ord + Copy> RangeExt<T> for Range<T> {
143 fn in_range(&self, outer: &Range<T>) -> bool {
144 in_range(self, outer)
145 }
146
147 fn intersects(&self, other: &Range<T>) -> bool {
148 intersects(self, other)
149 }
150
151 fn intersect(&self, other: &Range<T>) -> Option<Range<T>> {
152 get_intersect(self, other)
153 }
154
155 fn trim(&self, trim_to_len: T) -> Option<Range<T>> {
156 trim_range(self, trim_to_len)
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_in_range_basic() {
166 assert!(in_range_max(0, 1024, 4096));
168 assert!(in_range_min_max(0, 1024, 0, 4096));
169 assert!((0..1024).in_range(&(0..4096)));
170
171 assert!(!in_range_min_max(0, 1024, 1, 4096));
173 assert!(!(0..1024).in_range(&(1..4096)));
174
175 assert!(in_range_min_max(0, 1024, 0, 1024));
177 assert!((0..1024).in_range(&(0..1024)));
178
179 assert!(!in_range_min_max(0, 1024, 0, 1023));
181 assert!(!(0..1024).in_range(&(0..1023)));
182
183 assert!(!in_range_min_max(32768, 1024, 524288, 1048576));
185 assert!(!(32768..33792).in_range(&(524288..1048576)));
186
187 assert!(!in_range_min_max(4000, 1000, 4500, 5500));
189 assert!(!in_range_min_max(5000, 1000, 4500, 5500));
190 assert!(!in_range_min_max(4000, 2000, 4500, 5500));
191 }
192
193 #[test]
194 fn test_in_range_overflow() {
195 assert!(!in_range_max(u64::MAX - 10, 20, u64::MAX));
196 assert!(!in_range_min_max(u64::MAX - 10, 20, 0, u64::MAX));
197 }
198
199 #[test]
200 fn test_trim_range() {
201 assert_eq!(trim_range_offset_len(0, 1000, 500), Some(500));
202 assert_eq!(trim_range_offset_len(0, 1000, 2000), Some(1000));
203 assert_eq!(trim_range_offset_len(500, 1000, 1000), Some(500));
204 assert_eq!(trim_range_offset_len(1000, 1000, 1000), Some(0));
205 assert_eq!(trim_range_offset_len(1500, 1000, 1000), None);
206
207 assert_eq!((0..1000).trim(500), Some(0..500));
208 assert_eq!((0..1000).trim(2000), Some(0..1000));
209 assert_eq!((1500..2500).trim(1000), None);
210 }
211
212 #[test]
213 fn test_intersects() {
214 assert!(!intersects_offset_len(0, 10, 10, 10));
216 assert!(!intersects_offset_len(10, 10, 0, 10));
217 assert!(!(0..10).intersects(&(10..20)));
218 assert!(!(10..20).intersects(&(0..10)));
219
220 assert!(intersects_offset_len(0, 10, 5, 10));
222 assert!(intersects_offset_len(5, 10, 0, 10));
223 assert!((0..10).intersects(&(5..15)));
224 assert!((5..15).intersects(&(0..10)));
225
226 assert!(intersects_offset_len(0, 20, 5, 5));
228 assert!(intersects_offset_len(5, 5, 0, 20));
229 assert!((0..20).intersects(&(5..10)));
230 assert!((5..10).intersects(&(0..20)));
231
232 assert!(!intersects_offset_len(5, 0, 0, 20));
234 assert!(!intersects_offset_len(0, 20, 5, 0));
235 assert!(!(5..5).intersects(&(0..20)));
236 assert!(!(0..20).intersects(&(5..5)));
237 }
238
239 #[test]
240 fn test_get_intersect() {
241 assert_eq!(get_intersect_offset_len(0, 10, 10, 10), None);
242 assert_eq!(get_intersect_offset_len(0, 10, 5, 10), Some((5, 5)));
243 assert_eq!(get_intersect_offset_len(5, 10, 0, 10), Some((5, 5)));
244 assert_eq!(get_intersect_offset_len(0, 20, 5, 10), Some((5, 10)));
245 assert_eq!(get_intersect_offset_len(5, 10, 0, 20), Some((5, 10)));
246
247 assert_eq!((0..10).intersect(&(10..20)), None);
248 assert_eq!((0..10).intersect(&(5..15)), Some(5..10));
249 assert_eq!((5..15).intersect(&(0..10)), Some(5..10));
250 assert_eq!((0..20).intersect(&(5..15)), Some(5..15));
251 }
252}