1pub trait CastFrom<T> {
33 fn cast_from(from: T) -> Self;
35}
36
37pub trait CastInto<T> {
40 fn cast_into(self) -> T;
42}
43
44impl<T, U> CastInto<U> for T
45where
46 U: CastFrom<T>,
47{
48 fn cast_into(self) -> U {
49 U::cast_from(self)
50 }
51}
52
53macro_rules! cast_from {
54 ($from:ty, $to:ty) => {
55 paste::paste! {
56 impl crate::cast::CastFrom<$from> for $to {
57 #[allow(clippy::as_conversions)]
58 fn cast_from(from: $from) -> $to {
59 from as $to
60 }
61 }
62
63 #[allow(clippy::as_conversions)]
68 pub const fn [< $from _to_ $to >](from: $from) -> $to {
69 from as $to
70 }
71
72 impl crate::cast::CastFrom<std::num::NonZero<$from>> for $to {
73 #[allow(clippy::as_conversions)]
74 fn cast_from(from: std::num::NonZero<$from>) -> $to {
75 from.get() as $to
76 }
77 }
78 }
79 };
80}
81
82#[cfg(target_pointer_width = "32")]
83mod target32 {
85 cast_from!(u8, usize);
87 cast_from!(u16, usize);
88 cast_from!(u8, isize);
89 cast_from!(i8, isize);
90 cast_from!(u16, isize);
91 cast_from!(i16, isize);
92
93 cast_from!(usize, u64);
94 cast_from!(usize, i64);
95 cast_from!(usize, u128);
96 cast_from!(usize, i128);
97 cast_from!(isize, i64);
98 cast_from!(isize, i128);
99
100 cast_from!(usize, u32);
102 cast_from!(isize, i32);
103 cast_from!(u32, usize);
104 cast_from!(i32, isize);
105}
106#[cfg(target_pointer_width = "32")]
107pub use target32::*;
108
109#[cfg(target_pointer_width = "64")]
110pub mod target64 {
112 cast_from!(u8, usize);
114 cast_from!(u16, usize);
115 cast_from!(u32, usize);
116 cast_from!(u8, isize);
117 cast_from!(i8, isize);
118 cast_from!(u16, isize);
119 cast_from!(i16, isize);
120 cast_from!(u32, isize);
121 cast_from!(i32, isize);
122
123 cast_from!(usize, u128);
124 cast_from!(usize, i128);
125 cast_from!(isize, i128);
126
127 cast_from!(usize, u64);
129 cast_from!(isize, i64);
130 cast_from!(u64, usize);
131 cast_from!(i64, isize);
132}
133#[cfg(target_pointer_width = "64")]
134pub use target64::*;
135
136cast_from!(u8, u8);
138cast_from!(u8, u16);
139cast_from!(u8, i16);
140cast_from!(u8, u32);
141cast_from!(u8, i32);
142cast_from!(u8, u64);
143cast_from!(u8, i64);
144cast_from!(u8, u128);
145cast_from!(u8, i128);
146cast_from!(u16, u16);
147cast_from!(u16, u32);
148cast_from!(u16, i32);
149cast_from!(u16, u64);
150cast_from!(u16, i64);
151cast_from!(u16, u128);
152cast_from!(u16, i128);
153cast_from!(u32, u32);
154cast_from!(u32, u64);
155cast_from!(u32, i64);
156cast_from!(u32, u128);
157cast_from!(u32, i128);
158cast_from!(u64, u64);
159cast_from!(u64, u128);
160cast_from!(u64, i128);
161cast_from!(i8, i8);
162cast_from!(i8, i16);
163cast_from!(i8, i32);
164cast_from!(i8, i64);
165cast_from!(i8, i128);
166cast_from!(i16, i16);
167cast_from!(i16, i32);
168cast_from!(i16, i64);
169cast_from!(i16, i128);
170cast_from!(i32, i32);
171cast_from!(i32, i64);
172cast_from!(i32, i128);
173cast_from!(i64, i64);
174cast_from!(i64, i128);
175
176pub trait ReinterpretCast<T> {
187 fn reinterpret_cast(from: T) -> Self;
189}
190
191macro_rules! reinterpret_cast {
192 ($from:ty, $to:ty) => {
193 impl ReinterpretCast<$from> for $to {
194 #[allow(clippy::as_conversions)]
195 fn reinterpret_cast(from: $from) -> $to {
196 from as $to
197 }
198 }
199 };
200}
201
202reinterpret_cast!(u8, i8);
203reinterpret_cast!(i8, u8);
204reinterpret_cast!(u16, i16);
205reinterpret_cast!(i16, u16);
206reinterpret_cast!(u32, i32);
207reinterpret_cast!(i32, u32);
208reinterpret_cast!(u64, i64);
209reinterpret_cast!(i64, u64);
210
211pub trait TryCastFrom<T>: Sized {
221 fn try_cast_from(from: T) -> Option<Self>;
223}
224
225macro_rules! try_cast_from {
229 ($from:ty, $to:ty) => {
230 impl crate::cast::TryCastFrom<$from> for $to {
231 #[allow(clippy::as_conversions)]
232 fn try_cast_from(from: $from) -> Option<$to> {
233 let to = from as $to;
234 let inverse = to as $from;
235 if from == inverse { Some(to) } else { None }
236 }
237 }
238 };
239}
240
241try_cast_from!(f64, i64);
242try_cast_from!(i64, f64);
243try_cast_from!(f64, u64);
244try_cast_from!(u64, f64);
245
246pub trait CastLossy<T> {
250 fn cast_lossy(from: T) -> Self;
252}
253
254macro_rules! cast_lossy {
256 ($from:ty, $to:ty) => {
257 impl crate::cast::CastLossy<$from> for $to {
258 #[allow(clippy::as_conversions)]
259 fn cast_lossy(from: $from) -> $to {
260 from as $to
261 }
262 }
263 };
264}
265
266cast_lossy!(usize, f32);
267cast_lossy!(isize, f32);
268cast_lossy!(f32, usize);
269cast_lossy!(i64, f32);
270cast_lossy!(f32, i64);
271cast_lossy!(u64, f32);
272cast_lossy!(f32, u64);
273cast_lossy!(f32, u32);
274cast_lossy!(usize, f64);
275cast_lossy!(isize, f64);
276cast_lossy!(f64, usize);
277cast_lossy!(i64, f64);
278cast_lossy!(f64, i64);
279cast_lossy!(u64, f64);
280cast_lossy!(f64, u64);
281cast_lossy!(f64, u32);
282
283#[crate::test]
284fn test_try_cast_from() {
285 let f64_i64_cases = vec![
286 (0.0, Some(0)),
287 (1.0, Some(1)),
288 (1.5, None),
289 (f64::INFINITY, None),
290 (f64::NAN, None),
291 (f64::EPSILON, None),
292 (f64::MAX, None),
293 (f64::MIN, None),
294 (9223372036854775807f64, Some(i64::MAX)),
295 (-9223372036854775808f64, Some(i64::MIN)),
296 (9223372036854775807f64 + 10_000f64, None),
297 (-9223372036854775808f64 - 10_000f64, None),
298 ];
299 let i64_f64_cases = vec![
300 (0, Some(0.0)),
301 (1, Some(1.0)),
302 (-1, Some(-1.0)),
303 (i64::MAX, Some(9223372036854775807f64)),
304 (i64::MIN, Some(-9223372036854775808f64)),
305 (i64::MAX - 1, None),
306 (i64::MIN + 1, None),
307 ];
308 let f64_u64_cases = vec![
309 (0.0, Some(0)),
310 (1.0, Some(1)),
311 (1.5, None),
312 (f64::INFINITY, None),
313 (f64::NAN, None),
314 (f64::EPSILON, None),
315 (f64::MAX, None),
316 (f64::MIN, None),
317 (-1.0, None),
318 (18446744073709551615f64, Some(u64::MAX)),
319 (18446744073709551615f64 + 10_000f64, None),
320 (9007199254740992f64, Some(9007199254740992)),
322 (9007199254740991f64, Some(9007199254740991)),
324 ];
325 let u64_f64_cases = vec![
326 (0, Some(0.0)),
327 (1, Some(1.0)),
328 (u64::MAX, Some(18446744073709551615f64)),
329 (u64::MAX - 1, None),
330 (9007199254740992, Some(9007199254740992f64)),
332 (9007199254740991, Some(9007199254740991f64)),
334 (9007199254740993, None),
336 ];
337 for (f, expect) in f64_i64_cases {
338 let r = i64::try_cast_from(f);
339 assert_eq!(r, expect, "input: {f}");
340 }
341 for (i, expect) in i64_f64_cases {
342 let r = f64::try_cast_from(i);
343 assert_eq!(r, expect, "input: {i}");
344 }
345 for (f, expect) in f64_u64_cases {
346 let r = u64::try_cast_from(f);
347 assert_eq!(r, expect, "input: {f}");
348 }
349 for (u, expect) in u64_f64_cases {
350 let r = f64::try_cast_from(u);
351 assert_eq!(r, expect, "input: {u}");
352 }
353}