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, f64);
260cast_lossy!(isize, f64);
261cast_lossy!(f64, usize);
262cast_lossy!(i64, f64);
263cast_lossy!(f64, i64);
264cast_lossy!(u64, f64);
265cast_lossy!(f64, u64);
266cast_lossy!(f64, u32);
267
268#[crate::test]
269fn test_try_cast_from() {
270 let f64_i64_cases = vec![
271 (0.0, Some(0)),
272 (1.0, Some(1)),
273 (1.5, None),
274 (f64::INFINITY, None),
275 (f64::NAN, None),
276 (f64::EPSILON, None),
277 (f64::MAX, None),
278 (f64::MIN, None),
279 (9223372036854775807f64, Some(i64::MAX)),
280 (-9223372036854775808f64, Some(i64::MIN)),
281 (9223372036854775807f64 + 10_000f64, None),
282 (-9223372036854775808f64 - 10_000f64, None),
283 ];
284 let i64_f64_cases = vec![
285 (0, Some(0.0)),
286 (1, Some(1.0)),
287 (-1, Some(-1.0)),
288 (i64::MAX, Some(9223372036854775807f64)),
289 (i64::MIN, Some(-9223372036854775808f64)),
290 (i64::MAX - 1, None),
291 (i64::MIN + 1, None),
292 ];
293 let f64_u64_cases = vec![
294 (0.0, Some(0)),
295 (1.0, Some(1)),
296 (1.5, None),
297 (f64::INFINITY, None),
298 (f64::NAN, None),
299 (f64::EPSILON, None),
300 (f64::MAX, None),
301 (f64::MIN, None),
302 (-1.0, None),
303 (18446744073709551615f64, Some(u64::MAX)),
304 (18446744073709551615f64 + 10_000f64, None),
305 (9007199254740992f64, Some(9007199254740992)),
307 (9007199254740991f64, Some(9007199254740991)),
309 ];
310 let u64_f64_cases = vec![
311 (0, Some(0.0)),
312 (1, Some(1.0)),
313 (u64::MAX, Some(18446744073709551615f64)),
314 (u64::MAX - 1, None),
315 (9007199254740992, Some(9007199254740992f64)),
317 (9007199254740991, Some(9007199254740991f64)),
319 (9007199254740993, None),
321 ];
322 for (f, expect) in f64_i64_cases {
323 let r = i64::try_cast_from(f);
324 assert_eq!(r, expect, "input: {f}");
325 }
326 for (i, expect) in i64_f64_cases {
327 let r = f64::try_cast_from(i);
328 assert_eq!(r, expect, "input: {i}");
329 }
330 for (f, expect) in f64_u64_cases {
331 let r = u64::try_cast_from(f);
332 assert_eq!(r, expect, "input: {f}");
333 }
334 for (u, expect) in u64_f64_cases {
335 let r = f64::try_cast_from(u);
336 assert_eq!(r, expect, "input: {u}");
337 }
338}