1use std::{
14 fmt::Display,
15 ops::{Add, AddAssign, Index, IndexMut, Rem, Sub, SubAssign},
16};
17
18use num::{zero, ToPrimitive};
19
20macro_rules! impl_from_wrapnum {
21 ($($t:ty),*) => {
22 $(
23 impl From<WrapNum<$t>> for $t {
24 fn from(wrap_num: WrapNum<$t>) -> Self {
25 wrap_num.value
26 }
27 }
28 )*
29 };
30}
31
32#[derive(Clone, Copy, Debug)]
33pub struct WrapNum<T> {
35 pub value: T,
37 pub min: T,
39 pub max: T,
41}
42
43impl<T> Display for WrapNum<T>
44where
45 T: std::fmt::Display,
46{
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(f, "{}", self.value)
49 }
50}
51
52impl<T> PartialEq for WrapNum<T>
53where
54 T: Copy + PartialEq,
55{
56 fn eq(&self, other: &Self) -> bool {
57 self.value == other.value
58 }
59}
60
61impl<T> PartialEq<T> for WrapNum<T>
62where
63 T: Copy + PartialEq,
64{
65 fn eq(&self, other: &T) -> bool {
66 self.value == *other
67 }
68}
69
70impl<T, U> Index<WrapNum<U>> for Vec<T>
71where
72 U: ToPrimitive + Copy,
73{
74 type Output = T;
75
76 fn index(&self, index: WrapNum<U>) -> &Self::Output {
77 let idx = index
78 .value
79 .to_usize()
80 .expect("Failed to convert index to usize");
81 &self[idx]
82 }
83}
84
85impl<T, U> IndexMut<WrapNum<U>> for Vec<T>
86where
87 U: ToPrimitive + Copy,
88{
89 fn index_mut(&mut self, index: WrapNum<U>) -> &mut Self::Output {
90 &mut self[index
91 .value
92 .to_usize()
93 .expect("Failed to convert index to usize")]
94 }
95}
96
97impl<T> WrapNum<T>
98where
99 T: Add<Output = T> + Sub<Output = T> + Ord + num::Bounded + Rem<Output = T> + Copy,
100{
101 fn wrapped_result(value: T, min: T, max: T) -> T {
102 let range = max - min;
103 (value - min) % range + min
104 }
105}
106
107impl<T> Add for WrapNum<T>
108where
109 T: Add<Output = T> + Sub<Output = T> + Ord + num::Bounded + Rem<Output = T> + Copy,
110{
111 type Output = Self;
112
113 fn add(self, rhs: Self) -> Self::Output {
114 let wrapped_value = Self::wrapped_result(self.value + rhs.value, self.min, self.max);
115
116 Self {
117 value: wrapped_value,
118 min: self.min,
119 max: self.max,
120 }
121 }
122}
123
124impl<T> Add<T> for WrapNum<T>
125where
126 T: Add<Output = T> + Sub<Output = T> + Ord + num::Bounded + Rem<Output = T> + Copy,
127{
128 type Output = Self;
129
130 fn add(self, rhs: T) -> Self::Output {
131 let wrapped_value = Self::wrapped_result(self.value + rhs, self.min, self.max);
132
133 Self {
134 value: wrapped_value,
135 min: self.min,
136 max: self.max,
137 }
138 }
139}
140
141impl<T> Sub for WrapNum<T>
142where
143 T: Sub<Output = T> + Add<Output = T> + Rem<Output = T> + Ord + num::Bounded + num::One + Copy,
144{
145 type Output = Self;
146
147 fn sub(self, rhs: Self) -> Self::Output {
148 let result = if self.value < rhs.value {
149 self.max - self.min + (self.value - rhs.value)
150 } else {
151 self.value - rhs.value
152 };
153
154 let wrapped_value = Self::wrapped_result(result, self.min, self.max);
155
156 Self {
157 value: wrapped_value,
158 min: self.min,
159 max: self.max,
160 }
161 }
162}
163
164impl<T> Sub<T> for WrapNum<T>
165where
166 T: Sub<Output = T> + Add<Output = T> + Rem<Output = T> + Ord + num::Bounded + num::One + Copy,
167{
168 type Output = Self;
169
170 fn sub(self, rhs: T) -> Self::Output {
171 let result = if self.value < rhs {
172 self.max - self.min + (self.value - rhs)
173 } else {
174 self.value - rhs
175 };
176
177 let wrapped_value = Self::wrapped_result(result, self.min, self.max);
178
179 Self {
180 value: wrapped_value,
181 min: self.min,
182 max: self.max,
183 }
184 }
185}
186
187impl<T> AddAssign<T> for WrapNum<T>
188where
189 T: Add<Output = T> + Sub<Output = T> + Ord + num::Bounded + Rem<Output = T> + Copy,
190{
191 fn add_assign(&mut self, rhs: T) {
192 let result = self.value + rhs;
193
194 self.value = Self::wrapped_result(result, self.min, self.max);
195 }
196}
197
198impl<T> SubAssign<T> for WrapNum<T>
199where
200 T: Sub<Output = T> + Add<Output = T> + Rem<Output = T> + Ord + num::Bounded + num::One + Copy,
201{
202 fn sub_assign(&mut self, rhs: T) {
203 let result = if self.value < rhs {
204 self.max - self.min + (self.value - rhs)
205 } else {
206 self.value - rhs
207 };
208
209 self.value = Self::wrapped_result(result, self.min, self.max);
210 }
211}
212
213impl<T> From<T> for WrapNum<T>
214where
215 T: Copy + num::Bounded + num::Zero,
216{
217 fn from(value: T) -> Self {
218 Self {
219 value,
220 min: zero(),
221 max: T::max_value(),
222 }
223 }
224}
225
226impl_from_wrapnum!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
229
230impl<T> Default for WrapNum<T>
231where
232 T: num::Bounded + num::Zero,
233{
234 fn default() -> Self {
237 WrapNum {
238 value: zero(),
239 min: zero(),
240 max: T::max_value(),
241 }
242 }
243}
244
245impl<T> WrapNum<T>
246where
247 T: num::Bounded + num::Zero + PartialOrd,
248{
249 pub fn new(max: T) -> Self {
251 Self {
252 max,
253 ..Default::default()
254 }
255 }
256
257 pub fn new_max(value: T, max: T) -> Self {
262 assert!(!(value > max), "`value` is greater than `max`.");
263 Self {
264 value,
265 max,
266 ..Default::default()
267 }
268 }
269
270 pub fn new_min_max(value: T, min: T, max: T) -> Self {
275 if value > max {
276 panic!("`value` is greater than `max`.");
277 } else if value < min {
278 panic!("`value` is less than `min`.");
279 }
280 Self { value, min, max }
281 }
282}
283
284impl<T: PartialEq> WrapNum<T> {
285 pub fn total_eq(self, other: &Self) -> bool {
286 self.value == other.value && self.min == other.min && self.max == other.max
287 }
288}
289
290#[macro_export]
291macro_rules! wrap {
302 ($max:expr) => {
303 $crate::WrapNum::new($max)
304 };
305 (=$max:expr) => {
306 $crate::WrapNum::new($max + 1)
307 };
308 ($v:expr, $max:expr) => {
309 $crate::WrapNum::new_max($v, $max)
310 };
311 (($min:expr)..($max:expr)) => {
312 $crate::WrapNum::new_min_max($min, $min, $max)
313 };
314 (($min:expr)..=($max:expr)) => {
315 $crate::WrapNum::new_min_max($min, $min, $max + 1)
316 };
317 ($v:expr, $min:expr, $max:expr) => {
318 $crate::WrapNum::new_min_max($v, $min, $max)
319 };
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn make_usize() {
328 let mut result = wrap!(50);
329 for _ in 0..60 {
330 result += 1;
331 println!("{}", result);
332 }
333 }
334
335 #[test]
336 fn months() {
337 let mut months = wrap!(11);
338 for _ in 0..11 {
339 months += 1;
340 }
341 assert_eq!(months.value, 0);
342 }
343
344 #[test]
345 fn custom_min() {
346 let mut mins = wrap!(5, 5, 7);
347 mins += 3;
348 assert_eq!(mins.value, 6);
352 }
353
354 #[test]
355 fn can_convert() {
356 let mut mins = wrap!(=5);
357 mins += 5 as u16;
358 }
359
360 #[test]
361 fn has_indexing() {
362 let here = wrap!(5);
363 let oh = vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
364 assert_eq!(oh[here], 10);
365 }
366
367 #[test]
368 fn are_equals() {
369 let mut here = wrap!(6);
370 here += 5;
371 println!("{}", here);
372 let there = wrap!(50);
373 assert_eq!(here, there + 5);
374 }
375
376 #[test]
377 fn into_integer() {
378 let here = wrap!(420, 0, 69420);
379 let hmm: WrapNum<u32> = 420.into();
380 let as_u32 = u32::from(here);
381 }
382}