1use std::ops;
2
3fn slice_index_fail(start: usize, end: usize, len: usize) -> ! {
5 if start > len {
6 panic!("range start index {start} out of range for slice of length {len}",)
7 }
8
9 if end > len {
10 panic!("range end index {end} out of range for slice of length {len}",)
11 }
12
13 if start > end {
14 panic!("slice index starts at {start} but ends at {end}",)
15 }
16
17 panic!("range end index {end} out of range for slice of length {len}",)
20}
21
22#[must_use]
23pub fn check_range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
24where
25 R: ops::RangeBounds<usize>,
26{
27 let len = bounds.end;
28 let end = match range.end_bound() {
29 ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len),
30 ops::Bound::Included(&end) => end + 1,
32
33 ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len),
34 ops::Bound::Excluded(&end) => end,
35 ops::Bound::Unbounded => len,
36 };
37
38 let start = match range.start_bound() {
39 ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len),
40 ops::Bound::Excluded(&start) => start + 1,
42
43 ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len),
44 ops::Bound::Included(&start) => start,
45
46 ops::Bound::Unbounded => 0,
47 };
48
49 ops::Range { start, end }
50}
51
52#[must_use]
53pub fn decode_range_unchecked<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
54where
55 R: ops::RangeBounds<usize>,
56{
57 let len = bounds.end;
58 let end = match range.end_bound() {
59 ops::Bound::Included(&end) => end + 1,
60 ops::Bound::Excluded(&end) => end,
61 ops::Bound::Unbounded => len,
62 };
63
64 let start = match range.start_bound() {
65 ops::Bound::Excluded(&start) => start + 1,
66 ops::Bound::Included(&start) => start,
67 ops::Bound::Unbounded => 0,
68 };
69
70 ops::Range { start, end }
71}