offset_views/
with_offset.rs1pub trait WithOffset<O> {
11 type Output;
12 fn with_offset(&self, offset: O) -> Self::Output;
16}
17
18impl WithOffset<isize> for isize {
19 type Output = usize;
20 fn with_offset(&self, offset: isize) -> usize {
21 (self + offset)
22 .try_into()
23 .expect("cannot convert to `usize`")
24 }
25}
26
27use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
28
29impl<I> WithOffset<isize> for Range<I>
30where
31 I: WithOffset<isize, Output = usize>,
32{
33 type Output = Range<usize>;
34 fn with_offset(&self, offset: isize) -> Range<usize> {
35 self.start.with_offset(offset)..self.end.with_offset(offset)
36 }
37}
38
39impl<I> WithOffset<isize> for RangeInclusive<I>
40where
41 I: WithOffset<isize, Output = usize>,
42{
43 type Output = RangeInclusive<usize>;
44 fn with_offset(&self, offset: isize) -> RangeInclusive<usize> {
45 self.start().with_offset(offset)..=self.end().with_offset(offset)
46 }
47}
48
49impl<I> WithOffset<isize> for RangeFrom<I>
50where
51 I: WithOffset<isize, Output = usize>,
52{
53 type Output = RangeFrom<usize>;
54 fn with_offset(&self, offset: isize) -> RangeFrom<usize> {
55 self.start.with_offset(offset)..
56 }
57}
58
59impl<I> WithOffset<isize> for RangeTo<I>
60where
61 I: WithOffset<isize, Output = usize>,
62{
63 type Output = RangeTo<usize>;
64 fn with_offset(&self, offset: isize) -> RangeTo<usize> {
65 ..self.end.with_offset(offset)
66 }
67}
68
69impl<I> WithOffset<isize> for RangeToInclusive<I>
70where
71 I: WithOffset<isize, Output = usize>,
72{
73 type Output = RangeToInclusive<usize>;
74 fn with_offset(&self, offset: isize) -> RangeToInclusive<usize> {
75 ..=self.end.with_offset(offset)
76 }
77}
78
79impl WithOffset<isize> for RangeFull {
80 type Output = RangeFull;
81 fn with_offset(&self, _offset: isize) -> RangeFull {
82 RangeFull
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use cool_asserts::assert_panics;
90
91 #[test]
92 fn isize() {
93 assert_eq!(0.with_offset(5), 5);
94 assert_panics!(0.with_offset(-5), includes("cannot convert to `usize`"));
95 assert_eq!(3.with_offset(3), 6);
96 assert_eq!(3.with_offset(-3), 0);
97 assert_panics!(3.with_offset(-5), includes("cannot convert to `usize`"));
98 }
99
100 #[test]
101 fn range() {
102 assert_eq!((0..10).with_offset(3), 3..13);
103 assert_eq!((3..13).with_offset(-3), 0..10);
104 assert_panics!(
105 (3..13).with_offset(-5),
106 includes("cannot convert to `usize`")
107 );
108 }
109
110 #[test]
111 fn range_inclusive() {
112 assert_eq!((0..=10).with_offset(3), 3..=13);
113 assert_eq!((3..=13).with_offset(-3), 0..=10);
114 assert_panics!(
115 (3..=13).with_offset(-5),
116 includes("cannot convert to `usize`")
117 );
118 }
119
120 #[test]
121 fn range_from() {
122 assert_eq!((0..).with_offset(3), 3..);
123 assert_eq!((3..).with_offset(-3), 0..);
124 assert_panics!((3..).with_offset(-5), includes("cannot convert to `usize`"));
125 }
126
127 #[test]
128 fn range_to() {
129 assert_eq!((..10).with_offset(3), ..13);
130 assert_eq!((..13).with_offset(-3), ..10);
131 assert_eq!((..13).with_offset(-5), (..8));
132 }
133
134 #[test]
135 fn range_to_inclusive() {
136 assert_eq!((..=10).with_offset(3), ..=13);
137 assert_eq!((..=13).with_offset(-3), ..=10);
138 assert_eq!((..=13).with_offset(-5), (..=8));
139 }
140
141 #[test]
142 fn range_full() {
143 assert_eq!(RangeFull.with_offset(5), RangeFull);
144 assert_eq!(RangeFull.with_offset(-5), RangeFull);
145 }
146}