1 | use crate::num::TryFromIntError; |
2 | |
3 | mod private { |
4 | /// This trait being unreachable from outside the crate |
5 | /// prevents other implementations of the `FloatToInt` trait, |
6 | /// which allows potentially adding more trait methods after the trait is `#[stable]`. |
7 | #[unstable (feature = "convert_float_to_int" , issue = "67057" )] |
8 | pub trait Sealed {} |
9 | } |
10 | |
11 | /// Supporting trait for inherent methods of `f32` and `f64` such as `to_int_unchecked`. |
12 | /// Typically doesn’t need to be used directly. |
13 | #[unstable (feature = "convert_float_to_int" , issue = "67057" )] |
14 | pub trait FloatToInt<Int>: private::Sealed + Sized { |
15 | #[unstable (feature = "convert_float_to_int" , issue = "67057" )] |
16 | #[doc (hidden)] |
17 | unsafe fn to_int_unchecked(self) -> Int; |
18 | } |
19 | |
20 | macro_rules! impl_float_to_int { |
21 | ($Float:ty => $($Int:ty),+) => { |
22 | #[unstable(feature = "convert_float_to_int" , issue = "67057" )] |
23 | impl private::Sealed for $Float {} |
24 | $( |
25 | #[unstable(feature = "convert_float_to_int" , issue = "67057" )] |
26 | impl FloatToInt<$Int> for $Float { |
27 | #[inline] |
28 | unsafe fn to_int_unchecked(self) -> $Int { |
29 | // SAFETY: the safety contract must be upheld by the caller. |
30 | unsafe { crate::intrinsics::float_to_int_unchecked(self) } |
31 | } |
32 | } |
33 | )+ |
34 | } |
35 | } |
36 | |
37 | impl_float_to_int!(f16 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); |
38 | impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); |
39 | impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); |
40 | impl_float_to_int!(f128 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); |
41 | |
42 | // Conversion traits for primitive integer and float types |
43 | // Conversions T -> T are covered by a blanket impl and therefore excluded |
44 | // Some conversions from and to usize/isize are not implemented due to portability concerns |
45 | macro_rules! impl_from { |
46 | (bool => $Int:ty $(,)?) => { |
47 | impl_from!( |
48 | bool => $Int, |
49 | #[stable(feature = "from_bool" , since = "1.28.0" )], |
50 | concat!( |
51 | "Converts a [`bool`] to [`" , stringify!($Int), "`] losslessly. \n" , |
52 | "The resulting value is `0` for `false` and `1` for `true` values. \n" , |
53 | " \n" , |
54 | "# Examples \n" , |
55 | " \n" , |
56 | "``` \n" , |
57 | "assert_eq!(" , stringify!($Int), "::from(true), 1); \n" , |
58 | "assert_eq!(" , stringify!($Int), "::from(false), 0); \n" , |
59 | "``` \n" , |
60 | ), |
61 | ); |
62 | }; |
63 | ($Small:ty => $Large:ty, #[$attr:meta] $(,)?) => { |
64 | impl_from!( |
65 | $Small => $Large, |
66 | #[$attr], |
67 | concat!("Converts [`" , stringify!($Small), "`] to [`" , stringify!($Large), "`] losslessly." ), |
68 | ); |
69 | }; |
70 | ($Small:ty => $Large:ty, #[$attr:meta], $doc:expr $(,)?) => { |
71 | #[$attr] |
72 | impl From<$Small> for $Large { |
73 | // Rustdocs on the impl block show a "[+] show undocumented items" toggle. |
74 | // Rustdocs on functions do not. |
75 | #[doc = $doc] |
76 | #[inline(always)] |
77 | fn from(small: $Small) -> Self { |
78 | small as Self |
79 | } |
80 | } |
81 | }; |
82 | } |
83 | |
84 | // boolean -> integer |
85 | impl_from!(bool => u8); |
86 | impl_from!(bool => u16); |
87 | impl_from!(bool => u32); |
88 | impl_from!(bool => u64); |
89 | impl_from!(bool => u128); |
90 | impl_from!(bool => usize); |
91 | impl_from!(bool => i8); |
92 | impl_from!(bool => i16); |
93 | impl_from!(bool => i32); |
94 | impl_from!(bool => i64); |
95 | impl_from!(bool => i128); |
96 | impl_from!(bool => isize); |
97 | |
98 | // unsigned integer -> unsigned integer |
99 | impl_from!(u8 => u16, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
100 | impl_from!(u8 => u32, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
101 | impl_from!(u8 => u64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
102 | impl_from!(u8 => u128, #[stable (feature = "i128" , since = "1.26.0" )]); |
103 | impl_from!(u8 => usize, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
104 | impl_from!(u16 => u32, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
105 | impl_from!(u16 => u64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
106 | impl_from!(u16 => u128, #[stable (feature = "i128" , since = "1.26.0" )]); |
107 | impl_from!(u32 => u64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
108 | impl_from!(u32 => u128, #[stable (feature = "i128" , since = "1.26.0" )]); |
109 | impl_from!(u64 => u128, #[stable (feature = "i128" , since = "1.26.0" )]); |
110 | |
111 | // signed integer -> signed integer |
112 | impl_from!(i8 => i16, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
113 | impl_from!(i8 => i32, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
114 | impl_from!(i8 => i64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
115 | impl_from!(i8 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
116 | impl_from!(i8 => isize, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
117 | impl_from!(i16 => i32, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
118 | impl_from!(i16 => i64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
119 | impl_from!(i16 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
120 | impl_from!(i32 => i64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
121 | impl_from!(i32 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
122 | impl_from!(i64 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
123 | |
124 | // unsigned integer -> signed integer |
125 | impl_from!(u8 => i16, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
126 | impl_from!(u8 => i32, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
127 | impl_from!(u8 => i64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
128 | impl_from!(u8 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
129 | impl_from!(u16 => i32, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
130 | impl_from!(u16 => i64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
131 | impl_from!(u16 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
132 | impl_from!(u32 => i64, #[stable (feature = "lossless_int_conv" , since = "1.5.0" )]); |
133 | impl_from!(u32 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
134 | impl_from!(u64 => i128, #[stable (feature = "i128" , since = "1.26.0" )]); |
135 | |
136 | // The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX |
137 | // which imply that pointer-sized integers must be at least 16 bits: |
138 | // https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 |
139 | impl_from!(u16 => usize, #[stable (feature = "lossless_iusize_conv" , since = "1.26.0" )]); |
140 | impl_from!(u8 => isize, #[stable (feature = "lossless_iusize_conv" , since = "1.26.0" )]); |
141 | impl_from!(i16 => isize, #[stable (feature = "lossless_iusize_conv" , since = "1.26.0" )]); |
142 | |
143 | // RISC-V defines the possibility of a 128-bit address space (RV128). |
144 | |
145 | // CHERI proposes 128-bit “capabilities”. Unclear if this would be relevant to usize/isize. |
146 | // https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf |
147 | // https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf |
148 | |
149 | // Note: integers can only be represented with full precision in a float if |
150 | // they fit in the significand, which is: |
151 | // * 11 bits in f16 |
152 | // * 24 bits in f32 |
153 | // * 53 bits in f64 |
154 | // * 113 bits in f128 |
155 | // Lossy float conversions are not implemented at this time. |
156 | // FIXME(f16_f128): The `f16`/`f128` impls `#[stable]` attributes should be changed to reference |
157 | // `f16`/`f128` when they are stabilised (trait impls have to have a `#[stable]` attribute, but none |
158 | // of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable). |
159 | |
160 | // signed integer -> float |
161 | impl_from!(i8 => f16, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
162 | impl_from!(i8 => f32, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
163 | impl_from!(i8 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
164 | impl_from!(i8 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
165 | impl_from!(i16 => f32, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
166 | impl_from!(i16 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
167 | impl_from!(i16 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
168 | impl_from!(i32 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
169 | impl_from!(i32 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
170 | // FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised. |
171 | // impl_from!(i64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); |
172 | |
173 | // unsigned integer -> float |
174 | impl_from!(u8 => f16, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
175 | impl_from!(u8 => f32, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
176 | impl_from!(u8 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
177 | impl_from!(u8 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
178 | impl_from!(u16 => f16, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
179 | impl_from!(u16 => f32, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
180 | impl_from!(u16 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
181 | impl_from!(u16 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
182 | impl_from!(u32 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
183 | impl_from!(u32 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
184 | // FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised. |
185 | // impl_from!(u64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); |
186 | |
187 | // float -> float |
188 | // FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See |
189 | // <https://github.com/rust-lang/rust/issues/123831> |
190 | impl_from!(f16 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
191 | impl_from!(f16 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
192 | impl_from!(f32 => f64, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
193 | impl_from!(f32 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
194 | impl_from!(f64 => f128, #[stable (feature = "lossless_float_conv" , since = "1.6.0" )]); |
195 | |
196 | macro_rules! impl_float_from_bool { |
197 | ( |
198 | $float:ty $(; |
199 | doctest_prefix: $(#[doc = $doctest_prefix:literal])* |
200 | doctest_suffix: $(#[doc = $doctest_suffix:literal])* |
201 | )? |
202 | ) => { |
203 | #[stable(feature = "float_from_bool" , since = "1.68.0" )] |
204 | impl From<bool> for $float { |
205 | #[doc = concat!("Converts a [`bool`] to [`" , stringify!($float),"`] losslessly." )] |
206 | /// The resulting value is positive `0.0` for `false` and `1.0` for `true` values. |
207 | /// |
208 | /// # Examples |
209 | /// ``` |
210 | $($(#[doc = $doctest_prefix])*)? |
211 | #[doc = concat!("let x: " , stringify!($float)," = false.into();" )] |
212 | /// assert_eq!(x, 0.0); |
213 | /// assert!(x.is_sign_positive()); |
214 | /// |
215 | #[doc = concat!("let y: " , stringify!($float)," = true.into();" )] |
216 | /// assert_eq!(y, 1.0); |
217 | $($(#[doc = $doctest_suffix])*)? |
218 | /// ``` |
219 | #[inline] |
220 | fn from(small: bool) -> Self { |
221 | small as u8 as Self |
222 | } |
223 | } |
224 | }; |
225 | } |
226 | |
227 | // boolean -> float |
228 | impl_float_from_bool!( |
229 | f16; |
230 | doctest_prefix: |
231 | // rustdoc doesn't remove the conventional space after the `///` |
232 | ///#![feature(f16)] |
233 | ///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { |
234 | /// |
235 | doctest_suffix: |
236 | ///# } |
237 | ); |
238 | impl_float_from_bool!(f32); |
239 | impl_float_from_bool!(f64); |
240 | impl_float_from_bool!( |
241 | f128; |
242 | doctest_prefix: |
243 | ///#![feature(f128)] |
244 | ///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { |
245 | /// |
246 | doctest_suffix: |
247 | ///# } |
248 | ); |
249 | |
250 | // no possible bounds violation |
251 | macro_rules! impl_try_from_unbounded { |
252 | ($source:ty => $($target:ty),+) => {$( |
253 | #[stable(feature = "try_from" , since = "1.34.0" )] |
254 | impl TryFrom<$source> for $target { |
255 | type Error = TryFromIntError; |
256 | |
257 | /// Tries to create the target number type from a source |
258 | /// number type. This returns an error if the source value |
259 | /// is outside of the range of the target type. |
260 | #[inline] |
261 | fn try_from(value: $source) -> Result<Self, Self::Error> { |
262 | Ok(value as Self) |
263 | } |
264 | } |
265 | )*} |
266 | } |
267 | |
268 | // only negative bounds |
269 | macro_rules! impl_try_from_lower_bounded { |
270 | ($source:ty => $($target:ty),+) => {$( |
271 | #[stable(feature = "try_from" , since = "1.34.0" )] |
272 | impl TryFrom<$source> for $target { |
273 | type Error = TryFromIntError; |
274 | |
275 | /// Tries to create the target number type from a source |
276 | /// number type. This returns an error if the source value |
277 | /// is outside of the range of the target type. |
278 | #[inline] |
279 | fn try_from(u: $source) -> Result<Self, Self::Error> { |
280 | if u >= 0 { |
281 | Ok(u as Self) |
282 | } else { |
283 | Err(TryFromIntError(())) |
284 | } |
285 | } |
286 | } |
287 | )*} |
288 | } |
289 | |
290 | // unsigned to signed (only positive bound) |
291 | macro_rules! impl_try_from_upper_bounded { |
292 | ($source:ty => $($target:ty),+) => {$( |
293 | #[stable(feature = "try_from" , since = "1.34.0" )] |
294 | impl TryFrom<$source> for $target { |
295 | type Error = TryFromIntError; |
296 | |
297 | /// Tries to create the target number type from a source |
298 | /// number type. This returns an error if the source value |
299 | /// is outside of the range of the target type. |
300 | #[inline] |
301 | fn try_from(u: $source) -> Result<Self, Self::Error> { |
302 | if u > (Self::MAX as $source) { |
303 | Err(TryFromIntError(())) |
304 | } else { |
305 | Ok(u as Self) |
306 | } |
307 | } |
308 | } |
309 | )*} |
310 | } |
311 | |
312 | // all other cases |
313 | macro_rules! impl_try_from_both_bounded { |
314 | ($source:ty => $($target:ty),+) => {$( |
315 | #[stable(feature = "try_from" , since = "1.34.0" )] |
316 | impl TryFrom<$source> for $target { |
317 | type Error = TryFromIntError; |
318 | |
319 | /// Tries to create the target number type from a source |
320 | /// number type. This returns an error if the source value |
321 | /// is outside of the range of the target type. |
322 | #[inline] |
323 | fn try_from(u: $source) -> Result<Self, Self::Error> { |
324 | let min = Self::MIN as $source; |
325 | let max = Self::MAX as $source; |
326 | if u < min || u > max { |
327 | Err(TryFromIntError(())) |
328 | } else { |
329 | Ok(u as Self) |
330 | } |
331 | } |
332 | } |
333 | )*} |
334 | } |
335 | |
336 | macro_rules! rev { |
337 | ($mac:ident, $source:ty => $($target:ty),+) => {$( |
338 | $mac!($target => $source); |
339 | )*} |
340 | } |
341 | |
342 | // unsigned integer -> unsigned integer |
343 | impl_try_from_upper_bounded!(u16 => u8); |
344 | impl_try_from_upper_bounded!(u32 => u8, u16); |
345 | impl_try_from_upper_bounded!(u64 => u8, u16, u32); |
346 | impl_try_from_upper_bounded!(u128 => u8, u16, u32, u64); |
347 | |
348 | // signed integer -> signed integer |
349 | impl_try_from_both_bounded!(i16 => i8); |
350 | impl_try_from_both_bounded!(i32 => i8, i16); |
351 | impl_try_from_both_bounded!(i64 => i8, i16, i32); |
352 | impl_try_from_both_bounded!(i128 => i8, i16, i32, i64); |
353 | |
354 | // unsigned integer -> signed integer |
355 | impl_try_from_upper_bounded!(u8 => i8); |
356 | impl_try_from_upper_bounded!(u16 => i8, i16); |
357 | impl_try_from_upper_bounded!(u32 => i8, i16, i32); |
358 | impl_try_from_upper_bounded!(u64 => i8, i16, i32, i64); |
359 | impl_try_from_upper_bounded!(u128 => i8, i16, i32, i64, i128); |
360 | |
361 | // signed integer -> unsigned integer |
362 | impl_try_from_lower_bounded!(i8 => u8, u16, u32, u64, u128); |
363 | impl_try_from_both_bounded!(i16 => u8); |
364 | impl_try_from_lower_bounded!(i16 => u16, u32, u64, u128); |
365 | impl_try_from_both_bounded!(i32 => u8, u16); |
366 | impl_try_from_lower_bounded!(i32 => u32, u64, u128); |
367 | impl_try_from_both_bounded!(i64 => u8, u16, u32); |
368 | impl_try_from_lower_bounded!(i64 => u64, u128); |
369 | impl_try_from_both_bounded!(i128 => u8, u16, u32, u64); |
370 | impl_try_from_lower_bounded!(i128 => u128); |
371 | |
372 | // usize/isize |
373 | impl_try_from_upper_bounded!(usize => isize); |
374 | impl_try_from_lower_bounded!(isize => usize); |
375 | |
376 | #[cfg (target_pointer_width = "16" )] |
377 | mod ptr_try_from_impls { |
378 | use super::TryFromIntError; |
379 | |
380 | impl_try_from_upper_bounded!(usize => u8); |
381 | impl_try_from_unbounded!(usize => u16, u32, u64, u128); |
382 | impl_try_from_upper_bounded!(usize => i8, i16); |
383 | impl_try_from_unbounded!(usize => i32, i64, i128); |
384 | |
385 | impl_try_from_both_bounded!(isize => u8); |
386 | impl_try_from_lower_bounded!(isize => u16, u32, u64, u128); |
387 | impl_try_from_both_bounded!(isize => i8); |
388 | impl_try_from_unbounded!(isize => i16, i32, i64, i128); |
389 | |
390 | rev!(impl_try_from_upper_bounded, usize => u32, u64, u128); |
391 | rev!(impl_try_from_lower_bounded, usize => i8, i16); |
392 | rev!(impl_try_from_both_bounded, usize => i32, i64, i128); |
393 | |
394 | rev!(impl_try_from_upper_bounded, isize => u16, u32, u64, u128); |
395 | rev!(impl_try_from_both_bounded, isize => i32, i64, i128); |
396 | } |
397 | |
398 | #[cfg (target_pointer_width = "32" )] |
399 | mod ptr_try_from_impls { |
400 | use super::TryFromIntError; |
401 | |
402 | impl_try_from_upper_bounded!(usize => u8, u16); |
403 | impl_try_from_unbounded!(usize => u32, u64, u128); |
404 | impl_try_from_upper_bounded!(usize => i8, i16, i32); |
405 | impl_try_from_unbounded!(usize => i64, i128); |
406 | |
407 | impl_try_from_both_bounded!(isize => u8, u16); |
408 | impl_try_from_lower_bounded!(isize => u32, u64, u128); |
409 | impl_try_from_both_bounded!(isize => i8, i16); |
410 | impl_try_from_unbounded!(isize => i32, i64, i128); |
411 | |
412 | rev!(impl_try_from_unbounded, usize => u32); |
413 | rev!(impl_try_from_upper_bounded, usize => u64, u128); |
414 | rev!(impl_try_from_lower_bounded, usize => i8, i16, i32); |
415 | rev!(impl_try_from_both_bounded, usize => i64, i128); |
416 | |
417 | rev!(impl_try_from_unbounded, isize => u16); |
418 | rev!(impl_try_from_upper_bounded, isize => u32, u64, u128); |
419 | rev!(impl_try_from_unbounded, isize => i32); |
420 | rev!(impl_try_from_both_bounded, isize => i64, i128); |
421 | } |
422 | |
423 | #[cfg (target_pointer_width = "64" )] |
424 | mod ptr_try_from_impls { |
425 | use super::TryFromIntError; |
426 | |
427 | impl_try_from_upper_bounded!(usize => u8, u16, u32); |
428 | impl_try_from_unbounded!(usize => u64, u128); |
429 | impl_try_from_upper_bounded!(usize => i8, i16, i32, i64); |
430 | impl_try_from_unbounded!(usize => i128); |
431 | |
432 | impl_try_from_both_bounded!(isize => u8, u16, u32); |
433 | impl_try_from_lower_bounded!(isize => u64, u128); |
434 | impl_try_from_both_bounded!(isize => i8, i16, i32); |
435 | impl_try_from_unbounded!(isize => i64, i128); |
436 | |
437 | rev!(impl_try_from_unbounded, usize => u32, u64); |
438 | rev!(impl_try_from_upper_bounded, usize => u128); |
439 | rev!(impl_try_from_lower_bounded, usize => i8, i16, i32, i64); |
440 | rev!(impl_try_from_both_bounded, usize => i128); |
441 | |
442 | rev!(impl_try_from_unbounded, isize => u16, u32); |
443 | rev!(impl_try_from_upper_bounded, isize => u64, u128); |
444 | rev!(impl_try_from_unbounded, isize => i32, i64); |
445 | rev!(impl_try_from_both_bounded, isize => i128); |
446 | } |
447 | |
448 | // Conversion traits for non-zero integer types |
449 | use crate::num::NonZero; |
450 | |
451 | macro_rules! impl_nonzero_int_from_nonzero_int { |
452 | ($Small:ty => $Large:ty) => { |
453 | #[stable(feature = "nz_int_conv" , since = "1.41.0" )] |
454 | impl From<NonZero<$Small>> for NonZero<$Large> { |
455 | // Rustdocs on the impl block show a "[+] show undocumented items" toggle. |
456 | // Rustdocs on functions do not. |
457 | #[doc = concat!("Converts <code>[NonZero] \\<[" , stringify!($Small), "]></code> " )] |
458 | #[doc = concat!("to <code>[NonZero] \\<[" , stringify!($Large), "]></code> losslessly." )] |
459 | #[inline] |
460 | fn from(small: NonZero<$Small>) -> Self { |
461 | // SAFETY: input type guarantees the value is non-zero |
462 | unsafe { Self::new_unchecked(From::from(small.get())) } |
463 | } |
464 | } |
465 | }; |
466 | } |
467 | |
468 | // non-zero unsigned integer -> non-zero unsigned integer |
469 | impl_nonzero_int_from_nonzero_int!(u8 => u16); |
470 | impl_nonzero_int_from_nonzero_int!(u8 => u32); |
471 | impl_nonzero_int_from_nonzero_int!(u8 => u64); |
472 | impl_nonzero_int_from_nonzero_int!(u8 => u128); |
473 | impl_nonzero_int_from_nonzero_int!(u8 => usize); |
474 | impl_nonzero_int_from_nonzero_int!(u16 => u32); |
475 | impl_nonzero_int_from_nonzero_int!(u16 => u64); |
476 | impl_nonzero_int_from_nonzero_int!(u16 => u128); |
477 | impl_nonzero_int_from_nonzero_int!(u16 => usize); |
478 | impl_nonzero_int_from_nonzero_int!(u32 => u64); |
479 | impl_nonzero_int_from_nonzero_int!(u32 => u128); |
480 | impl_nonzero_int_from_nonzero_int!(u64 => u128); |
481 | |
482 | // non-zero signed integer -> non-zero signed integer |
483 | impl_nonzero_int_from_nonzero_int!(i8 => i16); |
484 | impl_nonzero_int_from_nonzero_int!(i8 => i32); |
485 | impl_nonzero_int_from_nonzero_int!(i8 => i64); |
486 | impl_nonzero_int_from_nonzero_int!(i8 => i128); |
487 | impl_nonzero_int_from_nonzero_int!(i8 => isize); |
488 | impl_nonzero_int_from_nonzero_int!(i16 => i32); |
489 | impl_nonzero_int_from_nonzero_int!(i16 => i64); |
490 | impl_nonzero_int_from_nonzero_int!(i16 => i128); |
491 | impl_nonzero_int_from_nonzero_int!(i16 => isize); |
492 | impl_nonzero_int_from_nonzero_int!(i32 => i64); |
493 | impl_nonzero_int_from_nonzero_int!(i32 => i128); |
494 | impl_nonzero_int_from_nonzero_int!(i64 => i128); |
495 | |
496 | // non-zero unsigned -> non-zero signed integer |
497 | impl_nonzero_int_from_nonzero_int!(u8 => i16); |
498 | impl_nonzero_int_from_nonzero_int!(u8 => i32); |
499 | impl_nonzero_int_from_nonzero_int!(u8 => i64); |
500 | impl_nonzero_int_from_nonzero_int!(u8 => i128); |
501 | impl_nonzero_int_from_nonzero_int!(u8 => isize); |
502 | impl_nonzero_int_from_nonzero_int!(u16 => i32); |
503 | impl_nonzero_int_from_nonzero_int!(u16 => i64); |
504 | impl_nonzero_int_from_nonzero_int!(u16 => i128); |
505 | impl_nonzero_int_from_nonzero_int!(u32 => i64); |
506 | impl_nonzero_int_from_nonzero_int!(u32 => i128); |
507 | impl_nonzero_int_from_nonzero_int!(u64 => i128); |
508 | |
509 | macro_rules! impl_nonzero_int_try_from_int { |
510 | ($Int:ty) => { |
511 | #[stable(feature = "nzint_try_from_int_conv" , since = "1.46.0" )] |
512 | impl TryFrom<$Int> for NonZero<$Int> { |
513 | type Error = TryFromIntError; |
514 | |
515 | // Rustdocs on the impl block show a "[+] show undocumented items" toggle. |
516 | // Rustdocs on functions do not. |
517 | #[doc = concat!("Attempts to convert [`" , stringify!($Int), "`] " )] |
518 | #[doc = concat!("to <code>[NonZero] \\<[" , stringify!($Int), "]></code>." )] |
519 | #[inline] |
520 | fn try_from(value: $Int) -> Result<Self, Self::Error> { |
521 | Self::new(value).ok_or(TryFromIntError(())) |
522 | } |
523 | } |
524 | }; |
525 | } |
526 | |
527 | // integer -> non-zero integer |
528 | impl_nonzero_int_try_from_int!(u8); |
529 | impl_nonzero_int_try_from_int!(u16); |
530 | impl_nonzero_int_try_from_int!(u32); |
531 | impl_nonzero_int_try_from_int!(u64); |
532 | impl_nonzero_int_try_from_int!(u128); |
533 | impl_nonzero_int_try_from_int!(usize); |
534 | impl_nonzero_int_try_from_int!(i8); |
535 | impl_nonzero_int_try_from_int!(i16); |
536 | impl_nonzero_int_try_from_int!(i32); |
537 | impl_nonzero_int_try_from_int!(i64); |
538 | impl_nonzero_int_try_from_int!(i128); |
539 | impl_nonzero_int_try_from_int!(isize); |
540 | |
541 | macro_rules! impl_nonzero_int_try_from_nonzero_int { |
542 | ($source:ty => $($target:ty),+) => {$( |
543 | #[stable(feature = "nzint_try_from_nzint_conv" , since = "1.49.0" )] |
544 | impl TryFrom<NonZero<$source>> for NonZero<$target> { |
545 | type Error = TryFromIntError; |
546 | |
547 | // Rustdocs on the impl block show a "[+] show undocumented items" toggle. |
548 | // Rustdocs on functions do not. |
549 | #[doc = concat!("Attempts to convert <code>[NonZero] \\<[" , stringify!($source), "]></code> " )] |
550 | #[doc = concat!("to <code>[NonZero] \\<[" , stringify!($target), "]></code>." )] |
551 | #[inline] |
552 | fn try_from(value: NonZero<$source>) -> Result<Self, Self::Error> { |
553 | // SAFETY: Input is guaranteed to be non-zero. |
554 | Ok(unsafe { Self::new_unchecked(<$target>::try_from(value.get())?) }) |
555 | } |
556 | } |
557 | )*}; |
558 | } |
559 | |
560 | // unsigned non-zero integer -> unsigned non-zero integer |
561 | impl_nonzero_int_try_from_nonzero_int!(u16 => u8); |
562 | impl_nonzero_int_try_from_nonzero_int!(u32 => u8, u16, usize); |
563 | impl_nonzero_int_try_from_nonzero_int!(u64 => u8, u16, u32, usize); |
564 | impl_nonzero_int_try_from_nonzero_int!(u128 => u8, u16, u32, u64, usize); |
565 | impl_nonzero_int_try_from_nonzero_int!(usize => u8, u16, u32, u64, u128); |
566 | |
567 | // signed non-zero integer -> signed non-zero integer |
568 | impl_nonzero_int_try_from_nonzero_int!(i16 => i8); |
569 | impl_nonzero_int_try_from_nonzero_int!(i32 => i8, i16, isize); |
570 | impl_nonzero_int_try_from_nonzero_int!(i64 => i8, i16, i32, isize); |
571 | impl_nonzero_int_try_from_nonzero_int!(i128 => i8, i16, i32, i64, isize); |
572 | impl_nonzero_int_try_from_nonzero_int!(isize => i8, i16, i32, i64, i128); |
573 | |
574 | // unsigned non-zero integer -> signed non-zero integer |
575 | impl_nonzero_int_try_from_nonzero_int!(u8 => i8); |
576 | impl_nonzero_int_try_from_nonzero_int!(u16 => i8, i16, isize); |
577 | impl_nonzero_int_try_from_nonzero_int!(u32 => i8, i16, i32, isize); |
578 | impl_nonzero_int_try_from_nonzero_int!(u64 => i8, i16, i32, i64, isize); |
579 | impl_nonzero_int_try_from_nonzero_int!(u128 => i8, i16, i32, i64, i128, isize); |
580 | impl_nonzero_int_try_from_nonzero_int!(usize => i8, i16, i32, i64, i128, isize); |
581 | |
582 | // signed non-zero integer -> unsigned non-zero integer |
583 | impl_nonzero_int_try_from_nonzero_int!(i8 => u8, u16, u32, u64, u128, usize); |
584 | impl_nonzero_int_try_from_nonzero_int!(i16 => u8, u16, u32, u64, u128, usize); |
585 | impl_nonzero_int_try_from_nonzero_int!(i32 => u8, u16, u32, u64, u128, usize); |
586 | impl_nonzero_int_try_from_nonzero_int!(i64 => u8, u16, u32, u64, u128, usize); |
587 | impl_nonzero_int_try_from_nonzero_int!(i128 => u8, u16, u32, u64, u128, usize); |
588 | impl_nonzero_int_try_from_nonzero_int!(isize => u8, u16, u32, u64, u128, usize); |
589 | |