1pub trait ToOffset where Self:PartialOrd {
7 fn to_offset(self, length: usize) -> usize;
8}
9
10
11fn offset_wihin_range(offset: usize, length: usize) -> usize {
12if offset > length {
13 length
14} else {
15 offset
16}
17}
18
19macro_rules! impl_indexable_signed_to_offset {
21 ($t:ty) => {
22 impl ToOffset for $t {
23 fn to_offset(self, length: usize) -> usize {
24 let offset = if self < 0 {
25 length.saturating_sub(self.abs() as usize)
26 } else {
27 self as usize
28 };
29 offset_wihin_range(offset, length)
30 }
31 }
32 };
33}
34
35macro_rules! impl_indexable_unsigned_to_offset {
37 ($t:ty) => {
38 impl ToOffset for $t {
39 fn to_offset(self, length: usize) -> usize {
40 offset_wihin_range(self as usize, length)
41 }
42 }
43 };
44}
45
46impl_indexable_signed_to_offset!(i32);
48
49impl_indexable_signed_to_offset!(i64);
51
52impl_indexable_unsigned_to_offset!(u8);
54
55impl_indexable_unsigned_to_offset!(u16);
57
58impl_indexable_unsigned_to_offset!(u32);
60
61impl_indexable_unsigned_to_offset!(u64);
63
64impl_indexable_unsigned_to_offset!(usize);
66
67
68pub trait FromOffset<T> where T:Sized {
73 fn from_offset<U: ToOffset>(&self, relative_index: U) -> Option<&T>;
74}
75
76impl<T> FromOffset<T> for [T] {
77 fn from_offset<U: ToOffset>(&self, relative_index: U) -> Option<&T> {
78 let length = self.len();
79 if length < 1 {
80 return None;
81 }
82 let target_index = relative_index.to_offset(length);
83 let index = if target_index < length {
84 target_index
85 } else {
86 target_index - 1
87 };
88 self.get(index)
89 }
90}
91
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_end_offset() {
99 let integer_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
100
101 let penultimate_index = (-2).to_offset(integer_array.len());
102
103 assert_eq!(penultimate_index, 10);
104
105 let penultimate_value = integer_array[penultimate_index];
106
107 assert_eq!(penultimate_value, 11);
108
109 let third_from_last = integer_array.from_offset(-3);
110
111 assert_eq!(*third_from_last.unwrap(), 10);
112 }
113
114 #[test]
115 fn test_array_overflow() {
116 let integer_array = [1, 2, 3, 4, 5, 6];
117
118 let distant_element_index = 1_000_000.to_offset(integer_array.len());
119
120 assert_eq!(distant_element_index, 6);
122
123 let twentieth_from_the_end = integer_array.from_offset(-20);
124
125 assert_eq!(twentieth_from_the_end.unwrap().to_owned(), 1);
127
128 }
129}