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 };
73}
74
75#[cfg(target_pointer_width = "32")]
76mod target32 {
78 cast_from!(u8, usize);
80 cast_from!(u16, usize);
81 cast_from!(u8, isize);
82 cast_from!(i8, isize);
83 cast_from!(u16, isize);
84 cast_from!(i16, isize);
85
86 cast_from!(usize, u64);
87 cast_from!(usize, i64);
88 cast_from!(usize, u128);
89 cast_from!(usize, i128);
90 cast_from!(isize, i64);
91 cast_from!(isize, i128);
92
93 cast_from!(usize, u32);
95 cast_from!(isize, i32);
96 cast_from!(u32, usize);
97 cast_from!(i32, isize);
98}
99#[cfg(target_pointer_width = "32")]
100pub use target32::*;
101
102#[cfg(target_pointer_width = "64")]
103pub mod target64 {
105 cast_from!(u8, usize);
107 cast_from!(u16, usize);
108 cast_from!(u32, usize);
109 cast_from!(u8, isize);
110 cast_from!(i8, isize);
111 cast_from!(u16, isize);
112 cast_from!(i16, isize);
113 cast_from!(u32, isize);
114 cast_from!(i32, isize);
115
116 cast_from!(usize, u128);
117 cast_from!(usize, i128);
118 cast_from!(isize, i128);
119
120 cast_from!(usize, u64);
122 cast_from!(isize, i64);
123 cast_from!(u64, usize);
124 cast_from!(i64, isize);
125}
126#[cfg(target_pointer_width = "64")]
127pub use target64::*;
128
129cast_from!(u8, u8);
131cast_from!(u8, u16);
132cast_from!(u8, i16);
133cast_from!(u8, u32);
134cast_from!(u8, i32);
135cast_from!(u8, u64);
136cast_from!(u8, i64);
137cast_from!(u8, u128);
138cast_from!(u8, i128);
139cast_from!(u16, u16);
140cast_from!(u16, u32);
141cast_from!(u16, i32);
142cast_from!(u16, u64);
143cast_from!(u16, i64);
144cast_from!(u16, u128);
145cast_from!(u16, i128);
146cast_from!(u32, u32);
147cast_from!(u32, u64);
148cast_from!(u32, i64);
149cast_from!(u32, u128);
150cast_from!(u32, i128);
151cast_from!(u64, u64);
152cast_from!(u64, u128);
153cast_from!(u64, i128);
154cast_from!(i8, i8);
155cast_from!(i8, i16);
156cast_from!(i8, i32);
157cast_from!(i8, i64);
158cast_from!(i8, i128);
159cast_from!(i16, i16);
160cast_from!(i16, i32);
161cast_from!(i16, i64);
162cast_from!(i16, i128);
163cast_from!(i32, i32);
164cast_from!(i32, i64);
165cast_from!(i32, i128);
166cast_from!(i64, i64);
167cast_from!(i64, i128);
168
169pub trait ReinterpretCast<T> {
180 fn reinterpret_cast(from: T) -> Self;
182}
183
184macro_rules! reinterpret_cast {
185 ($from:ty, $to:ty) => {
186 impl ReinterpretCast<$from> for $to {
187 #[allow(clippy::as_conversions)]
188 fn reinterpret_cast(from: $from) -> $to {
189 from as $to
190 }
191 }
192 };
193}
194
195reinterpret_cast!(u8, i8);
196reinterpret_cast!(i8, u8);
197reinterpret_cast!(u16, i16);
198reinterpret_cast!(i16, u16);
199reinterpret_cast!(u32, i32);
200reinterpret_cast!(i32, u32);
201reinterpret_cast!(u64, i64);
202reinterpret_cast!(i64, u64);
203
204pub trait TryCastFrom<T>: Sized {
214 fn try_cast_from(from: T) -> Option<Self>;
216}
217
218macro_rules! try_cast_from {
222 ($from:ty, $to:ty) => {
223 impl crate::cast::TryCastFrom<$from> for $to {
224 #[allow(clippy::as_conversions)]
225 fn try_cast_from(from: $from) -> Option<$to> {
226 let to = from as $to;
227 let inverse = to as $from;
228 if from == inverse { Some(to) } else { None }
229 }
230 }
231 };
232}
233
234try_cast_from!(f64, i64);
235try_cast_from!(i64, f64);
236try_cast_from!(f64, u64);
237try_cast_from!(u64, f64);
238
239pub trait CastLossy<T> {
243 fn cast_lossy(from: T) -> Self;
245}
246
247macro_rules! cast_lossy {
249 ($from:ty, $to:ty) => {
250 impl crate::cast::CastLossy<$from> for $to {
251 #[allow(clippy::as_conversions)]
252 fn cast_lossy(from: $from) -> $to {
253 from as $to
254 }
255 }
256 };
257}
258
259cast_lossy!(usize, f32);
260cast_lossy!(isize, f32);
261cast_lossy!(f32, usize);
262cast_lossy!(i64, f32);
263cast_lossy!(f32, i64);
264cast_lossy!(u64, f32);
265cast_lossy!(f32, u64);
266cast_lossy!(f32, u32);
267cast_lossy!(usize, f64);
268cast_lossy!(isize, f64);
269cast_lossy!(f64, usize);
270cast_lossy!(i64, f64);
271cast_lossy!(f64, i64);
272cast_lossy!(u64, f64);
273cast_lossy!(f64, u64);
274cast_lossy!(f64, u32);
275
276#[crate::test]
277fn test_try_cast_from() {
278 let f64_i64_cases = vec![
279 (0.0, Some(0)),
280 (1.0, Some(1)),
281 (1.5, None),
282 (f64::INFINITY, None),
283 (f64::NAN, None),
284 (f64::EPSILON, None),
285 (f64::MAX, None),
286 (f64::MIN, None),
287 (9223372036854775807f64, Some(i64::MAX)),
288 (-9223372036854775808f64, Some(i64::MIN)),
289 (9223372036854775807f64 + 10_000f64, None),
290 (-9223372036854775808f64 - 10_000f64, None),
291 ];
292 let i64_f64_cases = vec![
293 (0, Some(0.0)),
294 (1, Some(1.0)),
295 (-1, Some(-1.0)),
296 (i64::MAX, Some(9223372036854775807f64)),
297 (i64::MIN, Some(-9223372036854775808f64)),
298 (i64::MAX - 1, None),
299 (i64::MIN + 1, None),
300 ];
301 let f64_u64_cases = vec![
302 (0.0, Some(0)),
303 (1.0, Some(1)),
304 (1.5, None),
305 (f64::INFINITY, None),
306 (f64::NAN, None),
307 (f64::EPSILON, None),
308 (f64::MAX, None),
309 (f64::MIN, None),
310 (-1.0, None),
311 (18446744073709551615f64, Some(u64::MAX)),
312 (18446744073709551615f64 + 10_000f64, None),
313 (9007199254740992f64, Some(9007199254740992)),
315 (9007199254740991f64, Some(9007199254740991)),
317 ];
318 let u64_f64_cases = vec![
319 (0, Some(0.0)),
320 (1, Some(1.0)),
321 (u64::MAX, Some(18446744073709551615f64)),
322 (u64::MAX - 1, None),
323 (9007199254740992, Some(9007199254740992f64)),
325 (9007199254740991, Some(9007199254740991f64)),
327 (9007199254740993, None),
329 ];
330 for (f, expect) in f64_i64_cases {
331 let r = i64::try_cast_from(f);
332 assert_eq!(r, expect, "input: {f}");
333 }
334 for (i, expect) in i64_f64_cases {
335 let r = f64::try_cast_from(i);
336 assert_eq!(r, expect, "input: {i}");
337 }
338 for (f, expect) in f64_u64_cases {
339 let r = u64::try_cast_from(f);
340 assert_eq!(r, expect, "input: {f}");
341 }
342 for (u, expect) in u64_f64_cases {
343 let r = f64::try_cast_from(u);
344 assert_eq!(r, expect, "input: {u}");
345 }
346}