Skip to main content

platform_num/
imp.rs

1use std::fmt::{Debug, Display};
2use std::hash::Hash;
3
4use num_traits::{AsPrimitive, FromPrimitive, PrimInt, Signed, ToPrimitive, Unsigned};
5
6pub trait Num: PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive {}
7
8impl<All: PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive> Num for All {}
9
10pub trait SignNum: Num + Signed + FromPrimitive {}
11
12impl<All: Num + Signed + FromPrimitive> SignNum for All {}
13
14pub trait ToSigned {
15    type Type: Num + Signed;
16
17    fn to_signed(&self) -> Self::Type;
18}
19
20macro_rules! signed_type_impl {
21    ($U:ty, $S:ty) => {
22        impl ToSigned for $U {
23            type Type = $S;
24
25            fn to_signed(&self) -> Self::Type {
26                *self as Self::Type
27            }
28        }
29    };
30}
31
32signed_type_impl!(i8, i8);
33signed_type_impl!(u8, i8);
34signed_type_impl!(i16, i16);
35signed_type_impl!(u16, i16);
36signed_type_impl!(i32, i32);
37signed_type_impl!(u32, i32);
38signed_type_impl!(i64, i64);
39signed_type_impl!(u64, i64);
40signed_type_impl!(i128, i128);
41signed_type_impl!(u128, i128);
42signed_type_impl!(isize, isize);
43signed_type_impl!(usize, isize);
44
45pub trait MaxValue {
46    const MAX: Self;
47}
48
49macro_rules! max_value_impl {
50    ($T:ty) => {
51        impl MaxValue for $T {
52            const MAX: Self = <$T>::MAX;
53        }
54    };
55}
56
57// TODO: Create macro foreach
58max_value_impl!(i8);
59max_value_impl!(u8);
60max_value_impl!(i16);
61max_value_impl!(u16);
62max_value_impl!(i32);
63max_value_impl!(u32);
64max_value_impl!(i64);
65max_value_impl!(u64);
66max_value_impl!(i128);
67max_value_impl!(u128);
68max_value_impl!(isize);
69max_value_impl!(usize);
70
71// TODO: Not use alias - IDEs does not support it
72#[rustfmt::skip]
73pub trait LinkType:
74Num
75+ Unsigned
76+ ToSigned
77+ MaxValue
78+ FromPrimitive
79+ Debug
80+ Display
81+ Hash
82+ Send
83+ Sync
84+ 'static {}
85
86#[rustfmt::skip]
87impl<
88    All: Num
89    + Unsigned
90    + ToSigned
91    + MaxValue
92    + FromPrimitive
93    + Debug
94    + Display
95    + Hash
96    + Send
97    + Sync
98    + 'static,
99> LinkType for All {}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    // ==========================================
106    // Tests for Num trait
107    // ==========================================
108
109    #[test]
110    fn test_num_trait_for_i8() {
111        fn assert_num<T: Num>(_val: T) {}
112        assert_num(0i8);
113    }
114
115    #[test]
116    fn test_num_trait_for_u8() {
117        fn assert_num<T: Num>(_val: T) {}
118        assert_num(0u8);
119    }
120
121    #[test]
122    fn test_num_trait_for_i16() {
123        fn assert_num<T: Num>(_val: T) {}
124        assert_num(0i16);
125    }
126
127    #[test]
128    fn test_num_trait_for_u16() {
129        fn assert_num<T: Num>(_val: T) {}
130        assert_num(0u16);
131    }
132
133    #[test]
134    fn test_num_trait_for_i32() {
135        fn assert_num<T: Num>(_val: T) {}
136        assert_num(0i32);
137    }
138
139    #[test]
140    fn test_num_trait_for_u32() {
141        fn assert_num<T: Num>(_val: T) {}
142        assert_num(0u32);
143    }
144
145    #[test]
146    fn test_num_trait_for_i64() {
147        fn assert_num<T: Num>(_val: T) {}
148        assert_num(0i64);
149    }
150
151    #[test]
152    fn test_num_trait_for_u64() {
153        fn assert_num<T: Num>(_val: T) {}
154        assert_num(0u64);
155    }
156
157    #[test]
158    fn test_num_trait_for_i128() {
159        fn assert_num<T: Num>(_val: T) {}
160        assert_num(0i128);
161    }
162
163    #[test]
164    fn test_num_trait_for_u128() {
165        fn assert_num<T: Num>(_val: T) {}
166        assert_num(0u128);
167    }
168
169    #[test]
170    fn test_num_trait_for_isize() {
171        fn assert_num<T: Num>(_val: T) {}
172        assert_num(0isize);
173    }
174
175    #[test]
176    fn test_num_trait_for_usize() {
177        fn assert_num<T: Num>(_val: T) {}
178        assert_num(0usize);
179    }
180
181    // ==========================================
182    // Tests for SignNum trait
183    // ==========================================
184
185    #[test]
186    fn test_sign_num_trait_for_i8() {
187        fn assert_sign_num<T: SignNum>(_val: T) {}
188        assert_sign_num(0i8);
189    }
190
191    #[test]
192    fn test_sign_num_trait_for_i16() {
193        fn assert_sign_num<T: SignNum>(_val: T) {}
194        assert_sign_num(0i16);
195    }
196
197    #[test]
198    fn test_sign_num_trait_for_i32() {
199        fn assert_sign_num<T: SignNum>(_val: T) {}
200        assert_sign_num(0i32);
201    }
202
203    #[test]
204    fn test_sign_num_trait_for_i64() {
205        fn assert_sign_num<T: SignNum>(_val: T) {}
206        assert_sign_num(0i64);
207    }
208
209    #[test]
210    fn test_sign_num_trait_for_i128() {
211        fn assert_sign_num<T: SignNum>(_val: T) {}
212        assert_sign_num(0i128);
213    }
214
215    #[test]
216    fn test_sign_num_trait_for_isize() {
217        fn assert_sign_num<T: SignNum>(_val: T) {}
218        assert_sign_num(0isize);
219    }
220
221    // ==========================================
222    // Tests for ToSigned trait
223    // ==========================================
224
225    #[test]
226    fn test_to_signed_i8() {
227        let val: i8 = 42;
228        let signed: i8 = val.to_signed();
229        assert_eq!(signed, 42i8);
230    }
231
232    #[test]
233    fn test_to_signed_u8() {
234        let val: u8 = 42;
235        let signed: i8 = val.to_signed();
236        assert_eq!(signed, 42i8);
237    }
238
239    #[test]
240    fn test_to_signed_i16() {
241        let val: i16 = 1000;
242        let signed: i16 = val.to_signed();
243        assert_eq!(signed, 1000i16);
244    }
245
246    #[test]
247    fn test_to_signed_u16() {
248        let val: u16 = 1000;
249        let signed: i16 = val.to_signed();
250        assert_eq!(signed, 1000i16);
251    }
252
253    #[test]
254    fn test_to_signed_i32() {
255        let val: i32 = 100000;
256        let signed: i32 = val.to_signed();
257        assert_eq!(signed, 100000i32);
258    }
259
260    #[test]
261    fn test_to_signed_u32() {
262        let val: u32 = 100000;
263        let signed: i32 = val.to_signed();
264        assert_eq!(signed, 100000i32);
265    }
266
267    #[test]
268    fn test_to_signed_i64() {
269        let val: i64 = 1000000000;
270        let signed: i64 = val.to_signed();
271        assert_eq!(signed, 1000000000i64);
272    }
273
274    #[test]
275    fn test_to_signed_u64() {
276        let val: u64 = 1000000000;
277        let signed: i64 = val.to_signed();
278        assert_eq!(signed, 1000000000i64);
279    }
280
281    #[test]
282    fn test_to_signed_i128() {
283        let val: i128 = 1000000000000000;
284        let signed: i128 = val.to_signed();
285        assert_eq!(signed, 1000000000000000i128);
286    }
287
288    #[test]
289    fn test_to_signed_u128() {
290        let val: u128 = 1000000000000000;
291        let signed: i128 = val.to_signed();
292        assert_eq!(signed, 1000000000000000i128);
293    }
294
295    #[test]
296    fn test_to_signed_isize() {
297        let val: isize = 12345;
298        let signed: isize = val.to_signed();
299        assert_eq!(signed, 12345isize);
300    }
301
302    #[test]
303    fn test_to_signed_usize() {
304        let val: usize = 12345;
305        let signed: isize = val.to_signed();
306        assert_eq!(signed, 12345isize);
307    }
308
309    #[test]
310    fn test_to_signed_type_alias_i8() {
311        fn check<T: ToSigned<Type = i8>>(_val: T) {}
312        check(0i8);
313        check(0u8);
314    }
315
316    #[test]
317    fn test_to_signed_type_alias_i16() {
318        fn check<T: ToSigned<Type = i16>>(_val: T) {}
319        check(0i16);
320        check(0u16);
321    }
322
323    #[test]
324    fn test_to_signed_type_alias_i32() {
325        fn check<T: ToSigned<Type = i32>>(_val: T) {}
326        check(0i32);
327        check(0u32);
328    }
329
330    #[test]
331    fn test_to_signed_type_alias_i64() {
332        fn check<T: ToSigned<Type = i64>>(_val: T) {}
333        check(0i64);
334        check(0u64);
335    }
336
337    #[test]
338    fn test_to_signed_type_alias_i128() {
339        fn check<T: ToSigned<Type = i128>>(_val: T) {}
340        check(0i128);
341        check(0u128);
342    }
343
344    #[test]
345    fn test_to_signed_type_alias_isize() {
346        fn check<T: ToSigned<Type = isize>>(_val: T) {}
347        check(0isize);
348        check(0usize);
349    }
350
351    // ==========================================
352    // Tests for MaxValue trait
353    // ==========================================
354
355    #[test]
356    fn test_max_value_i8() {
357        assert_eq!(i8::MAX, <i8 as MaxValue>::MAX);
358    }
359
360    #[test]
361    fn test_max_value_u8() {
362        assert_eq!(u8::MAX, <u8 as MaxValue>::MAX);
363    }
364
365    #[test]
366    fn test_max_value_i16() {
367        assert_eq!(i16::MAX, <i16 as MaxValue>::MAX);
368    }
369
370    #[test]
371    fn test_max_value_u16() {
372        assert_eq!(u16::MAX, <u16 as MaxValue>::MAX);
373    }
374
375    #[test]
376    fn test_max_value_i32() {
377        assert_eq!(i32::MAX, <i32 as MaxValue>::MAX);
378    }
379
380    #[test]
381    fn test_max_value_u32() {
382        assert_eq!(u32::MAX, <u32 as MaxValue>::MAX);
383    }
384
385    #[test]
386    fn test_max_value_i64() {
387        assert_eq!(i64::MAX, <i64 as MaxValue>::MAX);
388    }
389
390    #[test]
391    fn test_max_value_u64() {
392        assert_eq!(u64::MAX, <u64 as MaxValue>::MAX);
393    }
394
395    #[test]
396    fn test_max_value_i128() {
397        assert_eq!(i128::MAX, <i128 as MaxValue>::MAX);
398    }
399
400    #[test]
401    fn test_max_value_u128() {
402        assert_eq!(u128::MAX, <u128 as MaxValue>::MAX);
403    }
404
405    #[test]
406    fn test_max_value_isize() {
407        assert_eq!(isize::MAX, <isize as MaxValue>::MAX);
408    }
409
410    #[test]
411    fn test_max_value_usize() {
412        assert_eq!(usize::MAX, <usize as MaxValue>::MAX);
413    }
414
415    // ==========================================
416    // Tests for LinkType trait
417    // ==========================================
418
419    #[test]
420    fn test_link_type_for_u8() {
421        fn assert_link_type<T: LinkType>(_val: T) {}
422        assert_link_type(0u8);
423    }
424
425    #[test]
426    fn test_link_type_for_u16() {
427        fn assert_link_type<T: LinkType>(_val: T) {}
428        assert_link_type(0u16);
429    }
430
431    #[test]
432    fn test_link_type_for_u32() {
433        fn assert_link_type<T: LinkType>(_val: T) {}
434        assert_link_type(0u32);
435    }
436
437    #[test]
438    fn test_link_type_for_u64() {
439        fn assert_link_type<T: LinkType>(_val: T) {}
440        assert_link_type(0u64);
441    }
442
443    #[test]
444    fn test_link_type_for_usize() {
445        fn assert_link_type<T: LinkType>(_val: T) {}
446        assert_link_type(0usize);
447    }
448
449    // ==========================================
450    // Edge case tests for ToSigned
451    // ==========================================
452
453    #[test]
454    fn test_to_signed_u8_max() {
455        let val: u8 = u8::MAX;
456        let signed: i8 = val.to_signed();
457        assert_eq!(signed, -1i8); // Wrapping behavior
458    }
459
460    #[test]
461    fn test_to_signed_u16_max() {
462        let val: u16 = u16::MAX;
463        let signed: i16 = val.to_signed();
464        assert_eq!(signed, -1i16); // Wrapping behavior
465    }
466
467    #[test]
468    fn test_to_signed_u32_max() {
469        let val: u32 = u32::MAX;
470        let signed: i32 = val.to_signed();
471        assert_eq!(signed, -1i32); // Wrapping behavior
472    }
473
474    #[test]
475    fn test_to_signed_u64_max() {
476        let val: u64 = u64::MAX;
477        let signed: i64 = val.to_signed();
478        assert_eq!(signed, -1i64); // Wrapping behavior
479    }
480
481    #[test]
482    fn test_to_signed_u128_max() {
483        let val: u128 = u128::MAX;
484        let signed: i128 = val.to_signed();
485        assert_eq!(signed, -1i128); // Wrapping behavior
486    }
487
488    #[test]
489    fn test_to_signed_usize_max() {
490        let val: usize = usize::MAX;
491        let signed: isize = val.to_signed();
492        assert_eq!(signed, -1isize); // Wrapping behavior
493    }
494
495    #[test]
496    fn test_to_signed_zero() {
497        assert_eq!(0u8.to_signed(), 0i8);
498        assert_eq!(0u16.to_signed(), 0i16);
499        assert_eq!(0u32.to_signed(), 0i32);
500        assert_eq!(0u64.to_signed(), 0i64);
501        assert_eq!(0u128.to_signed(), 0i128);
502        assert_eq!(0usize.to_signed(), 0isize);
503    }
504
505    #[test]
506    fn test_to_signed_negative() {
507        assert_eq!((-1i8).to_signed(), -1i8);
508        assert_eq!((-1i16).to_signed(), -1i16);
509        assert_eq!((-1i32).to_signed(), -1i32);
510        assert_eq!((-1i64).to_signed(), -1i64);
511        assert_eq!((-1i128).to_signed(), -1i128);
512        assert_eq!((-1isize).to_signed(), -1isize);
513    }
514
515    // ==========================================
516    // Integration tests - using traits together
517    // ==========================================
518
519    #[test]
520    fn test_link_type_can_be_converted_to_signed() {
521        fn use_link_type<T: LinkType + ToSigned>(val: T) -> <T as ToSigned>::Type {
522            val.to_signed()
523        }
524        assert_eq!(use_link_type(42u8), 42i8);
525        assert_eq!(use_link_type(42u16), 42i16);
526        assert_eq!(use_link_type(42u32), 42i32);
527        assert_eq!(use_link_type(42u64), 42i64);
528        assert_eq!(use_link_type(42usize), 42isize);
529    }
530
531    #[test]
532    fn test_link_type_has_max_value() {
533        fn get_max<T: LinkType + MaxValue>() -> T {
534            T::MAX
535        }
536        assert_eq!(get_max::<u8>(), u8::MAX);
537        assert_eq!(get_max::<u16>(), u16::MAX);
538        assert_eq!(get_max::<u32>(), u32::MAX);
539        assert_eq!(get_max::<u64>(), u64::MAX);
540        assert_eq!(get_max::<usize>(), usize::MAX);
541    }
542
543    #[test]
544    fn test_num_default_values() {
545        fn check_default<T: Num>() -> T {
546            T::default()
547        }
548        assert_eq!(check_default::<i8>(), 0i8);
549        assert_eq!(check_default::<u8>(), 0u8);
550        assert_eq!(check_default::<i16>(), 0i16);
551        assert_eq!(check_default::<u16>(), 0u16);
552        assert_eq!(check_default::<i32>(), 0i32);
553        assert_eq!(check_default::<u32>(), 0u32);
554        assert_eq!(check_default::<i64>(), 0i64);
555        assert_eq!(check_default::<u64>(), 0u64);
556        assert_eq!(check_default::<i128>(), 0i128);
557        assert_eq!(check_default::<u128>(), 0u128);
558        assert_eq!(check_default::<isize>(), 0isize);
559        assert_eq!(check_default::<usize>(), 0usize);
560    }
561
562    #[test]
563    fn test_num_as_usize() {
564        fn to_usize<T: Num>(val: T) -> usize {
565            val.as_()
566        }
567        assert_eq!(to_usize(42i8), 42usize);
568        assert_eq!(to_usize(42u8), 42usize);
569        assert_eq!(to_usize(42i16), 42usize);
570        assert_eq!(to_usize(42u16), 42usize);
571        assert_eq!(to_usize(42i32), 42usize);
572        assert_eq!(to_usize(42u32), 42usize);
573    }
574
575    #[test]
576    fn test_sign_num_signum() {
577        fn get_signum<T: SignNum>(val: T) -> T {
578            val.signum()
579        }
580        assert_eq!(get_signum(5i8), 1i8);
581        assert_eq!(get_signum(-5i8), -1i8);
582        assert_eq!(get_signum(0i8), 0i8);
583        assert_eq!(get_signum(5i32), 1i32);
584        assert_eq!(get_signum(-5i32), -1i32);
585        assert_eq!(get_signum(0i32), 0i32);
586    }
587
588    #[test]
589    fn test_sign_num_abs() {
590        fn get_abs<T: SignNum>(val: T) -> T {
591            val.abs()
592        }
593        assert_eq!(get_abs(-5i8), 5i8);
594        assert_eq!(get_abs(5i8), 5i8);
595        assert_eq!(get_abs(-100i32), 100i32);
596        assert_eq!(get_abs(100i32), 100i32);
597    }
598}