1#![no_std]
2#![forbid(unsafe_code)]
3#![allow(clippy::doc_markdown)]
4#![doc = include_str!("../README.md")]
5#![allow(clippy::cast_possible_truncation)]
9#![allow(clippy::cast_possible_wrap)]
10
11#[cfg(any(feature = "min-usize-32", feature = "from_usize"))]
12macro_rules! assert_infallible_cast {
13 ($src:tt => $dst:tt) => {
14 const _: () = {
15 const SRC_BITS: u32 = $src::BITS;
16 const DST_BITS: u32 = $dst::BITS;
17 #[allow(clippy::cast_sign_loss)]
18 const SRC_SIGNED: bool = (-1_i8 as $src) < (0 as $src);
19 #[allow(clippy::cast_sign_loss)]
20 const DST_SIGNED: bool = (-1_i8 as $dst) < (0 as $dst);
21 assert!(match (SRC_SIGNED, DST_SIGNED) {
22 (false, false) => SRC_BITS <= DST_BITS,
23 (true, true) => SRC_BITS <= DST_BITS,
24 (false, true) => SRC_BITS < DST_BITS,
25 (true, false) => false,
26 });
27 };
28 };
29}
30
31#[cfg(feature = "min-usize-32")]
32pub trait ToUsize {
45 fn to_usize(self) -> usize;
46}
47
48#[cfg(feature = "min-usize-32")]
49pub trait ToIsize {
62 fn to_isize(self) -> isize;
63}
64
65#[cfg(feature = "from_usize")]
66pub trait ToU64 {
68 fn to_u64(self) -> u64;
69}
70
71#[cfg(feature = "from_usize")]
72pub trait ToI64 {
74 fn to_i64(self) -> i64;
75}
76
77#[cfg(feature = "from_usize")]
78pub trait ToU128 {
80 fn to_u128(self) -> u128;
81}
82
83#[cfg(feature = "from_usize")]
84pub trait ToI128 {
86 fn to_i128(self) -> i128;
87}
88
89#[cfg(feature = "min-usize-32")]
90macro_rules! impl_to_usize {
91 ($src:tt) => {
92 assert_infallible_cast!($src => usize);
93
94 impl ToUsize for $src {
95 #[inline]
96 fn to_usize(self) -> usize {
97 self as usize
98 }
99 }
100 };
101}
102
103#[cfg(feature = "min-usize-32")]
104macro_rules! impl_to_isize {
105 ($src:tt) => {
106 assert_infallible_cast!($src => isize);
107
108 impl ToIsize for $src {
109 #[inline]
110 fn to_isize(self) -> isize {
111 self as isize
112 }
113 }
114 };
115}
116
117#[cfg(feature = "min-usize-32")]
118macro_rules! impl_nonzero_usize {
119 ($($src:tt),* $(,)?) => {
120 $(
121 impl ToUsize for $src {
122 #[inline]
123 fn to_usize(self) -> usize {
124 self.get() as usize
125 }
126 }
127 )*
128 };
129}
130
131#[cfg(feature = "min-usize-32")]
132macro_rules! impl_nonzero_isize {
133 ($($src:ty),* $(,)?) => {
134 $(
135 impl ToIsize for $src {
136 #[inline]
137 fn to_isize(self) -> isize {
138 self.get() as isize
139 }
140 }
141 )*
142 };
143}
144
145#[cfg(feature = "min-usize-32")]
146impl ToUsize for usize {
147 #[inline]
148 fn to_usize(self) -> usize {
149 self
150 }
151}
152
153#[cfg(feature = "min-usize-32")]
154impl ToIsize for isize {
155 #[inline]
156 fn to_isize(self) -> isize {
157 self
158 }
159}
160
161#[cfg(feature = "min-usize-32")]
166mod ge32 {
167 #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
168 compile_error!("`min-usize-32` requires a target with at least 32-bit `usize`");
169
170 #[allow(clippy::wildcard_imports)]
171 use super::*;
172 use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU8, NonZeroU16, NonZeroU32};
173
174 impl_to_usize!(u8);
175 impl_to_usize!(u16);
176 impl_to_usize!(u32);
177
178 impl_to_isize!(u8);
179 impl_to_isize!(i8);
180 impl_to_isize!(u16);
181 impl_to_isize!(i16);
182 impl_to_isize!(i32);
183
184 impl_nonzero_usize!(NonZeroU8);
185 impl_nonzero_usize!(NonZeroU16);
186 impl_nonzero_usize!(NonZeroU32);
187
188 impl_nonzero_isize!(NonZeroU8);
189 impl_nonzero_isize!(NonZeroI8);
190 impl_nonzero_isize!(NonZeroU16);
191 impl_nonzero_isize!(NonZeroI16);
192 impl_nonzero_isize!(NonZeroI32);
193}
194
195#[cfg(feature = "min-usize-64")]
200mod ge64 {
201 #[cfg(not(target_pointer_width = "64"))]
202 compile_error!("`min-usize-64` requires a target with 64-bit `usize`");
203
204 #[allow(clippy::wildcard_imports)]
205 use super::*;
206 use core::num::{NonZeroI64, NonZeroU32, NonZeroU64};
207
208 impl_to_isize!(u32);
209 impl_to_usize!(u64);
210 impl_to_isize!(i64);
211
212 impl_nonzero_usize!(NonZeroU64);
213 impl_nonzero_isize!(NonZeroU32);
214 impl_nonzero_isize!(NonZeroI64);
215}
216
217#[cfg(feature = "from_usize")]
221mod from_usize_mod {
222 #[allow(clippy::wildcard_imports)]
223 use super::*;
224
225 assert_infallible_cast!(usize => u64);
226
227 impl ToU64 for usize {
228 #[inline]
229 fn to_u64(self) -> u64 {
230 self as u64
231 }
232 }
233
234 assert_infallible_cast!(usize => u128);
235
236 impl ToU128 for usize {
237 #[inline]
238 fn to_u128(self) -> u128 {
239 self as u128
240 }
241 }
242
243 assert_infallible_cast!(usize => i128);
244
245 impl ToI128 for usize {
246 #[inline]
247 fn to_i128(self) -> i128 {
248 self as i128
249 }
250 }
251
252 assert_infallible_cast!(isize => i64);
253
254 impl ToI64 for isize {
255 #[inline]
256 fn to_i64(self) -> i64 {
257 self as i64
258 }
259 }
260
261 assert_infallible_cast!(isize => i128);
262
263 impl ToI128 for isize {
264 #[inline]
265 fn to_i128(self) -> i128 {
266 self as i128
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 #[allow(clippy::wildcard_imports)]
274 use super::*;
275
276 #[cfg(feature = "min-usize-32")]
277 mod ge32 {
278 #[allow(clippy::wildcard_imports)]
279 use super::*;
280 use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU8, NonZeroU16, NonZeroU32};
281
282 #[test]
283 fn identity() {
284 assert_eq!(7usize.to_usize(), 7);
285 assert_eq!((-7isize).to_isize(), -7);
286 }
287
288 #[test]
289 fn basic() {
290 assert_eq!(123u8.to_usize(), 123);
292 assert_eq!(123u8.to_isize(), 123);
293 assert_eq!((-12i8).to_isize(), -12);
294
295 assert_eq!(123u16.to_usize(), 123);
297 assert_eq!(123u16.to_isize(), 123);
298 assert_eq!((-12i16).to_isize(), -12);
299
300 assert_eq!(456u32.to_usize(), 456);
302 assert_eq!((-456i32).to_isize(), -456);
303 }
304
305 #[test]
306 fn nonzero() {
307 let x = NonZeroU8::new(5).unwrap();
309 assert_eq!(x.to_usize(), 5);
310
311 let x = NonZeroU16::new(5).unwrap();
312 assert_eq!(x.to_usize(), 5);
313
314 let x = NonZeroU32::new(7).unwrap();
315 assert_eq!(x.to_usize(), 7);
316
317 let y = NonZeroI8::new(-5).unwrap();
319 assert_eq!(y.to_isize(), -5);
320
321 let y = NonZeroI16::new(-5).unwrap();
322 assert_eq!(y.to_isize(), -5);
323
324 let y = NonZeroI32::new(-7).unwrap();
325 assert_eq!(y.to_isize(), -7);
326
327 let x = NonZeroU8::new(5).unwrap();
329 assert_eq!(x.to_isize(), 5);
330
331 let x = NonZeroU16::new(5).unwrap();
332 assert_eq!(x.to_isize(), 5);
333 }
334 }
335
336 #[cfg(feature = "min-usize-64")]
337 mod ge64 {
338 #[allow(clippy::wildcard_imports)]
339 use super::*;
340 use core::num::{NonZeroI64, NonZeroU32, NonZeroU64};
341
342 #[test]
343 fn basic() {
344 assert_eq!(789u64.to_usize(), 789);
346
347 assert_eq!((-789i64).to_isize(), -789);
349
350 assert_eq!(456u32.to_isize(), 456);
352 }
353
354 #[test]
355 fn nonzero() {
356 let x = NonZeroU64::new(9).unwrap();
357 assert_eq!(x.to_usize(), 9);
358
359 let y = NonZeroI64::new(-9).unwrap();
360 assert_eq!(y.to_isize(), -9);
361
362 let x = NonZeroU32::new(7).unwrap();
364 assert_eq!(x.to_isize(), 7);
365 }
366 }
367
368 #[cfg(feature = "from_usize")]
369 #[test]
370 fn widening() {
371 assert_eq!(42usize.to_u64(), 42);
372 assert_eq!(42usize.to_u128(), 42);
373 assert_eq!(42usize.to_i128(), 42);
374
375 assert_eq!((-42isize).to_i64(), -42);
376 assert_eq!((-42isize).to_i128(), -42);
377 }
378}