enum_primitive/
cast.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5use core::mem::size_of;
6use core::num::Wrapping;
7
8/// A generic trait for converting a value to a number.
9pub trait ToPrimitive {
10    /// Converts the value of `self` to an `isize`.
11    #[inline]
12    fn to_isize(&self) -> Option<isize> {
13        self.to_i64().as_ref().and_then(ToPrimitive::to_isize)
14    }
15
16    /// Converts the value of `self` to an `i8`.
17    #[inline]
18    fn to_i8(&self) -> Option<i8> {
19        self.to_i64().as_ref().and_then(ToPrimitive::to_i8)
20    }
21
22    /// Converts the value of `self` to an `i16`.
23    #[inline]
24    fn to_i16(&self) -> Option<i16> {
25        self.to_i64().as_ref().and_then(ToPrimitive::to_i16)
26    }
27
28    /// Converts the value of `self` to an `i32`.
29    #[inline]
30    fn to_i32(&self) -> Option<i32> {
31        self.to_i64().as_ref().and_then(ToPrimitive::to_i32)
32    }
33
34    /// Converts the value of `self` to an `i64`.
35    fn to_i64(&self) -> Option<i64>;
36
37    /// Converts the value of `self` to a `usize`.
38    #[inline]
39    fn to_usize(&self) -> Option<usize> {
40        self.to_u64().as_ref().and_then(ToPrimitive::to_usize)
41    }
42
43    /// Converts the value of `self` to an `u8`.
44    #[inline]
45    fn to_u8(&self) -> Option<u8> {
46        self.to_u64().as_ref().and_then(ToPrimitive::to_u8)
47    }
48
49    /// Converts the value of `self` to an `u16`.
50    #[inline]
51    fn to_u16(&self) -> Option<u16> {
52        self.to_u64().as_ref().and_then(ToPrimitive::to_u16)
53    }
54
55    /// Converts the value of `self` to an `u32`.
56    #[inline]
57    fn to_u32(&self) -> Option<u32> {
58        self.to_u64().as_ref().and_then(ToPrimitive::to_u32)
59    }
60
61    /// Converts the value of `self` to an `u64`.
62    fn to_u64(&self) -> Option<u64>;
63}
64
65macro_rules! impl_to_primitive_int_to_int {
66    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
67        #[inline]
68        $(#[$cfg])*
69        fn $method(&self) -> Option<$DstT> {
70            let min = $DstT::MIN as $SrcT;
71            let max = $DstT::MAX as $SrcT;
72            if size_of::<$SrcT>() <= size_of::<$DstT>() || (min <= *self && *self <= max) {
73                Some(*self as $DstT)
74            } else {
75                None
76            }
77        }
78    )*}
79}
80
81macro_rules! impl_to_primitive_int_to_uint {
82    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
83        #[inline]
84        $(#[$cfg])*
85        fn $method(&self) -> Option<$DstT> {
86            let max = $DstT::MAX as $SrcT;
87            if 0 <= *self && (size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max) {
88                Some(*self as $DstT)
89            } else {
90                None
91            }
92        }
93    )*}
94}
95
96macro_rules! impl_to_primitive_int {
97    ($T:ident) => {
98        impl ToPrimitive for $T {
99            impl_to_primitive_int_to_int! { $T:
100                fn to_isize -> isize;
101                fn to_i8 -> i8;
102                fn to_i16 -> i16;
103                fn to_i32 -> i32;
104                fn to_i64 -> i64;
105            }
106
107            impl_to_primitive_int_to_uint! { $T:
108                fn to_usize -> usize;
109                fn to_u8 -> u8;
110                fn to_u16 -> u16;
111                fn to_u32 -> u32;
112                fn to_u64 -> u64;
113            }
114        }
115    };
116}
117
118impl_to_primitive_int!(isize);
119impl_to_primitive_int!(i8);
120impl_to_primitive_int!(i16);
121impl_to_primitive_int!(i32);
122impl_to_primitive_int!(i64);
123
124macro_rules! impl_to_primitive_uint_to_int {
125    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
126        #[inline]
127        $(#[$cfg])*
128        fn $method(&self) -> Option<$DstT> {
129            let max = $DstT::MAX as $SrcT;
130            if size_of::<$SrcT>() < size_of::<$DstT>() || *self <= max {
131                Some(*self as $DstT)
132            } else {
133                None
134            }
135        }
136    )*}
137}
138
139macro_rules! impl_to_primitive_uint_to_uint {
140    ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
141        #[inline]
142        $(#[$cfg])*
143        fn $method(&self) -> Option<$DstT> {
144            let max = $DstT::MAX as $SrcT;
145            if size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max {
146                Some(*self as $DstT)
147            } else {
148                None
149            }
150        }
151    )*}
152}
153
154macro_rules! impl_to_primitive_uint {
155    ($T:ident) => {
156        impl ToPrimitive for $T {
157            impl_to_primitive_uint_to_int! { $T:
158                fn to_isize -> isize;
159                fn to_i8 -> i8;
160                fn to_i16 -> i16;
161                fn to_i32 -> i32;
162                fn to_i64 -> i64;
163            }
164
165            impl_to_primitive_uint_to_uint! { $T:
166                fn to_usize -> usize;
167                fn to_u8 -> u8;
168                fn to_u16 -> u16;
169                fn to_u32 -> u32;
170                fn to_u64 -> u64;
171            }
172        }
173    };
174}
175
176impl_to_primitive_uint!(usize);
177impl_to_primitive_uint!(u8);
178impl_to_primitive_uint!(u16);
179impl_to_primitive_uint!(u32);
180impl_to_primitive_uint!(u64);
181
182/// A generic trait for converting a number to a value.
183pub trait FromPrimitive: Sized {
184    /// Convert an `isize` to return an optional value of this type. If the
185    /// value cannot be represented by this value, then `None` is returned.
186    #[inline]
187    fn from_isize(n: isize) -> Option<Self> {
188        n.to_i64().and_then(FromPrimitive::from_i64)
189    }
190
191    /// Convert an `i8` to return an optional value of this type. If the
192    /// type cannot be represented by this value, then `None` is returned.
193    #[inline]
194    fn from_i8(n: i8) -> Option<Self> {
195        FromPrimitive::from_i64(From::from(n))
196    }
197
198    /// Convert an `i16` to return an optional value of this type. If the
199    /// type cannot be represented by this value, then `None` is returned.
200    #[inline]
201    fn from_i16(n: i16) -> Option<Self> {
202        FromPrimitive::from_i64(From::from(n))
203    }
204
205    /// Convert an `i32` to return an optional value of this type. If the
206    /// type cannot be represented by this value, then `None` is returned.
207    #[inline]
208    fn from_i32(n: i32) -> Option<Self> {
209        FromPrimitive::from_i64(From::from(n))
210    }
211
212    /// Convert an `i64` to return an optional value of this type. If the
213    /// type cannot be represented by this value, then `None` is returned.
214    fn from_i64(n: i64) -> Option<Self>;
215
216    /// Convert a `usize` to return an optional value of this type. If the
217    /// type cannot be represented by this value, then `None` is returned.
218    #[inline]
219    fn from_usize(n: usize) -> Option<Self> {
220        n.to_u64().and_then(FromPrimitive::from_u64)
221    }
222
223    /// Convert an `u8` to return an optional value of this type. If the
224    /// type cannot be represented by this value, then `None` is returned.
225    #[inline]
226    fn from_u8(n: u8) -> Option<Self> {
227        FromPrimitive::from_u64(From::from(n))
228    }
229
230    /// Convert an `u16` to return an optional value of this type. If the
231    /// type cannot be represented by this value, then `None` is returned.
232    #[inline]
233    fn from_u16(n: u16) -> Option<Self> {
234        FromPrimitive::from_u64(From::from(n))
235    }
236
237    /// Convert an `u32` to return an optional value of this type. If the
238    /// type cannot be represented by this value, then `None` is returned.
239    #[inline]
240    fn from_u32(n: u32) -> Option<Self> {
241        FromPrimitive::from_u64(From::from(n))
242    }
243
244    /// Convert an `u64` to return an optional value of this type. If the
245    /// type cannot be represented by this value, then `None` is returned.
246    fn from_u64(n: u64) -> Option<Self>;
247}
248
249macro_rules! impl_from_primitive {
250    ($T:ty, $to_ty:ident) => {
251        #[allow(deprecated)]
252        impl FromPrimitive for $T {
253            #[inline]
254            fn from_isize(n: isize) -> Option<$T> {
255                n.$to_ty()
256            }
257            #[inline]
258            fn from_i8(n: i8) -> Option<$T> {
259                n.$to_ty()
260            }
261            #[inline]
262            fn from_i16(n: i16) -> Option<$T> {
263                n.$to_ty()
264            }
265            #[inline]
266            fn from_i32(n: i32) -> Option<$T> {
267                n.$to_ty()
268            }
269            #[inline]
270            fn from_i64(n: i64) -> Option<$T> {
271                n.$to_ty()
272            }
273
274            #[inline]
275            fn from_usize(n: usize) -> Option<$T> {
276                n.$to_ty()
277            }
278            #[inline]
279            fn from_u8(n: u8) -> Option<$T> {
280                n.$to_ty()
281            }
282            #[inline]
283            fn from_u16(n: u16) -> Option<$T> {
284                n.$to_ty()
285            }
286            #[inline]
287            fn from_u32(n: u32) -> Option<$T> {
288                n.$to_ty()
289            }
290            #[inline]
291            fn from_u64(n: u64) -> Option<$T> {
292                n.$to_ty()
293            }
294        }
295    };
296}
297
298impl_from_primitive!(isize, to_isize);
299impl_from_primitive!(i8, to_i8);
300impl_from_primitive!(i16, to_i16);
301impl_from_primitive!(i32, to_i32);
302impl_from_primitive!(i64, to_i64);
303impl_from_primitive!(usize, to_usize);
304impl_from_primitive!(u8, to_u8);
305impl_from_primitive!(u16, to_u16);
306impl_from_primitive!(u32, to_u32);
307impl_from_primitive!(u64, to_u64);
308
309macro_rules! impl_to_primitive_wrapping {
310    ($( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$(
311        #[inline]
312        $(#[$cfg])*
313        fn $method(&self) -> Option<$i> {
314            (self.0).$method()
315        }
316    )*}
317}
318
319impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
320    impl_to_primitive_wrapping! {
321        fn to_isize -> isize;
322        fn to_i8 -> i8;
323        fn to_i16 -> i16;
324        fn to_i32 -> i32;
325        fn to_i64 -> i64;
326
327        fn to_usize -> usize;
328        fn to_u8 -> u8;
329        fn to_u16 -> u16;
330        fn to_u32 -> u32;
331        fn to_u64 -> u64;
332    }
333}
334
335macro_rules! impl_from_primitive_wrapping {
336    ($( $(#[$cfg:meta])* fn $method:ident ( $i:ident ); )*) => {$(
337        #[inline]
338        $(#[$cfg])*
339        fn $method(n: $i) -> Option<Self> {
340            T::$method(n).map(Wrapping)
341        }
342    )*}
343}
344
345impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
346    impl_from_primitive_wrapping! {
347        fn from_isize(isize);
348        fn from_i8(i8);
349        fn from_i16(i16);
350        fn from_i32(i32);
351        fn from_i64(i64);
352        fn from_usize(usize);
353        fn from_u8(u8);
354        fn from_u16(u16);
355        fn from_u32(u32);
356        fn from_u64(u64);
357    }
358}