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
6/// A base numeric trait combining `PrimInt`, `Default`, `Debug`,
7/// `AsPrimitive<usize>`, and `ToPrimitive`.
8///
9/// Implemented for all primitive integer types.
10///
11/// # Examples
12///
13/// ```
14/// use platform_num::Number;
15/// use num_traits::AsPrimitive;
16///
17/// fn to_usize<T: Number>(val: T) -> usize {
18///     val.as_()
19/// }
20///
21/// assert_eq!(to_usize(42u32), 42usize);
22/// ```
23pub trait Number: PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive {}
24
25impl<All: PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive> Number for All {}
26
27/// A signed numeric trait extending [`Number`] with signed operations.
28///
29/// Implemented for all signed primitive integer types.
30///
31/// # Examples
32///
33/// ```
34/// use platform_num::SignedNumber;
35///
36/// fn get_abs<T: SignedNumber>(val: T) -> T {
37///     val.abs()
38/// }
39///
40/// assert_eq!(get_abs(-5i32), 5i32);
41/// ```
42pub trait SignedNumber: Number + Signed + FromPrimitive {}
43
44impl<All: Number + Signed + FromPrimitive> SignedNumber for All {}
45
46/// Converts a numeric type to its signed counterpart.
47///
48/// Maps each unsigned type to the corresponding signed type
49/// (e.g. `u32` → `i32`). Signed types map to themselves.
50///
51/// # Examples
52///
53/// ```
54/// use platform_num::ToSigned;
55///
56/// let unsigned_val: u32 = 42;
57/// let signed_val: i32 = unsigned_val.to_signed();
58/// assert_eq!(signed_val, 42i32);
59/// ```
60pub trait ToSigned {
61    /// The signed type that corresponds to `Self`.
62    type Type: Number + Signed;
63
64    /// Converts `self` to the corresponding signed type via `as` cast.
65    fn to_signed(&self) -> Self::Type;
66}
67
68macro_rules! signed_type_impl {
69    ($U:ty, $S:ty) => {
70        impl ToSigned for $U {
71            type Type = $S;
72
73            fn to_signed(&self) -> Self::Type {
74                *self as Self::Type
75            }
76        }
77    };
78}
79
80signed_type_impl!(i8, i8);
81signed_type_impl!(u8, i8);
82signed_type_impl!(i16, i16);
83signed_type_impl!(u16, i16);
84signed_type_impl!(i32, i32);
85signed_type_impl!(u32, i32);
86signed_type_impl!(i64, i64);
87signed_type_impl!(u64, i64);
88signed_type_impl!(i128, i128);
89signed_type_impl!(u128, i128);
90signed_type_impl!(isize, isize);
91signed_type_impl!(usize, isize);
92
93/// Provides the maximum value for a numeric type as an associated constant.
94///
95/// Implemented for all primitive integer types.
96///
97/// # Examples
98///
99/// ```
100/// use platform_num::MaxValue;
101///
102/// assert_eq!(<u64 as MaxValue>::MAX, u64::MAX);
103/// ```
104pub trait MaxValue {
105    /// The maximum value of this type.
106    const MAX: Self;
107}
108
109macro_rules! max_value_impl {
110    ($T:ty) => {
111        impl MaxValue for $T {
112            const MAX: Self = <$T>::MAX;
113        }
114    };
115}
116
117// TODO: Create macro foreach
118max_value_impl!(i8);
119max_value_impl!(u8);
120max_value_impl!(i16);
121max_value_impl!(u16);
122max_value_impl!(i32);
123max_value_impl!(u32);
124max_value_impl!(i64);
125max_value_impl!(u64);
126max_value_impl!(i128);
127max_value_impl!(u128);
128max_value_impl!(isize);
129max_value_impl!(usize);
130
131/// A composite trait for types that can be used as link identifiers.
132///
133/// Combines [`Number`], `Unsigned`, [`ToSigned`], [`MaxValue`],
134/// `FromPrimitive`, `Debug`, `Display`, `Hash`, `Send`, `Sync`,
135/// and `'static`.
136///
137/// Implemented for `u8`, `u16`, `u32`, `u64`, and `usize`.
138///
139/// # Examples
140///
141/// ```
142/// use platform_num::LinkReference;
143///
144/// fn create_link<T: LinkReference>(source: T, target: T) -> (T, T) {
145///     (source, target)
146/// }
147///
148/// let link = create_link(1u64, 2u64);
149/// assert_eq!(link, (1u64, 2u64));
150/// ```
151// TODO: Not use alias - IDEs does not support it
152#[rustfmt::skip]
153pub trait LinkReference:
154Number
155+ Unsigned
156+ ToSigned
157+ MaxValue
158+ FromPrimitive
159+ Debug
160+ Display
161+ Hash
162+ Send
163+ Sync
164+ 'static {}
165
166#[rustfmt::skip]
167impl<
168    All: Number
169    + Unsigned
170    + ToSigned
171    + MaxValue
172    + FromPrimitive
173    + Debug
174    + Display
175    + Hash
176    + Send
177    + Sync
178    + 'static,
179> LinkReference for All {}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    // ==========================================
186    // Tests for Number trait
187    // ==========================================
188
189    #[test]
190    fn test_number_trait_for_i8() {
191        fn assert_number<T: Number>(_val: T) {}
192        assert_number(0i8);
193    }
194
195    #[test]
196    fn test_number_trait_for_u8() {
197        fn assert_number<T: Number>(_val: T) {}
198        assert_number(0u8);
199    }
200
201    #[test]
202    fn test_number_trait_for_i16() {
203        fn assert_number<T: Number>(_val: T) {}
204        assert_number(0i16);
205    }
206
207    #[test]
208    fn test_number_trait_for_u16() {
209        fn assert_number<T: Number>(_val: T) {}
210        assert_number(0u16);
211    }
212
213    #[test]
214    fn test_number_trait_for_i32() {
215        fn assert_number<T: Number>(_val: T) {}
216        assert_number(0i32);
217    }
218
219    #[test]
220    fn test_number_trait_for_u32() {
221        fn assert_number<T: Number>(_val: T) {}
222        assert_number(0u32);
223    }
224
225    #[test]
226    fn test_number_trait_for_i64() {
227        fn assert_number<T: Number>(_val: T) {}
228        assert_number(0i64);
229    }
230
231    #[test]
232    fn test_number_trait_for_u64() {
233        fn assert_number<T: Number>(_val: T) {}
234        assert_number(0u64);
235    }
236
237    #[test]
238    fn test_number_trait_for_i128() {
239        fn assert_number<T: Number>(_val: T) {}
240        assert_number(0i128);
241    }
242
243    #[test]
244    fn test_number_trait_for_u128() {
245        fn assert_number<T: Number>(_val: T) {}
246        assert_number(0u128);
247    }
248
249    #[test]
250    fn test_number_trait_for_isize() {
251        fn assert_number<T: Number>(_val: T) {}
252        assert_number(0isize);
253    }
254
255    #[test]
256    fn test_number_trait_for_usize() {
257        fn assert_number<T: Number>(_val: T) {}
258        assert_number(0usize);
259    }
260
261    // ==========================================
262    // Tests for SignedNumber trait
263    // ==========================================
264
265    #[test]
266    fn test_signed_number_trait_for_i8() {
267        fn assert_signed_number<T: SignedNumber>(_val: T) {}
268        assert_signed_number(0i8);
269    }
270
271    #[test]
272    fn test_signed_number_trait_for_i16() {
273        fn assert_signed_number<T: SignedNumber>(_val: T) {}
274        assert_signed_number(0i16);
275    }
276
277    #[test]
278    fn test_signed_number_trait_for_i32() {
279        fn assert_signed_number<T: SignedNumber>(_val: T) {}
280        assert_signed_number(0i32);
281    }
282
283    #[test]
284    fn test_signed_number_trait_for_i64() {
285        fn assert_signed_number<T: SignedNumber>(_val: T) {}
286        assert_signed_number(0i64);
287    }
288
289    #[test]
290    fn test_signed_number_trait_for_i128() {
291        fn assert_signed_number<T: SignedNumber>(_val: T) {}
292        assert_signed_number(0i128);
293    }
294
295    #[test]
296    fn test_signed_number_trait_for_isize() {
297        fn assert_signed_number<T: SignedNumber>(_val: T) {}
298        assert_signed_number(0isize);
299    }
300
301    // ==========================================
302    // Tests for ToSigned trait
303    // ==========================================
304
305    #[test]
306    fn test_to_signed_i8() {
307        let val: i8 = 42;
308        let signed: i8 = val.to_signed();
309        assert_eq!(signed, 42i8);
310    }
311
312    #[test]
313    fn test_to_signed_u8() {
314        let val: u8 = 42;
315        let signed: i8 = val.to_signed();
316        assert_eq!(signed, 42i8);
317    }
318
319    #[test]
320    fn test_to_signed_i16() {
321        let val: i16 = 1000;
322        let signed: i16 = val.to_signed();
323        assert_eq!(signed, 1000i16);
324    }
325
326    #[test]
327    fn test_to_signed_u16() {
328        let val: u16 = 1000;
329        let signed: i16 = val.to_signed();
330        assert_eq!(signed, 1000i16);
331    }
332
333    #[test]
334    fn test_to_signed_i32() {
335        let val: i32 = 100000;
336        let signed: i32 = val.to_signed();
337        assert_eq!(signed, 100000i32);
338    }
339
340    #[test]
341    fn test_to_signed_u32() {
342        let val: u32 = 100000;
343        let signed: i32 = val.to_signed();
344        assert_eq!(signed, 100000i32);
345    }
346
347    #[test]
348    fn test_to_signed_i64() {
349        let val: i64 = 1000000000;
350        let signed: i64 = val.to_signed();
351        assert_eq!(signed, 1000000000i64);
352    }
353
354    #[test]
355    fn test_to_signed_u64() {
356        let val: u64 = 1000000000;
357        let signed: i64 = val.to_signed();
358        assert_eq!(signed, 1000000000i64);
359    }
360
361    #[test]
362    fn test_to_signed_i128() {
363        let val: i128 = 1000000000000000;
364        let signed: i128 = val.to_signed();
365        assert_eq!(signed, 1000000000000000i128);
366    }
367
368    #[test]
369    fn test_to_signed_u128() {
370        let val: u128 = 1000000000000000;
371        let signed: i128 = val.to_signed();
372        assert_eq!(signed, 1000000000000000i128);
373    }
374
375    #[test]
376    fn test_to_signed_isize() {
377        let val: isize = 12345;
378        let signed: isize = val.to_signed();
379        assert_eq!(signed, 12345isize);
380    }
381
382    #[test]
383    fn test_to_signed_usize() {
384        let val: usize = 12345;
385        let signed: isize = val.to_signed();
386        assert_eq!(signed, 12345isize);
387    }
388
389    #[test]
390    fn test_to_signed_type_alias_i8() {
391        fn check<T: ToSigned<Type = i8>>(_val: T) {}
392        check(0i8);
393        check(0u8);
394    }
395
396    #[test]
397    fn test_to_signed_type_alias_i16() {
398        fn check<T: ToSigned<Type = i16>>(_val: T) {}
399        check(0i16);
400        check(0u16);
401    }
402
403    #[test]
404    fn test_to_signed_type_alias_i32() {
405        fn check<T: ToSigned<Type = i32>>(_val: T) {}
406        check(0i32);
407        check(0u32);
408    }
409
410    #[test]
411    fn test_to_signed_type_alias_i64() {
412        fn check<T: ToSigned<Type = i64>>(_val: T) {}
413        check(0i64);
414        check(0u64);
415    }
416
417    #[test]
418    fn test_to_signed_type_alias_i128() {
419        fn check<T: ToSigned<Type = i128>>(_val: T) {}
420        check(0i128);
421        check(0u128);
422    }
423
424    #[test]
425    fn test_to_signed_type_alias_isize() {
426        fn check<T: ToSigned<Type = isize>>(_val: T) {}
427        check(0isize);
428        check(0usize);
429    }
430
431    // ==========================================
432    // Tests for MaxValue trait
433    // ==========================================
434
435    #[test]
436    fn test_max_value_i8() {
437        assert_eq!(i8::MAX, <i8 as MaxValue>::MAX);
438    }
439
440    #[test]
441    fn test_max_value_u8() {
442        assert_eq!(u8::MAX, <u8 as MaxValue>::MAX);
443    }
444
445    #[test]
446    fn test_max_value_i16() {
447        assert_eq!(i16::MAX, <i16 as MaxValue>::MAX);
448    }
449
450    #[test]
451    fn test_max_value_u16() {
452        assert_eq!(u16::MAX, <u16 as MaxValue>::MAX);
453    }
454
455    #[test]
456    fn test_max_value_i32() {
457        assert_eq!(i32::MAX, <i32 as MaxValue>::MAX);
458    }
459
460    #[test]
461    fn test_max_value_u32() {
462        assert_eq!(u32::MAX, <u32 as MaxValue>::MAX);
463    }
464
465    #[test]
466    fn test_max_value_i64() {
467        assert_eq!(i64::MAX, <i64 as MaxValue>::MAX);
468    }
469
470    #[test]
471    fn test_max_value_u64() {
472        assert_eq!(u64::MAX, <u64 as MaxValue>::MAX);
473    }
474
475    #[test]
476    fn test_max_value_i128() {
477        assert_eq!(i128::MAX, <i128 as MaxValue>::MAX);
478    }
479
480    #[test]
481    fn test_max_value_u128() {
482        assert_eq!(u128::MAX, <u128 as MaxValue>::MAX);
483    }
484
485    #[test]
486    fn test_max_value_isize() {
487        assert_eq!(isize::MAX, <isize as MaxValue>::MAX);
488    }
489
490    #[test]
491    fn test_max_value_usize() {
492        assert_eq!(usize::MAX, <usize as MaxValue>::MAX);
493    }
494
495    // ==========================================
496    // Tests for LinkReference trait
497    // ==========================================
498
499    #[test]
500    fn test_link_reference_for_u8() {
501        fn assert_link_reference<T: LinkReference>(_val: T) {}
502        assert_link_reference(0u8);
503    }
504
505    #[test]
506    fn test_link_reference_for_u16() {
507        fn assert_link_reference<T: LinkReference>(_val: T) {}
508        assert_link_reference(0u16);
509    }
510
511    #[test]
512    fn test_link_reference_for_u32() {
513        fn assert_link_reference<T: LinkReference>(_val: T) {}
514        assert_link_reference(0u32);
515    }
516
517    #[test]
518    fn test_link_reference_for_u64() {
519        fn assert_link_reference<T: LinkReference>(_val: T) {}
520        assert_link_reference(0u64);
521    }
522
523    #[test]
524    fn test_link_reference_for_usize() {
525        fn assert_link_reference<T: LinkReference>(_val: T) {}
526        assert_link_reference(0usize);
527    }
528
529    // ==========================================
530    // Edge case tests for ToSigned
531    // ==========================================
532
533    #[test]
534    fn test_to_signed_u8_max() {
535        let val: u8 = u8::MAX;
536        let signed: i8 = val.to_signed();
537        assert_eq!(signed, -1i8); // Wrapping behavior
538    }
539
540    #[test]
541    fn test_to_signed_u16_max() {
542        let val: u16 = u16::MAX;
543        let signed: i16 = val.to_signed();
544        assert_eq!(signed, -1i16); // Wrapping behavior
545    }
546
547    #[test]
548    fn test_to_signed_u32_max() {
549        let val: u32 = u32::MAX;
550        let signed: i32 = val.to_signed();
551        assert_eq!(signed, -1i32); // Wrapping behavior
552    }
553
554    #[test]
555    fn test_to_signed_u64_max() {
556        let val: u64 = u64::MAX;
557        let signed: i64 = val.to_signed();
558        assert_eq!(signed, -1i64); // Wrapping behavior
559    }
560
561    #[test]
562    fn test_to_signed_u128_max() {
563        let val: u128 = u128::MAX;
564        let signed: i128 = val.to_signed();
565        assert_eq!(signed, -1i128); // Wrapping behavior
566    }
567
568    #[test]
569    fn test_to_signed_usize_max() {
570        let val: usize = usize::MAX;
571        let signed: isize = val.to_signed();
572        assert_eq!(signed, -1isize); // Wrapping behavior
573    }
574
575    #[test]
576    fn test_to_signed_zero() {
577        assert_eq!(0u8.to_signed(), 0i8);
578        assert_eq!(0u16.to_signed(), 0i16);
579        assert_eq!(0u32.to_signed(), 0i32);
580        assert_eq!(0u64.to_signed(), 0i64);
581        assert_eq!(0u128.to_signed(), 0i128);
582        assert_eq!(0usize.to_signed(), 0isize);
583    }
584
585    #[test]
586    fn test_to_signed_negative() {
587        assert_eq!((-1i8).to_signed(), -1i8);
588        assert_eq!((-1i16).to_signed(), -1i16);
589        assert_eq!((-1i32).to_signed(), -1i32);
590        assert_eq!((-1i64).to_signed(), -1i64);
591        assert_eq!((-1i128).to_signed(), -1i128);
592        assert_eq!((-1isize).to_signed(), -1isize);
593    }
594
595    // ==========================================
596    // Integration tests - using traits together
597    // ==========================================
598
599    #[test]
600    fn test_link_reference_can_be_converted_to_signed() {
601        fn use_link_reference<T: LinkReference + ToSigned>(val: T) -> <T as ToSigned>::Type {
602            val.to_signed()
603        }
604        assert_eq!(use_link_reference(42u8), 42i8);
605        assert_eq!(use_link_reference(42u16), 42i16);
606        assert_eq!(use_link_reference(42u32), 42i32);
607        assert_eq!(use_link_reference(42u64), 42i64);
608        assert_eq!(use_link_reference(42usize), 42isize);
609    }
610
611    #[test]
612    fn test_link_reference_has_max_value() {
613        fn get_max<T: LinkReference + MaxValue>() -> T {
614            T::MAX
615        }
616        assert_eq!(get_max::<u8>(), u8::MAX);
617        assert_eq!(get_max::<u16>(), u16::MAX);
618        assert_eq!(get_max::<u32>(), u32::MAX);
619        assert_eq!(get_max::<u64>(), u64::MAX);
620        assert_eq!(get_max::<usize>(), usize::MAX);
621    }
622
623    #[test]
624    fn test_number_default_values() {
625        fn check_default<T: Number>() -> T {
626            T::default()
627        }
628        assert_eq!(check_default::<i8>(), 0i8);
629        assert_eq!(check_default::<u8>(), 0u8);
630        assert_eq!(check_default::<i16>(), 0i16);
631        assert_eq!(check_default::<u16>(), 0u16);
632        assert_eq!(check_default::<i32>(), 0i32);
633        assert_eq!(check_default::<u32>(), 0u32);
634        assert_eq!(check_default::<i64>(), 0i64);
635        assert_eq!(check_default::<u64>(), 0u64);
636        assert_eq!(check_default::<i128>(), 0i128);
637        assert_eq!(check_default::<u128>(), 0u128);
638        assert_eq!(check_default::<isize>(), 0isize);
639        assert_eq!(check_default::<usize>(), 0usize);
640    }
641
642    #[test]
643    fn test_number_as_usize() {
644        fn to_usize<T: Number>(val: T) -> usize {
645            val.as_()
646        }
647        assert_eq!(to_usize(42i8), 42usize);
648        assert_eq!(to_usize(42u8), 42usize);
649        assert_eq!(to_usize(42i16), 42usize);
650        assert_eq!(to_usize(42u16), 42usize);
651        assert_eq!(to_usize(42i32), 42usize);
652        assert_eq!(to_usize(42u32), 42usize);
653    }
654
655    #[test]
656    fn test_signed_number_signum() {
657        fn get_signum<T: SignedNumber>(val: T) -> T {
658            val.signum()
659        }
660        assert_eq!(get_signum(5i8), 1i8);
661        assert_eq!(get_signum(-5i8), -1i8);
662        assert_eq!(get_signum(0i8), 0i8);
663        assert_eq!(get_signum(5i32), 1i32);
664        assert_eq!(get_signum(-5i32), -1i32);
665        assert_eq!(get_signum(0i32), 0i32);
666    }
667
668    #[test]
669    fn test_signed_number_abs() {
670        fn get_abs<T: SignedNumber>(val: T) -> T {
671            val.abs()
672        }
673        assert_eq!(get_abs(-5i8), 5i8);
674        assert_eq!(get_abs(5i8), 5i8);
675        assert_eq!(get_abs(-100i32), 100i32);
676        assert_eq!(get_abs(100i32), 100i32);
677    }
678}