Skip to main content

platform_num/
imp.rs

1use std::fmt::{Debug, Display};
2use std::hash::Hash;
3
4use num_traits::ops::wrapping::{
5    WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
6};
7use num_traits::{AsPrimitive, FromPrimitive, PrimInt, Signed, ToPrimitive, Unsigned};
8
9/// A base numeric trait combining `PrimInt`, `Default`, `Debug`,
10/// `AsPrimitive<usize>`, and `ToPrimitive`.
11///
12/// Implemented for all primitive integer types.
13///
14/// # Examples
15///
16/// ```
17/// use platform_num::Number;
18/// use num_traits::AsPrimitive;
19///
20/// fn to_usize<T: Number>(val: T) -> usize {
21///     val.as_()
22/// }
23///
24/// assert_eq!(to_usize(42u32), 42usize);
25/// ```
26pub trait Number: PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive {}
27
28impl<All: PrimInt + Default + Debug + AsPrimitive<usize> + ToPrimitive> Number for All {}
29
30/// A signed numeric trait extending [`Number`] with signed operations.
31///
32/// Implemented for all signed primitive integer types.
33///
34/// # Examples
35///
36/// ```
37/// use platform_num::SignedNumber;
38///
39/// fn get_abs<T: SignedNumber>(val: T) -> T {
40///     val.abs()
41/// }
42///
43/// assert_eq!(get_abs(-5i32), 5i32);
44/// ```
45pub trait SignedNumber: Number + Signed + FromPrimitive {}
46
47impl<All: Number + Signed + FromPrimitive> SignedNumber for All {}
48
49/// Converts a numeric type to its signed counterpart.
50///
51/// Maps each unsigned type to the corresponding signed type
52/// (e.g. `u32` → `i32`). Signed types map to themselves.
53///
54/// # Examples
55///
56/// ```
57/// use platform_num::ToSigned;
58///
59/// let unsigned_val: u32 = 42;
60/// let signed_val: i32 = unsigned_val.to_signed();
61/// assert_eq!(signed_val, 42i32);
62/// ```
63pub trait ToSigned {
64    /// The signed type that corresponds to `Self`.
65    type Type: Number + Signed;
66
67    /// Converts `self` to the corresponding signed type via `as` cast.
68    fn to_signed(&self) -> Self::Type;
69}
70
71macro_rules! signed_type_impl {
72    ($U:ty, $S:ty) => {
73        impl ToSigned for $U {
74            type Type = $S;
75
76            fn to_signed(&self) -> Self::Type {
77                *self as Self::Type
78            }
79        }
80    };
81}
82
83signed_type_impl!(i8, i8);
84signed_type_impl!(u8, i8);
85signed_type_impl!(i16, i16);
86signed_type_impl!(u16, i16);
87signed_type_impl!(i32, i32);
88signed_type_impl!(u32, i32);
89signed_type_impl!(i64, i64);
90signed_type_impl!(u64, i64);
91signed_type_impl!(i128, i128);
92signed_type_impl!(u128, i128);
93signed_type_impl!(isize, isize);
94signed_type_impl!(usize, isize);
95
96/// Provides the maximum value for a numeric type as an associated constant.
97///
98/// Implemented for all primitive integer types.
99///
100/// # Examples
101///
102/// ```
103/// use platform_num::MaxValue;
104///
105/// assert_eq!(<u64 as MaxValue>::MAX, u64::MAX);
106/// ```
107pub trait MaxValue {
108    /// The maximum value of this type.
109    const MAX: Self;
110}
111
112/// Applies a macro to each primitive integer type.
113///
114/// This helper macro invokes `$macro!(type)` for every primitive integer type:
115/// `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`,
116/// `isize`, `usize`.
117macro_rules! for_each_integer_type {
118    ($macro:ident) => {
119        $macro!(i8);
120        $macro!(u8);
121        $macro!(i16);
122        $macro!(u16);
123        $macro!(i32);
124        $macro!(u32);
125        $macro!(i64);
126        $macro!(u64);
127        $macro!(i128);
128        $macro!(u128);
129        $macro!(isize);
130        $macro!(usize);
131    };
132}
133
134macro_rules! max_value_impl {
135    ($T:ty) => {
136        impl MaxValue for $T {
137            const MAX: Self = <$T>::MAX;
138        }
139    };
140}
141
142for_each_integer_type!(max_value_impl);
143
144/// A composite trait for wrapping arithmetic operations.
145///
146/// Combines all wrapping arithmetic traits from `num-traits`:
147/// [`WrappingAdd`], [`WrappingSub`], [`WrappingMul`],
148/// [`WrappingNeg`], [`WrappingShl`], and [`WrappingShr`].
149///
150/// Implemented for all primitive integer types.
151///
152/// # Examples
153///
154/// ```
155/// use platform_num::WrappingArithmetic;
156///
157/// fn wrapping_increment<T: WrappingArithmetic>(a: &T, b: &T) -> T {
158///     a.wrapping_add(b)
159/// }
160///
161/// assert_eq!(wrapping_increment(&u8::MAX, &1u8), 0u8);
162/// ```
163pub trait WrappingArithmetic:
164    WrappingAdd + WrappingSub + WrappingMul + WrappingNeg + WrappingShl + WrappingShr
165{
166}
167
168impl<All: WrappingAdd + WrappingSub + WrappingMul + WrappingNeg + WrappingShl + WrappingShr>
169    WrappingArithmetic for All
170{
171}
172
173/// A composite trait for types that can be used as link identifiers.
174///
175/// Combines [`Number`], `Unsigned`, [`ToSigned`], [`MaxValue`],
176/// [`WrappingArithmetic`], `FromPrimitive`,
177/// `TryFrom`/`TryInto` for all integer types,
178/// `Debug`, `Display`, `Hash`, `Send`, `Sync`, and `'static`.
179///
180/// Implemented for `u8`, `u16`, `u32`, `u64`, `u128`, and `usize`.
181///
182/// # Design note
183///
184/// Supertraits are listed explicitly rather than via type aliases,
185/// because some IDEs do not fully resolve trait aliases for
186/// autocompletion and go-to-definition.
187///
188/// # Examples
189///
190/// ```
191/// use platform_num::LinkReference;
192///
193/// fn create_link<T: LinkReference>(source: T, target: T) -> (T, T) {
194///     (source, target)
195/// }
196///
197/// let link = create_link(1u64, 2u64);
198/// assert_eq!(link, (1u64, 2u64));
199/// ```
200#[rustfmt::skip]
201pub trait LinkReference:
202Sized
203+ Number
204+ Unsigned
205+ ToSigned
206+ MaxValue
207+ WrappingArithmetic
208+ FromPrimitive
209+ TryFrom<i8, Error: Debug>
210+ TryFrom<u8, Error: Debug>
211+ TryFrom<i16, Error: Debug>
212+ TryFrom<u16, Error: Debug>
213+ TryFrom<i32, Error: Debug>
214+ TryFrom<u32, Error: Debug>
215+ TryFrom<i64, Error: Debug>
216+ TryFrom<u64, Error: Debug>
217+ TryFrom<i128, Error: Debug>
218+ TryFrom<u128, Error: Debug>
219+ TryFrom<isize, Error: Debug>
220+ TryFrom<usize, Error: Debug>
221+ TryInto<i8, Error: Debug>
222+ TryInto<u8, Error: Debug>
223+ TryInto<i16, Error: Debug>
224+ TryInto<u16, Error: Debug>
225+ TryInto<i32, Error: Debug>
226+ TryInto<u32, Error: Debug>
227+ TryInto<i64, Error: Debug>
228+ TryInto<u64, Error: Debug>
229+ TryInto<i128, Error: Debug>
230+ TryInto<u128, Error: Debug>
231+ TryInto<isize, Error: Debug>
232+ TryInto<usize, Error: Debug>
233+ Debug
234+ Display
235+ Hash
236+ Send
237+ Sync
238+ 'static
239{
240    /// Creates a value of this type from a `u8`, panicking on overflow.
241    fn from_byte(n: u8) -> Self {
242        Self::try_from(n).unwrap_or_else(|e| {
243            panic!("LinkReference::from_byte({n}) failed: {e:?}")
244        })
245    }
246}
247
248#[rustfmt::skip]
249impl<
250    All: Sized
251    + Number
252    + Unsigned
253    + ToSigned
254    + MaxValue
255    + WrappingArithmetic
256    + FromPrimitive
257    + TryFrom<i8, Error: Debug>
258    + TryFrom<u8, Error: Debug>
259    + TryFrom<i16, Error: Debug>
260    + TryFrom<u16, Error: Debug>
261    + TryFrom<i32, Error: Debug>
262    + TryFrom<u32, Error: Debug>
263    + TryFrom<i64, Error: Debug>
264    + TryFrom<u64, Error: Debug>
265    + TryFrom<i128, Error: Debug>
266    + TryFrom<u128, Error: Debug>
267    + TryFrom<isize, Error: Debug>
268    + TryFrom<usize, Error: Debug>
269    + TryInto<i8, Error: Debug>
270    + TryInto<u8, Error: Debug>
271    + TryInto<i16, Error: Debug>
272    + TryInto<u16, Error: Debug>
273    + TryInto<i32, Error: Debug>
274    + TryInto<u32, Error: Debug>
275    + TryInto<i64, Error: Debug>
276    + TryInto<u64, Error: Debug>
277    + TryInto<i128, Error: Debug>
278    + TryInto<u128, Error: Debug>
279    + TryInto<isize, Error: Debug>
280    + TryInto<usize, Error: Debug>
281    + Debug
282    + Display
283    + Hash
284    + Send
285    + Sync
286    + 'static,
287> LinkReference for All {}