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
109/// Applies a macro to each primitive integer type.
110///
111/// This helper macro invokes `$macro!(type)` for every primitive integer type:
112/// `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`,
113/// `isize`, `usize`.
114macro_rules! for_each_integer_type {
115 ($macro:ident) => {
116 $macro!(i8);
117 $macro!(u8);
118 $macro!(i16);
119 $macro!(u16);
120 $macro!(i32);
121 $macro!(u32);
122 $macro!(i64);
123 $macro!(u64);
124 $macro!(i128);
125 $macro!(u128);
126 $macro!(isize);
127 $macro!(usize);
128 };
129}
130
131macro_rules! max_value_impl {
132 ($T:ty) => {
133 impl MaxValue for $T {
134 const MAX: Self = <$T>::MAX;
135 }
136 };
137}
138
139for_each_integer_type!(max_value_impl);
140
141/// A composite trait for types that can be used as link identifiers.
142///
143/// Combines [`Number`], `Unsigned`, [`ToSigned`], [`MaxValue`],
144/// `FromPrimitive`, `Debug`, `Display`, `Hash`, `Send`, `Sync`,
145/// and `'static`.
146///
147/// Implemented for `u8`, `u16`, `u32`, `u64`, and `usize`.
148///
149/// # Design note
150///
151/// Supertraits are listed explicitly rather than via type aliases,
152/// because some IDEs do not fully resolve trait aliases for
153/// autocompletion and go-to-definition.
154///
155/// # Examples
156///
157/// ```
158/// use platform_num::LinkReference;
159///
160/// fn create_link<T: LinkReference>(source: T, target: T) -> (T, T) {
161/// (source, target)
162/// }
163///
164/// let link = create_link(1u64, 2u64);
165/// assert_eq!(link, (1u64, 2u64));
166/// ```
167#[rustfmt::skip]
168pub trait LinkReference:
169Number
170+ Unsigned
171+ ToSigned
172+ MaxValue
173+ FromPrimitive
174+ Debug
175+ Display
176+ Hash
177+ Send
178+ Sync
179+ 'static {}
180
181#[rustfmt::skip]
182impl<
183 All: Number
184 + Unsigned
185 + ToSigned
186 + MaxValue
187 + FromPrimitive
188 + Debug
189 + Display
190 + Hash
191 + Send
192 + Sync
193 + 'static,
194> LinkReference for All {}