wiwi/
num.rs

1use crate::prelude::*;
2use self::private::Sealed;
3
4macro_rules! from {
5	{
6		$losslessness:literal
7
8		$(#[$trait_meta:meta])*
9		trait $trait_name:ident
10
11		$(#[$fn_meta:meta])*
12		fn $fn_name:ident($type_name:ident)
13	} => {
14		#[doc = concat!(
15			"Trait for number types that can be converted from [`",
16			stringify!($type_name),
17			"`], ",
18			$losslessness
19		)]
20		#[doc = ""]
21		$(#[$trait_meta])*
22		pub trait $trait_name
23		where
24			Self: Sealed
25		{
26			#[doc = concat!("Convert from a [`", stringify!($type_name), "`] value")]
27			#[doc = ""]
28			$(#[$fn_meta])*
29			fn $fn_name(value: $type_name) -> Self;
30		}
31	};
32
33	{
34		impl $trait_name:ident::$fn_name:ident($type_name:ident)
35		$(
36			$(#[$meta:meta])*
37			$impl_type:ident
38		)*
39	} => {
40		$(
41			$(#[$meta])*
42			impl $trait_name for $impl_type {
43				#[expect(
44					clippy::as_conversions,
45					reason = "implementation detail of a more restrictive API"
46				)]
47				#[inline(always)]
48				fn $fn_name(value: $type_name) -> $impl_type { value as _ }
49			}
50		)*
51	};
52}
53
54macro_rules! into {
55	{
56		$losslessness:literal
57
58		$(#[$trait_meta:meta])*
59		trait $trait_name:ident
60
61		$(#[$fn_meta:meta])*
62		fn $fn_name:ident() -> $type_name:ident
63	} => {
64		#[doc = concat!(
65			"Trait for number types that can be converted into [`",
66			stringify!($type_name),
67			"`], ",
68			$losslessness
69		)]
70		#[doc = ""]
71		$(#[$trait_meta])*
72		pub trait $trait_name
73		where
74			Self: Sealed
75		{
76			#[doc = concat!("Convert into a [`", stringify!($type_name), "`] value")]
77			#[doc = ""]
78			$(#[$fn_meta])*
79			fn $fn_name(self) -> $type_name;
80		}
81	};
82
83	{
84		impl $trait_name:ident::$fn_name:ident() -> $type_name:ident
85		$(
86			$(#[$meta:meta])*
87			$impl_type:ident
88		)*
89	} => {
90		$(
91			$(#[$meta])*
92			impl $trait_name for $impl_type {
93				#[expect(
94					clippy::as_conversions,
95					reason = "implementation detail of a more restrictive API"
96				)]
97				#[inline(always)]
98				fn $fn_name(self) -> $type_name { self as _ }
99			}
100		)*
101	};
102}
103
104from! { "losslessly" trait FromU8 fn from_u8(u8) }
105from! { "losslessly" trait FromU16 fn from_u16(u16) }
106from! { "losslessly" trait FromU32 fn from_u32(u32) }
107from! { "losslessly" trait FromU64 fn from_u64(u64) }
108from! { "losslessly" trait FromU128 fn from_u128(u128) }
109from! { "losslessly" trait FromUsize fn from_usize(usize) }
110from! { "losslessly" trait FromI8 fn from_i8(i8) }
111from! { "losslessly" trait FromI16 fn from_i16(i16) }
112from! { "losslessly" trait FromI32 fn from_i32(i32) }
113from! { "losslessly" trait FromI64 fn from_i64(i64) }
114from! { "losslessly" trait FromI128 fn from_i128(i128) }
115from! { "losslessly" trait FromIsize fn from_isize(isize) }
116from! { "losslessly" trait FromF32 fn from_f32(f32) }
117from! { "losslessly" trait FromF64 fn from_f64(f64) }
118from! { "losslessly" trait FromBool fn from_bool(bool) }
119
120from! { "potentially lossily" trait FromU8Lossy fn from_u8_lossy(u8) }
121from! { "potentially lossily" trait FromU16Lossy fn from_u16_lossy(u16) }
122from! { "potentially lossily" trait FromU32Lossy fn from_u32_lossy(u32) }
123from! { "potentially lossily" trait FromU64Lossy fn from_u64_lossy(u64) }
124from! { "potentially lossily" trait FromU128Lossy fn from_u128_lossy(u128) }
125from! { "potentially lossily" trait FromUsizeLossy fn from_usize_lossy(usize) }
126from! { "potentially lossily" trait FromI8Lossy fn from_i8_lossy(i8) }
127from! { "potentially lossily" trait FromI16Lossy fn from_i16_lossy(i16) }
128from! { "potentially lossily" trait FromI32Lossy fn from_i32_lossy(i32) }
129from! { "potentially lossily" trait FromI64Lossy fn from_i64_lossy(i64) }
130from! { "potentially lossily" trait FromI128Lossy fn from_i128_lossy(i128) }
131from! { "potentially lossily" trait FromIsizeLossy fn from_isize_lossy(isize) }
132from! { "potentially lossily" trait FromF32Lossy fn from_f32_lossy(f32) }
133from! { "potentially lossily" trait FromF64Lossy fn from_f64_lossy(f64) }
134from! { "potentially lossily" trait FromBoolLossy fn from_bool_lossy(bool) }
135
136into! { "losslessly" trait IntoU8 fn into_u8() -> u8 }
137into! { "losslessly" trait IntoU16 fn into_u16() -> u16 }
138into! { "losslessly" trait IntoU32 fn into_u32() -> u32 }
139into! { "losslessly" trait IntoU64 fn into_u64() -> u64 }
140into! { "losslessly" trait IntoU128 fn into_u128() -> u128 }
141into! { "losslessly" trait IntoUsize fn into_usize() -> usize }
142into! { "losslessly" trait IntoI8 fn into_i8() -> i8 }
143into! { "losslessly" trait IntoI16 fn into_i16() -> i16 }
144into! { "losslessly" trait IntoI32 fn into_i32() -> i32 }
145into! { "losslessly" trait IntoI64 fn into_i64() -> i64 }
146into! { "losslessly" trait IntoI128 fn into_i128() -> i128 }
147into! { "losslessly" trait IntoIsize fn into_isize() -> isize }
148into! { "losslessly" trait IntoF32 fn into_f32() -> f32 }
149into! { "losslessly" trait IntoF64 fn into_f64() -> f64 }
150
151into! { "potentially lossily" trait IntoU8Lossy fn into_u8_lossy() -> u8 }
152into! { "potentially lossily" trait IntoU16Lossy fn into_u16_lossy() -> u16 }
153into! { "potentially lossily" trait IntoU32Lossy fn into_u32_lossy() -> u32 }
154into! { "potentially lossily" trait IntoU64Lossy fn into_u64_lossy() -> u64 }
155into! { "potentially lossily" trait IntoU128Lossy fn into_u128_lossy() -> u128 }
156into! { "potentially lossily" trait IntoUsizeLossy fn into_usize_lossy() -> usize }
157into! { "potentially lossily" trait IntoI8Lossy fn into_i8_lossy() -> i8 }
158into! { "potentially lossily" trait IntoI16Lossy fn into_i16_lossy() -> i16 }
159into! { "potentially lossily" trait IntoI32Lossy fn into_i32_lossy() -> i32 }
160into! { "potentially lossily" trait IntoI64Lossy fn into_i64_lossy() -> i64 }
161into! { "potentially lossily" trait IntoI128Lossy fn into_i128_lossy() -> i128 }
162into! { "potentially lossily" trait IntoIsizeLossy fn into_isize_lossy() -> isize }
163into! { "potentially lossily" trait IntoF32Lossy fn into_f32_lossy() -> f32 }
164into! { "potentially lossily" trait IntoF64Lossy fn into_f64_lossy() -> f64 }
165
166from! {
167	impl FromU8::from_u8(u8)
168	u8
169	u16 u32 u64 u128 usize
170	i16 i32 i64 i128 isize
171	f32 f64
172}
173
174from! {
175	impl FromU16::from_u16(u16)
176	u16
177	u32 u64 u128 usize
178	i32 i64 i128
179	#[cfg(any(
180		target_pointer_width = "32",
181		target_pointer_width = "64"
182	))]
183	isize
184	f32 f64
185}
186
187from! {
188	impl FromU32::from_u32(u32)
189	u32
190	u64 u128
191	#[cfg(any(
192		target_pointer_width = "32",
193		target_pointer_width = "64"
194	))]
195	usize
196	i64 i128
197	#[cfg(target_pointer_width = "64")]
198	isize
199	f64
200}
201
202from! {
203	impl FromU64::from_u64(u64)
204	u64
205	u128
206	#[cfg(target_pointer_width = "64")]
207	usize
208	i128
209}
210
211from! {
212	impl FromU128::from_u128(u128)
213	u128
214}
215
216from! {
217	impl FromUsize::from_usize(usize)
218	#[cfg(target_pointer_width = "16")]
219	u16
220	#[cfg(any(
221		target_pointer_width = "16",
222		target_pointer_width = "32"
223	))]
224	u32
225	u64 u128 usize
226	#[cfg(target_pointer_width = "16")]
227	i32
228	#[cfg(any(
229		target_pointer_width = "16",
230		target_pointer_width = "32"
231	))]
232	i64
233	i128
234	#[cfg(target_pointer_width = "16")]
235	f32
236	#[cfg(any(
237		target_pointer_width = "16",
238		target_pointer_width = "32"
239	))]
240	f64
241}
242
243from! {
244	impl FromI8::from_i8(i8)
245	i8
246	i16 i32 i64 i128 isize
247	f32 f64
248}
249
250from! {
251	impl FromI16::from_i16(i16)
252	i16
253	i32 i64 i128 isize
254	f32 f64
255}
256
257from! {
258	impl FromI32::from_i32(i32)
259	i32
260	i64 i128
261	#[cfg(any(
262		target_pointer_width = "32",
263		target_pointer_width = "64"
264	))]
265	isize
266	f64
267}
268
269from! {
270	impl FromI64::from_i64(i64)
271	i64
272	i128
273	#[cfg(target_pointer_width = "64")]
274	isize
275}
276
277from! {
278	impl FromI128::from_i128(i128)
279	i128
280}
281
282from! {
283	impl FromIsize::from_isize(isize)
284	#[cfg(target_pointer_width = "16")]
285	i16
286	#[cfg(any(
287		target_pointer_width = "16",
288		target_pointer_width = "32"
289	))]
290	i32
291	i64 i128 isize
292	#[cfg(target_pointer_width = "16")]
293	f32
294	#[cfg(any(
295		target_pointer_width = "16",
296		target_pointer_width = "32"
297	))]
298	f64
299}
300
301from! {
302	impl FromF32::from_f32(f32)
303	f32 f64
304}
305
306from! {
307	impl FromF64::from_f64(f64)
308	f64
309}
310
311from! {
312	impl FromBool::from_bool(bool)
313	u8 u16 u32 u64 u128 usize
314	i8 i16 i32 i64 i128 isize
315}
316
317impl FromBool for f32 {
318	#[expect(
319		clippy::as_conversions,
320		reason = "implementation detail of a more restrictive API"
321	)]
322	#[expect(
323		clippy::inline_always,
324		reason = "simple cast op"
325	)]
326	#[inline(always)]
327	// there is possibility for (micro)optimisation here...
328	// figure out which intermediate int type is best to cast to
329	fn from_bool(value: bool) -> f32 { value as u32 as _ }
330}
331
332impl FromBool for f64 {
333	#[expect(
334		clippy::as_conversions,
335		reason = "implementation detail of a more restrictive API"
336	)]
337	#[expect(
338		clippy::inline_always,
339		reason = "simple cast op"
340	)]
341	#[inline(always)]
342	// there is possibility for (micro)optimisation here...
343	// figure out which intermediate int type is best to cast to
344	fn from_bool(value: bool) -> f64 { value as u64 as _ }
345}
346
347from! {
348	impl FromU8Lossy::from_u8_lossy(u8)
349	u8 u16 u32 u64 u128 usize
350	i8 i16 i32 i64 i128 isize
351	f32 f64
352}
353
354from! {
355	impl FromU16Lossy::from_u16_lossy(u16)
356	u8 u16 u32 u64 u128 usize
357	i8 i16 i32 i64 i128 isize
358	f32 f64
359}
360
361from! {
362	impl FromU32Lossy::from_u32_lossy(u32)
363	u8 u16 u32 u64 u128 usize
364	i8 i16 i32 i64 i128 isize
365	f32 f64
366}
367
368from! {
369	impl FromU64Lossy::from_u64_lossy(u64)
370	u8 u16 u32 u64 u128 usize
371	i8 i16 i32 i64 i128 isize
372	f32 f64
373}
374
375from! {
376	impl FromU128Lossy::from_u128_lossy(u128)
377	u8 u16 u32 u64 u128 usize
378	i8 i16 i32 i64 i128 isize
379	f32 f64
380}
381
382from! {
383	impl FromUsizeLossy::from_usize_lossy(usize)
384	u8 u16 u32 u64 u128 usize
385	i8 i16 i32 i64 i128 isize
386	f32 f64
387}
388
389from! {
390	impl FromI8Lossy::from_i8_lossy(i8)
391	u8 u16 u32 u64 u128 usize
392	i8 i16 i32 i64 i128 isize
393	f32 f64
394}
395
396from! {
397	impl FromI16Lossy::from_i16_lossy(i16)
398	u8 u16 u32 u64 u128 usize
399	i8 i16 i32 i64 i128 isize
400	f32 f64
401}
402
403from! {
404	impl FromI32Lossy::from_i32_lossy(i32)
405	u8 u16 u32 u64 u128 usize
406	i8 i16 i32 i64 i128 isize
407	f32 f64
408}
409
410from! {
411	impl FromI64Lossy::from_i64_lossy(i64)
412	u8 u16 u32 u64 u128 usize
413	i8 i16 i32 i64 i128 isize
414	f32 f64
415}
416
417from! {
418	impl FromI128Lossy::from_i128_lossy(i128)
419	u8 u16 u32 u64 u128 usize
420	i8 i16 i32 i64 i128 isize
421	f32 f64
422}
423
424from! {
425	impl FromIsizeLossy::from_isize_lossy(isize)
426	u8 u16 u32 u64 u128 usize
427	i8 i16 i32 i64 i128 isize
428	f32 f64
429}
430
431from! {
432	impl FromF32Lossy::from_f32_lossy(f32)
433	u8 u16 u32 u64 u128 usize
434	i8 i16 i32 i64 i128 isize
435	f32 f64
436}
437
438from! {
439	impl FromF64Lossy::from_f64_lossy(f64)
440	u8 u16 u32 u64 u128 usize
441	i8 i16 i32 i64 i128 isize
442	f32 f64
443}
444
445from! {
446	impl FromBoolLossy::from_bool_lossy(bool)
447	u8 u16 u32 u64 u128 usize
448	i8 i16 i32 i64 i128 isize
449}
450
451impl FromBoolLossy for f32 {
452	#[expect(
453		clippy::as_conversions,
454		reason = "implementation detail of a more restrictive API"
455	)]
456	#[expect(
457		clippy::inline_always,
458		reason = "simple cast op"
459	)]
460	#[inline(always)]
461	// there is possibility for (micro)optimisation here...
462	// figure out which intermediate int type is best to cast to
463	fn from_bool_lossy(value: bool) -> f32 { value as u32 as _ }
464}
465
466impl FromBoolLossy for f64 {
467	#[expect(
468		clippy::as_conversions,
469		reason = "implementation detail of a more restrictive API"
470	)]
471	#[expect(
472		clippy::inline_always,
473		reason = "simple cast op"
474	)]
475	#[inline(always)]
476	// there is possibility for (micro)optimisation here...
477	// figure out which intermediate int type is best to cast to
478	fn from_bool_lossy(value: bool) -> f64 { value as u64 as _ }
479}
480
481into! {
482	impl IntoU8::into_u8() -> u8
483	u8
484	bool
485}
486
487into! {
488	impl IntoU16::into_u16() -> u16
489	u8 u16
490	#[cfg(target_pointer_width = "16")]
491	usize
492	bool
493}
494
495into! {
496	impl IntoU32::into_u32() -> u32
497	u8 u16 u32
498	#[cfg(any(
499		target_pointer_width = "16",
500		target_pointer_width = "32"
501	))]
502	usize
503	bool
504}
505
506into! {
507	impl IntoU64::into_u64() -> u64
508	u8 u16 u32 u64 usize
509	bool
510}
511
512into! {
513	impl IntoU128::into_u128() -> u128
514	u8 u16 u32 u64 u128 usize
515	bool
516}
517
518into! {
519	impl IntoUsize::into_usize() -> usize
520	u8 u16
521	#[cfg(any(
522		target_pointer_width = "32",
523		target_pointer_width = "64"
524	))]
525	u32
526	#[cfg(target_pointer_width = "64")]
527	u64
528	usize
529	bool
530}
531
532into! {
533	impl IntoI8::into_i8() -> i8
534	i8
535	bool
536}
537
538into! {
539	impl IntoI16::into_i16() -> i16
540	u8
541	i8 i16
542	#[cfg(target_pointer_width = "16")]
543	isize
544	bool
545}
546
547into! {
548	impl IntoI32::into_i32() -> i32
549	u8 u16
550	#[cfg(target_pointer_width = "16")]
551	usize
552	i8 i16 i32
553	#[cfg(any(
554		target_pointer_width = "16",
555		target_pointer_width = "32"
556	))]
557	isize
558	bool
559}
560
561into! {
562	impl IntoI64::into_i64() -> i64
563	u8 u16 u32
564	#[cfg(any(
565		target_pointer_width = "16",
566		target_pointer_width = "32"
567	))]
568	usize
569	i8 i16 i32 i64 isize
570	bool
571}
572
573into! {
574	impl IntoI128::into_i128() -> i128
575	u8 u16 u32 u64 usize
576	i8 i16 i32 i64 i128 isize
577	bool
578}
579
580into! {
581	impl IntoIsize::into_isize() -> isize
582	u8
583	#[cfg(any(
584		target_pointer_width = "32",
585		target_pointer_width = "64"
586	))]
587	u16
588	#[cfg(target_pointer_width = "64")]
589	u32
590	i8 i16
591	#[cfg(any(
592		target_pointer_width = "32",
593		target_pointer_width = "64"
594	))]
595	i32
596	#[cfg(target_pointer_width = "64")]
597	i64
598	isize
599	bool
600}
601
602into! {
603	impl IntoF32::into_f32() -> f32
604	u8 u16
605	#[cfg(target_pointer_width = "16")]
606	usize
607	i8 i16
608	#[cfg(target_pointer_width = "16")]
609	isize
610	f32
611}
612
613impl IntoF32 for bool {
614	#[expect(
615		clippy::as_conversions,
616		reason = "implementation detail of a more restrictive API"
617	)]
618	#[expect(
619		clippy::inline_always,
620		reason = "simple cast op"
621	)]
622	#[inline(always)]
623	fn into_f32(self) -> f32 { self as u32 as _ }
624}
625
626into! {
627	impl IntoF64::into_f64() -> f64
628	u8 u16 u32
629	#[cfg(any(
630		target_pointer_width = "16",
631		target_pointer_width = "32"
632	))]
633	usize
634	i8 i16 i32
635	#[cfg(any(
636		target_pointer_width = "16",
637		target_pointer_width = "32"
638	))]
639	isize
640	f32 f64
641}
642
643impl IntoF64 for bool {
644	#[expect(
645		clippy::as_conversions,
646		reason = "implementation detail of a more restrictive API"
647	)]
648	#[expect(
649		clippy::inline_always,
650		reason = "simple cast op"
651	)]
652	#[inline(always)]
653	// there is possibility for (micro)optimisation here...
654	// figure out which intermediate int type is best to cast to
655	fn into_f64(self) -> f64 { self as u64 as _ }
656}
657
658into! {
659	impl IntoU8Lossy::into_u8_lossy() -> u8
660	u8 u16 u32 u64 u128 usize
661	i8 i16 i32 i64 i128 isize
662	f32 f64
663	bool
664}
665
666into! {
667	impl IntoU16Lossy::into_u16_lossy() -> u16
668	u8 u16 u32 u64 u128 usize
669	i8 i16 i32 i64 i128 isize
670	f32 f64
671	bool
672}
673
674into! {
675	impl IntoU32Lossy::into_u32_lossy() -> u32
676	u8 u16 u32 u64 u128 usize
677	i8 i16 i32 i64 i128 isize
678	f32 f64
679	bool
680}
681
682into! {
683	impl IntoU64Lossy::into_u64_lossy() -> u64
684	u8 u16 u32 u64 u128 usize
685	i8 i16 i32 i64 i128 isize
686	f32 f64
687	bool
688}
689
690into! {
691	impl IntoU128Lossy::into_u128_lossy() -> u128
692	u8 u16 u32 u64 u128 usize
693	i8 i16 i32 i64 i128 isize
694	f32 f64
695	bool
696}
697
698into! {
699	impl IntoUsizeLossy::into_usize_lossy() -> usize
700	u8 u16 u32 u64 u128 usize
701	i8 i16 i32 i64 i128 isize
702	f32 f64
703	bool
704}
705
706into! {
707	impl IntoI8Lossy::into_i8_lossy() -> i8
708	u8 u16 u32 u64 u128 usize
709	i8 i16 i32 i64 i128 isize
710	f32 f64
711	bool
712}
713
714into! {
715	impl IntoI16Lossy::into_i16_lossy() -> i16
716	u8 u16 u32 u64 u128 usize
717	i8 i16 i32 i64 i128 isize
718	f32 f64
719	bool
720}
721
722into! {
723	impl IntoI32Lossy::into_i32_lossy() -> i32
724	u8 u16 u32 u64 u128 usize
725	i8 i16 i32 i64 i128 isize
726	f32 f64
727	bool
728}
729
730into! {
731	impl IntoI64Lossy::into_i64_lossy() -> i64
732	u8 u16 u32 u64 u128 usize
733	i8 i16 i32 i64 i128 isize
734	f32 f64
735	bool
736}
737
738into! {
739	impl IntoI128Lossy::into_i128_lossy() -> i128
740	u8 u16 u32 u64 u128 usize
741	i8 i16 i32 i64 i128 isize
742	f32 f64
743	bool
744}
745
746into! {
747	impl IntoIsizeLossy::into_isize_lossy() -> isize
748	u8 u16 u32 u64 u128 usize
749	i8 i16 i32 i64 i128 isize
750	f32 f64
751	bool
752}
753
754into! {
755	impl IntoF32Lossy::into_f32_lossy() -> f32
756	u8 u16 u32 u64 u128 usize
757	i8 i16 i32 i64 i128 isize
758	f32 f64
759}
760
761impl IntoF32Lossy for bool {
762	#[expect(
763		clippy::as_conversions,
764		reason = "implementation detail of a more restrictive API"
765	)]
766	#[expect(
767		clippy::inline_always,
768		reason = "simple cast op"
769	)]
770	#[inline(always)]
771	// there is possibility for (micro)optimisation here...
772	// figure out which intermediate int type is best to cast to
773	fn into_f32_lossy(self) -> f32 { self as u32 as _ }
774}
775
776into! {
777	impl IntoF64Lossy::into_f64_lossy() -> f64
778	u8 u16 u32 u64 u128 usize
779	i8 i16 i32 i64 i128 isize
780	f32 f64
781}
782
783impl IntoF64Lossy for bool {
784	#[expect(
785		clippy::as_conversions,
786		reason = "implementation detail of a more restrictive API"
787	)]
788	#[expect(
789		clippy::inline_always,
790		reason = "simple cast op"
791	)]
792	#[inline(always)]
793	fn into_f64_lossy(self) -> f64 { self as u64 as _ }
794}
795
796pub trait FromNum<Num>
797where
798	Self: Sealed
799{
800	fn from_num(num: Num) -> Self;
801}
802
803pub trait FromNumLossy<Num>
804where
805	Self: Sealed
806{
807	fn from_num_lossy(num: Num) -> Self;
808}
809
810pub trait IntoNum<Num>
811where
812	Self: Sealed
813{
814	fn into_num(self) -> Num;
815}
816
817pub trait IntoNumLossy<Num>
818where
819	Self: Sealed
820{
821	fn into_num_lossy(self) -> Num;
822}
823
824impl<NFrom, NInto> FromNumLossy<NFrom> for NInto
825where
826	NInto: FromNum<NFrom>
827{
828	#[inline]
829	fn from_num_lossy(num: NFrom) -> Self {
830		NInto::from_num(num)
831	}
832}
833
834impl<NFrom, NInto> IntoNum<NInto> for NFrom
835where
836	NFrom: Sealed,
837	NInto: FromNum<NFrom>
838{
839	#[inline]
840	fn into_num(self) -> NInto {
841		NInto::from_num(self)
842	}
843}
844
845impl<NFrom, NInto> IntoNumLossy<NInto> for NFrom
846where
847	NFrom: Sealed,
848	NInto: FromNumLossy<NFrom>
849{
850	#[inline]
851	fn into_num_lossy(self) -> NInto {
852		NInto::from_num_lossy(self)
853	}
854}
855
856macro_rules! impl_generic_num_conversions {
857	{
858		for $to:ident
859		lossless $trait_lossless:ident::$fn_lossless:ident
860		lossy $trait_lossy:ident::$fn_lossy:ident
861		$($(#[$meta:meta])* $from:ident $lossness:ident)*
862	} => {
863		$(
864			impl_generic_num_conversions! {
865				@impl
866				$trait_lossless $fn_lossless
867				$trait_lossy $fn_lossy
868				$(#[$meta])* $from $to $lossness
869			}
870		)*
871	};
872
873	{
874		@impl
875		$trait_lossless:ident $fn_lossless:ident
876		$trait_lossy:ident $fn_lossy:ident
877		$(#[$meta:meta])* $from:ident $to:ident lossless
878	} => {
879		impl_generic_num_conversions! {
880			@impl
881			$(#[$meta])* $from $to
882			FromNum from_num
883			$trait_lossless $fn_lossless
884		}
885	};
886
887	{
888		@impl
889		$trait_lossless:ident $fn_lossless:ident
890		$trait_lossy:ident $fn_lossy:ident
891		$(#[$meta:meta])* $from:ident $to:ident lossy
892	} => {
893		impl_generic_num_conversions! {
894			@impl
895			$(#[$meta])* $from $to
896			FromNumLossy from_num_lossy
897			$trait_lossy $fn_lossy
898		}
899	};
900
901	{
902		@impl
903		$(#[$meta:meta])*
904		$from:ident $to:ident
905		$generic_trait:ident $generic_fn:ident
906		$trait_name:ident $fn_name:ident
907	} => {
908		$(#[$meta])*
909		impl $generic_trait<$from> for $to {
910			#[inline(always)]
911			fn $generic_fn(num: $from) -> $to {
912				<$from as $trait_name>::$fn_name(num)
913			}
914		}
915	};
916}
917
918impl_generic_num_conversions! {
919	for u8
920	lossless IntoU8::into_u8
921	lossy IntoU8Lossy::into_u8_lossy
922
923	u8 lossless
924	u16 lossy
925	u32 lossy
926	u64 lossy
927	u128 lossy
928	usize lossy
929	i8 lossy
930	i16 lossy
931	i32 lossy
932	i64 lossy
933	i128 lossy
934	isize lossy
935	f32 lossy
936	f64 lossy
937	bool lossless
938}
939
940impl_generic_num_conversions! {
941	for u16
942	lossless IntoU16::into_u16
943	lossy IntoU16Lossy::into_u16_lossy
944
945	u8 lossless
946	u16 lossless
947	u32 lossy
948	u64 lossy
949	u128 lossy
950	#[cfg(target_pointer_width = "16")]
951	usize lossless
952	#[cfg(any(
953		target_pointer_width = "32",
954		target_pointer_width = "64"
955	))]
956	usize lossy
957	i8 lossy
958	i16 lossy
959	i32 lossy
960	i64 lossy
961	i128 lossy
962	isize lossy
963	f32 lossy
964	f64 lossy
965	bool lossless
966}
967
968impl_generic_num_conversions! {
969	for u32
970	lossless IntoU32::into_u32
971	lossy IntoU32Lossy::into_u32_lossy
972
973	u8 lossless
974	u16 lossless
975	u32 lossless
976	u64 lossy
977	u128 lossy
978	#[cfg(any(
979		target_pointer_width = "16",
980		target_pointer_width = "32"
981	))]
982	usize lossless
983	#[cfg(target_pointer_width = "64")]
984	usize lossy
985	i8 lossy
986	i16 lossy
987	i32 lossy
988	i64 lossy
989	i128 lossy
990	isize lossy
991	f32 lossy
992	f64 lossy
993	bool lossless
994}
995
996impl_generic_num_conversions! {
997	for u64
998	lossless IntoU64::into_u64
999	lossy IntoU64Lossy::into_u64_lossy
1000
1001	u8 lossless
1002	u16 lossless
1003	u32 lossless
1004	u64 lossless
1005	u128 lossy
1006	usize lossless
1007	i8 lossy
1008	i16 lossy
1009	i32 lossy
1010	i64 lossy
1011	i128 lossy
1012	isize lossy
1013	f32 lossy
1014	f64 lossy
1015	bool lossless
1016}
1017
1018impl_generic_num_conversions! {
1019	for u128
1020	lossless IntoU128::into_u128
1021	lossy IntoU128Lossy::into_u128_lossy
1022
1023	u8 lossless
1024	u16 lossless
1025	u32 lossless
1026	u64 lossless
1027	u128 lossless
1028	usize lossless
1029	i8 lossy
1030	i16 lossy
1031	i32 lossy
1032	i64 lossy
1033	i128 lossy
1034	isize lossy
1035	f32 lossy
1036	f64 lossy
1037	bool lossless
1038}
1039
1040impl_generic_num_conversions! {
1041	for usize
1042	lossless IntoUsize::into_usize
1043	lossy IntoUsizeLossy::into_usize_lossy
1044
1045	u8 lossless
1046	u16 lossless
1047	#[cfg(target_pointer_width = "16")]
1048	u32 lossy
1049	#[cfg(any(
1050		target_pointer_width = "32",
1051		target_pointer_width = "64"
1052	))]
1053	u32 lossless
1054	#[cfg(any(
1055		target_pointer_width = "16",
1056		target_pointer_width = "32"
1057	))]
1058	u64 lossy
1059	#[cfg(target_pointer_width = "64")]
1060	u64 lossless
1061	u128 lossy
1062	usize lossless
1063	i8 lossy
1064	i16 lossy
1065	i32 lossy
1066	i64 lossy
1067	i128 lossy
1068	isize lossy
1069	f32 lossy
1070	f64 lossy
1071	bool lossless
1072}
1073
1074impl_generic_num_conversions! {
1075	for i8
1076	lossless IntoI8::into_i8
1077	lossy IntoI8Lossy::into_i8_lossy
1078
1079	u8 lossy
1080	u16 lossy
1081	u32 lossy
1082	u64 lossy
1083	u128 lossy
1084	usize lossy
1085	i8 lossless
1086	i16 lossy
1087	i32 lossy
1088	i64 lossy
1089	i128 lossy
1090	isize lossy
1091	f32 lossy
1092	f64 lossy
1093	bool lossless
1094}
1095
1096impl_generic_num_conversions! {
1097	for i16
1098	lossless IntoI16::into_i16
1099	lossy IntoI16Lossy::into_i16_lossy
1100
1101	u8 lossless
1102	u16 lossy
1103	u32 lossy
1104	u64 lossy
1105	u128 lossy
1106	usize lossy
1107	i8 lossless
1108	i16 lossless
1109	i32 lossy
1110	i64 lossy
1111	i128 lossy
1112	#[cfg(target_pointer_width = "16")]
1113	isize lossless
1114	#[cfg(any(
1115		target_pointer_width = "32",
1116		target_pointer_width = "64"
1117	))]
1118	isize lossy
1119	f32 lossy
1120	f64 lossy
1121	bool lossless
1122}
1123
1124impl_generic_num_conversions! {
1125	for i32
1126	lossless IntoI32::into_i32
1127	lossy IntoI32Lossy::into_i32_lossy
1128
1129	u8 lossless
1130	u16 lossless
1131	u32 lossy
1132	u64 lossy
1133	u128 lossy
1134	#[cfg(target_pointer_width = "16")]
1135	usize lossless
1136	#[cfg(any(
1137		target_pointer_width = "32",
1138		target_pointer_width = "64"
1139	))]
1140	usize lossy
1141	i8 lossless
1142	i16 lossless
1143	i32 lossless
1144	i64 lossy
1145	i128 lossy
1146	#[cfg(any(
1147		target_pointer_width = "16",
1148		target_pointer_width = "32"
1149	))]
1150	isize lossless
1151	#[cfg(target_pointer_width = "64")]
1152	isize lossy
1153	f32 lossy
1154	f64 lossy
1155	bool lossless
1156}
1157
1158impl_generic_num_conversions! {
1159	for i64
1160	lossless IntoI64::into_i64
1161	lossy IntoI64Lossy::into_i64_lossy
1162
1163	u8 lossless
1164	u16 lossless
1165	u32 lossless
1166	u64 lossy
1167	u128 lossy
1168	#[cfg(any(
1169		target_pointer_width = "16",
1170		target_pointer_width = "32"
1171	))]
1172	usize lossless
1173	#[cfg(target_pointer_width = "64")]
1174	usize lossy
1175	i8 lossless
1176	i16 lossless
1177	i32 lossless
1178	i64 lossless
1179	i128 lossy
1180	isize lossless
1181	f32 lossy
1182	f64 lossy
1183	bool lossless
1184}
1185
1186impl_generic_num_conversions! {
1187	for i128
1188	lossless IntoI128::into_i128
1189	lossy IntoI128Lossy::into_i128_lossy
1190
1191	u8 lossless
1192	u16 lossless
1193	u32 lossless
1194	u64 lossless
1195	u128 lossy
1196	usize lossless
1197	i8 lossless
1198	i16 lossless
1199	i32 lossless
1200	i64 lossless
1201	i128 lossless
1202	isize lossless
1203	f32 lossy
1204	f64 lossy
1205	bool lossless
1206}
1207
1208impl_generic_num_conversions! {
1209	for isize
1210	lossless IntoIsize::into_isize
1211	lossy IntoIsizeLossy::into_isize_lossy
1212
1213	u8 lossless
1214	#[cfg(target_pointer_width = "16")]
1215	u16 lossy
1216	#[cfg(any(
1217		target_pointer_width = "32",
1218		target_pointer_width = "64"
1219	))]
1220	u16 lossless
1221	#[cfg(any(
1222		target_pointer_width = "16",
1223		target_pointer_width = "32"
1224	))]
1225	u32 lossy
1226	#[cfg(target_pointer_width = "64")]
1227	u32 lossless
1228	u64 lossy
1229	u128 lossy
1230	usize lossy
1231	i8 lossless
1232	i16 lossless
1233	#[cfg(target_pointer_width = "16")]
1234	i32 lossy
1235	#[cfg(any(
1236		target_pointer_width = "32",
1237		target_pointer_width = "64"
1238	))]
1239	i32 lossless
1240	#[cfg(any(
1241		target_pointer_width = "16",
1242		target_pointer_width = "32"
1243	))]
1244	i64 lossy
1245	#[cfg(target_pointer_width = "64")]
1246	i64 lossless
1247	i128 lossy
1248	isize lossless
1249	f32 lossy
1250	f64 lossy
1251	bool lossless
1252}
1253
1254impl_generic_num_conversions! {
1255	for f32
1256	lossless IntoF32::into_f32
1257	lossy IntoF32Lossy::into_f32_lossy
1258
1259	u8 lossless
1260	u16 lossless
1261	u32 lossy
1262	u64 lossy
1263	u128 lossy
1264	usize lossy
1265	i8 lossless
1266	i16 lossless
1267	i32 lossy
1268	i64 lossy
1269	i128 lossy
1270	isize lossy
1271	f32 lossless
1272	f64 lossy
1273	bool lossless
1274}
1275
1276impl_generic_num_conversions! {
1277	for f64
1278	lossless IntoF64::into_f64
1279	lossy IntoF64Lossy::into_f64_lossy
1280
1281	u8 lossless
1282	u16 lossless
1283	u32 lossless
1284	u64 lossy
1285	u128 lossy
1286	usize lossy
1287	i8 lossless
1288	i16 lossless
1289	i32 lossless
1290	i64 lossy
1291	i128 lossy
1292	isize lossy
1293	f32 lossless
1294	f64 lossless
1295	bool lossless
1296}
1297
1298pub trait ArrayConversions<const N: usize>
1299where
1300	Self: Sealed
1301{
1302	fn into_le_bytes(self) -> [u8; N];
1303	fn into_be_bytes(self) -> [u8; N];
1304	fn into_ne_bytes(self) -> [u8; N];
1305	fn from_le_bytes(bytes: [u8; N]) -> Self;
1306	fn from_be_bytes(bytes: [u8; N]) -> Self;
1307	fn from_ne_bytes(bytes: [u8; N]) -> Self;
1308}
1309
1310macro_rules! impl_array_conversions {
1311	{ $($(#[$meta:meta])* $num:ident $bytes:literal)* } => {
1312		$(
1313			$(#[$meta])*
1314			impl ArrayConversions<$bytes> for $num {
1315				#[inline(always)]
1316				fn into_le_bytes(self) -> [u8; $bytes] { $num::to_le_bytes(self) }
1317
1318				#[inline(always)]
1319				fn into_be_bytes(self) -> [u8; $bytes] { $num::to_be_bytes(self) }
1320
1321				#[inline(always)]
1322				fn into_ne_bytes(self) -> [u8; $bytes] { $num::to_ne_bytes(self) }
1323
1324				#[inline(always)]
1325				fn from_le_bytes(bytes: [u8; $bytes]) -> $num { $num::from_le_bytes(bytes) }
1326
1327				#[inline(always)]
1328				fn from_be_bytes(bytes: [u8; $bytes]) -> $num { $num::from_be_bytes(bytes) }
1329
1330				#[inline(always)]
1331				fn from_ne_bytes(bytes: [u8; $bytes]) -> $num { $num::from_ne_bytes(bytes) }
1332			}
1333		)*
1334	}
1335}
1336
1337impl_array_conversions! {
1338	u8 1
1339	u16 2
1340	u32 4
1341	u64 8
1342	u128 16
1343
1344	i8 1
1345	i16 2
1346	i32 4
1347	i64 8
1348	i128 16
1349
1350	f32 4
1351	f64 8
1352
1353	#[cfg(target_pointer_width = "16")]
1354	usize 2
1355	#[cfg(target_pointer_width = "16")]
1356	isize 2
1357
1358	#[cfg(target_pointer_width = "32")]
1359	usize 4
1360	#[cfg(target_pointer_width = "32")]
1361	isize 4
1362
1363	#[cfg(target_pointer_width = "64")]
1364	usize 8
1365	#[cfg(target_pointer_width = "64")]
1366	isize 8
1367}
1368
1369pub trait Endian<Num, const N: usize>
1370where
1371	Self: Sealed,
1372	Num: ArrayConversions<N>
1373{
1374	fn from_bytes(bytes: [u8; N]) -> Num;
1375	fn into_bytes(num: Num) -> [u8; N];
1376}
1377
1378macro_rules! decl_endian_structs {
1379	{ $($endian_str:literal $struct:ident $from:ident $into:ident)* } => {
1380		$(
1381			/// Implements [`Endian`] trait and provides
1382			#[doc = $endian_str]
1383			/// conversions between numbers and arrays
1384			pub struct $struct {
1385				__private: ()
1386			}
1387
1388			impl Sealed for $struct {}
1389
1390			impl<Num, const N: usize> Endian<Num, N> for $struct
1391			where
1392				Num: ArrayConversions<N>
1393			{
1394				#[inline]
1395				fn from_bytes(bytes: [u8; N]) -> Num {
1396					Num::$from(bytes)
1397				}
1398
1399				#[inline]
1400				fn into_bytes(num: Num) -> [u8; N] {
1401					Num::$into(num)
1402				}
1403			}
1404		)*
1405	}
1406}
1407
1408decl_endian_structs! {
1409	"little endian" EndianLittle from_le_bytes into_le_bytes
1410	"big endian" EndianBig from_be_bytes into_be_bytes
1411	"native endian" EndianNative from_ne_bytes into_ne_bytes
1412}
1413
1414pub trait IntSignedness
1415where
1416	Self: Sealed
1417{
1418	const SIGNED: bool;
1419}
1420
1421macro_rules! impl_int_signedness {
1422	{ $($int:ident $signed:literal)* } => {
1423		$(
1424			impl IntSignedness for $int {
1425				const SIGNED: bool = $signed;
1426			}
1427		)*
1428	}
1429}
1430
1431impl_int_signedness! {
1432	u8 false
1433	u16 false
1434	u32 false
1435	u64 false
1436	u128 false
1437	usize false
1438	i8 true
1439	i16 true
1440	i32 true
1441	i64 true
1442	i128 true
1443	isize true
1444}
1445
1446pub trait IntUnsigned
1447where
1448	Self: Sealed,
1449	Self::Signed: IntSigned<Unsigned = Self>
1450{
1451	type Signed;
1452
1453	fn into_signed(self) -> Self::Signed;
1454}
1455
1456pub trait IntSigned
1457where
1458	Self: Sealed,
1459	Self::Unsigned: IntUnsigned<Signed = Self>
1460{
1461	type Unsigned;
1462
1463	fn into_unsigned(self) -> Self::Unsigned;
1464}
1465
1466macro_rules! impl_int_signed_and_unsigned {
1467	{ $($unsigned:ident $signed:ident)* } => {
1468		$(
1469			impl IntUnsigned for $unsigned {
1470				type Signed = $signed;
1471
1472				#[expect(
1473					clippy::as_conversions,
1474					reason = "implementation detail of a more restrictive API"
1475				)]
1476				#[inline(always)]
1477				fn into_signed(self) -> $signed { self as _ }
1478			}
1479
1480			impl IntSigned for $signed {
1481				type Unsigned = $unsigned;
1482
1483				#[expect(
1484					clippy::as_conversions,
1485					reason = "implementation detail of a more restrictive API"
1486				)]
1487				#[inline(always)]
1488				fn into_unsigned(self) -> $unsigned { self as _ }
1489			}
1490		)*
1491	}
1492}
1493
1494impl_int_signed_and_unsigned! {
1495	u8 i8
1496	u16 i16
1497	u32 i32
1498	u64 i64
1499	u128 i128
1500	usize isize
1501}
1502
1503macro_rules! op_trait {
1504	{
1505		$(#[$trait_meta:meta])*
1506		trait $trait_name:ident
1507		$(#[$fn_meta:meta])*
1508		fn $fn_name:ident(rhs)
1509		$(
1510			$(#[$output_meta:meta])*
1511			type Output
1512		)?
1513	} => {
1514		$(#[$trait_meta])*
1515		pub trait $trait_name<R>
1516		where
1517			Self: Sealed,
1518			R: Sealed
1519		{
1520			$($(#[$output_meta])*)?
1521			type Output;
1522
1523			$(#[$fn_meta])*
1524			fn $fn_name(self, rhs: R) -> Self::Output;
1525		}
1526	};
1527
1528	{
1529		$(#[$trait_meta:meta])*
1530		trait $trait_name:ident
1531		$(#[$fn_meta:meta])*
1532		fn $fn_name:ident()
1533		$(
1534			$(#[$output_meta:meta])*
1535			type Output
1536		)?
1537	} => {
1538		$(#[$trait_meta])*
1539		pub trait $trait_name
1540		where
1541			Self: Sealed
1542		{
1543			$($(#[$output_meta])*)?
1544			type Output;
1545
1546			$(#[$fn_meta])*
1547			fn $fn_name(self) -> Self::Output;
1548		}
1549	};
1550
1551	{
1552		$(#[$trait_meta:meta])*
1553		trait(option) $trait_name:ident
1554		$(#[$fn_meta:meta])*
1555		fn $fn_name:ident(rhs)
1556		$(
1557			$(#[$output_meta:meta])*
1558			type Output
1559		)?
1560	} => {
1561		$(#[$trait_meta])*
1562		pub trait $trait_name<R>
1563		where
1564			Self: Sealed,
1565			R: Sealed
1566		{
1567			$($(#[$output_meta])*)?
1568			type Output;
1569
1570			$(#[$fn_meta])*
1571			fn $fn_name(self, rhs: R) -> Option<Self::Output>;
1572		}
1573	};
1574
1575	{
1576		$(#[$trait_meta:meta])*
1577		trait(option) $trait_name:ident
1578		$(#[$fn_meta:meta])*
1579		fn $fn_name:ident()
1580		$(
1581			$(#[$output_meta:meta])*
1582			type Output
1583		)?
1584	} => {
1585		$(#[$trait_meta])*
1586		pub trait $trait_name
1587		where
1588			Self: Sealed
1589		{
1590			$($(#[$output_meta])*)?
1591			type Output;
1592
1593			$(#[$fn_meta])*
1594			fn $fn_name(self) -> Option<Self::Output>;
1595		}
1596	};
1597
1598	{
1599		$(#[$trait_meta:meta])*
1600		trait(tuple) $trait_name:ident
1601		$(#[$fn_meta:meta])*
1602		fn $fn_name:ident(rhs)
1603		$(
1604			$(#[$output_meta:meta])*
1605			type Output
1606		)?
1607	} => {
1608		$(#[$trait_meta])*
1609		pub trait $trait_name<R>
1610		where
1611			Self: Sealed,
1612			R: Sealed
1613		{
1614			$($(#[$output_meta])*)?
1615			type Output;
1616
1617			$(#[$fn_meta])*
1618			fn $fn_name(self, rhs: R) -> (Self::Output, bool);
1619		}
1620	};
1621
1622	{
1623		$(#[$trait_meta:meta])*
1624		trait(tuple) $trait_name:ident
1625		$(#[$fn_meta:meta])*
1626		fn $fn_name:ident()
1627		$(
1628			$(#[$output_meta:meta])*
1629			type Output
1630		)?
1631	} => {
1632		$(#[$trait_meta])*
1633		pub trait $trait_name
1634		where
1635			Self: Sealed
1636		{
1637			$($(#[$output_meta])*)?
1638			type Output;
1639
1640			$(#[$fn_meta])*
1641			fn $fn_name(self) -> (Self::Output, bool);
1642		}
1643	};
1644
1645	{
1646		$(#[$trait_meta:meta])*
1647		trait(unsafe) $trait_name:ident
1648		$(#[$fn_meta:meta])*
1649		fn $fn_name:ident(rhs)
1650		$(
1651			$(#[$output_meta:meta])*
1652			type Output
1653		)?
1654	} => {
1655		$(#[$trait_meta])*
1656		pub trait $trait_name<R>
1657		where
1658			Self: Sealed,
1659			R: Sealed
1660		{
1661			$($(#[$output_meta])*)?
1662			type Output;
1663
1664			$(#[$fn_meta])*
1665			/// # Safety
1666			///
1667			/// TODO (also remove me from here (definition)
1668			/// and write it in the macro invocation)
1669			unsafe fn $fn_name(self, rhs: R) -> Self::Output;
1670		}
1671	};
1672
1673	{
1674		$(#[$trait_meta:meta])*
1675		trait(unsafe) $trait_name:ident
1676		$(#[$fn_meta:meta])*
1677		fn $fn_name:ident()
1678		$(
1679			$(#[$output_meta:meta])*
1680			type Output
1681		)?
1682	} => {
1683		$(#[$trait_meta])*
1684		pub trait $trait_name
1685		where
1686			Self: Sealed
1687		{
1688			$($(#[$output_meta])*)?
1689			type Output;
1690
1691			$(#[$fn_meta])*
1692			/// # Safety
1693			///
1694			/// TODO (also remove me from here (definition)
1695			/// and write it in the macro invocation)
1696			unsafe fn $fn_name(self) -> Self::Output;
1697		}
1698	};
1699
1700	{
1701		impl
1702		$(
1703			$lhs:ident: $lhs_ty:ident { $($lhs_stuff:tt)* }
1704		)*
1705	} => {
1706		$(
1707			op_trait! {
1708				impl(lhs_stuff)
1709				$lhs $lhs_ty $($lhs_stuff)*
1710			}
1711		)*
1712	};
1713
1714	{
1715		impl(lhs_stuff)
1716		$lhs:ident $lhs_ty:ident
1717		$rhs:ident: $rhs_ty:ident { $($rhs_stuff:tt)* }
1718		$($rest:tt)*
1719	} => {
1720		op_trait! {
1721			impl(rhs_stuff)
1722			$lhs $lhs_ty
1723			$rhs $rhs_ty
1724			$($rhs_stuff)*
1725		}
1726		op_trait! {
1727			impl(lhs_stuff)
1728			$lhs $lhs_ty
1729			$($rest)*
1730		}
1731	};
1732
1733	{
1734		impl(lhs_stuff)
1735		$lhs:ident $lhs_ty:ident
1736		$(#[$meta:meta])*
1737		$op:ident -> $output_ty:ident { $($body:tt)* }
1738		$($rest:tt)*
1739	} => {
1740		op_trait! {
1741			impl(helper_lhs)
1742			$op
1743			$(#[$meta])*
1744			$lhs $lhs_ty
1745			$output_ty
1746			$($body)*
1747		}
1748		op_trait! {
1749			impl(lhs_stuff)
1750			$lhs $lhs_ty
1751			$($rest)*
1752		}
1753	};
1754
1755	{
1756		impl(lhs_stuff)
1757		$lhs:ident $lhs_ty:ident
1758	} => {};
1759
1760	{
1761		impl(rhs_stuff)
1762		$lhs:ident $lhs_ty:ident
1763		$rhs:ident $rhs_ty:ident
1764		$(#[$meta:meta])*
1765		$op:ident -> $output_ty:ident { $($body:tt)* }
1766		$($rest:tt)*
1767	} => {
1768		op_trait! {
1769			impl(helper_rhs)
1770			$op
1771			$(#[$meta])*
1772			$lhs $lhs_ty
1773			$rhs $rhs_ty
1774			$output_ty
1775			$($body)*
1776		}
1777		op_trait! {
1778			impl(rhs_stuff)
1779			$lhs $lhs_ty
1780			$rhs $rhs_ty
1781			$($rest)*
1782		}
1783	};
1784
1785	{
1786		impl(rhs_stuff)
1787		$lhs:ident $lhs_ty:ident
1788		$rhs:ident $rhs_ty:ident
1789	} => {};
1790
1791	{
1792		impl(normal)
1793		$trait_name:ident $fn_name:ident
1794		$(#[$meta:meta])*
1795		$lhs:ident $lhs_ty:ident
1796		$rhs:ident $rhs_ty:ident
1797		$output_ty:ident
1798		$($body:tt)*
1799	} => {
1800		$(#[$meta])*
1801		impl $trait_name<$rhs_ty> for $lhs_ty {
1802			type Output = $output_ty;
1803
1804			#[inline(always)]
1805			fn $fn_name(self, rhs: $rhs_ty) -> $output_ty {
1806				#[inline(always)]
1807				fn inner($lhs: $lhs_ty, $rhs: $rhs_ty) -> $output_ty {
1808					$($body)*
1809				}
1810
1811				inner(self, rhs)
1812			}
1813		}
1814	};
1815
1816	{
1817		impl(normal1)
1818		$trait_name:ident $fn_name:ident
1819		$(#[$meta:meta])*
1820		$lhs:ident $lhs_ty:ident
1821		$output_ty:ident
1822		$($body:tt)*
1823	} => {
1824		$(#[$meta])*
1825		impl $trait_name for $lhs_ty {
1826			type Output = $output_ty;
1827
1828			#[inline(always)]
1829			fn $fn_name(self) -> $output_ty {
1830				#[inline(always)]
1831				fn inner($lhs: $lhs_ty) -> $output_ty {
1832					$($body)*
1833				}
1834
1835				inner(self)
1836			}
1837		}
1838	};
1839
1840	{ impl(helper_rhs) add $($stuff:tt)* } => { op_trait! { impl(normal) Add add $($stuff)* } };
1841	{ impl(helper_rhs) sub $($stuff:tt)* } => { op_trait! { impl(normal) Sub sub $($stuff)* } };
1842	{ impl(helper_rhs) mul $($stuff:tt)* } => { op_trait! { impl(normal) Mul mul $($stuff)* } };
1843	{ impl(helper_rhs) div $($stuff:tt)* } => { op_trait! { impl(normal) Div div $($stuff)* } };
1844	{ impl(helper_lhs) neg $($stuff:tt)* } => { op_trait! { impl(normal1) Neg neg $($stuff)* } };
1845}
1846
1847op_trait! { trait Add fn add(rhs) }
1848op_trait! { trait Sub fn sub(rhs) }
1849op_trait! { trait Mul fn mul(rhs) }
1850op_trait! { trait Div fn div(rhs) }
1851op_trait! { trait Neg fn neg() }
1852
1853op_trait! { trait(option) AddChecked fn add_checked(rhs) }
1854op_trait! { trait(option) SubChecked fn sub_checked(rhs) }
1855op_trait! { trait(option) MulChecked fn mul_checked(rhs) }
1856op_trait! { trait(option) DivChecked fn div_checked(rhs) }
1857op_trait! { trait(option) NegChecked fn neg_checked() }
1858
1859op_trait! { trait(tuple) AddOverflowing fn add_overflowing(rhs) }
1860op_trait! { trait(tuple) SubOverflowing fn sub_overflowing(rhs) }
1861op_trait! { trait(tuple) MulOverflowing fn mul_overflowing(rhs) }
1862op_trait! { trait(tuple) DivOverflowing fn div_overflowing(rhs) }
1863op_trait! { trait(tuple) NegOverflowing fn neg_overflowing() }
1864
1865op_trait! { trait AddSaturating fn add_saturating(rhs) }
1866op_trait! { trait SubSaturating fn sub_saturating(rhs) }
1867op_trait! { trait MulSaturating fn mul_saturating(rhs) }
1868op_trait! { trait DivSaturating fn div_saturating(rhs) }
1869op_trait! { trait NegSaturating fn neg_saturating() }
1870
1871// // TODO: strict op?
1872// // TODO: unbounded shifts?
1873
1874op_trait! { trait(unsafe) AddUnchecked fn add_unchecked(rhs) }
1875op_trait! { trait(unsafe) SubUnchecked fn sub_unchecked(rhs) }
1876op_trait! { trait(unsafe) MulUnchecked fn mul_unchecked(rhs) }
1877op_trait! { trait(unsafe) DivUnchecked fn div_unchecked(rhs) }
1878op_trait! { trait(unsafe) NegUnchecked fn neg_unchecked() }
1879
1880op_trait! { trait AddWrapping fn add_wrapping(rhs) }
1881op_trait! { trait SubWrapping fn sub_wrapping(rhs) }
1882op_trait! { trait MulWrapping fn mul_wrapping(rhs) }
1883op_trait! { trait DivWrapping fn div_wrapping(rhs) }
1884op_trait! { trait NegWrapping fn neg_wrapping() }
1885
1886op_trait! {
1887	impl
1888
1889	lhs: u8 {
1890		rhs: u8 {
1891			add -> u8 { lhs + rhs }
1892			sub -> u8 { lhs - rhs }
1893			mul -> u8 { lhs * rhs }
1894			div -> u8 { lhs / rhs }
1895		}
1896
1897		rhs: u16 {
1898			add -> u16 { lhs.into_u16() + rhs }
1899			sub -> u16 { lhs.into_u16() - rhs }
1900			mul -> u16 { lhs.into_u16() * rhs }
1901			div -> u16 { lhs.into_u16() / rhs }
1902		}
1903
1904		rhs: u32 {
1905			add -> u32 { lhs.into_u32() + rhs }
1906			sub -> u32 { lhs.into_u32() - rhs }
1907			mul -> u32 { lhs.into_u32() * rhs }
1908			div -> u32 { lhs.into_u32() / rhs }
1909		}
1910
1911		rhs: u64 {
1912			add -> u64 { lhs.into_u64() + rhs }
1913			sub -> u64 { lhs.into_u64() - rhs }
1914			mul -> u64 { lhs.into_u64() * rhs }
1915			div -> u64 { lhs.into_u64() / rhs }
1916		}
1917
1918		rhs: u128 {
1919			add -> u128 { lhs.into_u128() + rhs }
1920			sub -> u128 { lhs.into_u128() - rhs }
1921			mul -> u128 { lhs.into_u128() * rhs }
1922			div -> u128 { lhs.into_u128() / rhs }
1923		}
1924
1925		rhs: usize {
1926			add -> usize { lhs.into_usize() + rhs }
1927			sub -> usize { lhs.into_usize() - rhs }
1928			mul -> usize { lhs.into_usize() * rhs }
1929			div -> usize { lhs.into_usize() / rhs }
1930		}
1931	}
1932
1933	lhs: u16 {}
1934
1935	lhs: u32 {}
1936
1937	lhs: u64 {}
1938
1939	lhs: u128 {}
1940
1941	lhs: usize {}
1942
1943	lhs: i8 {
1944		neg -> i8 { -lhs }
1945		rhs: i8 {
1946			add -> i8 { lhs + rhs }
1947		}
1948	}
1949
1950	lhs: i16 {}
1951
1952	lhs: i32 {}
1953
1954	lhs: i64 {}
1955
1956	lhs: i128 {}
1957
1958	lhs: isize {}
1959
1960	lhs: f32 {}
1961
1962	lhs: f64 {}
1963}
1964
1965/*
1966macro_rules! op_trait {
1967	{ impl(helper) add $($stuff:tt)* } => { op_trait! { impl(normal) Add::add $($stuff)* } };
1968	{ impl(helper) sub $($stuff:tt)* } => { op_trait! { impl(normal) Sub::sub $($stuff)* } };
1969	{ impl(helper) mul $($stuff:tt)* } => { op_trait! { impl(normal) Mul::mul $($stuff)* } };
1970	{ impl(helper) div $($stuff:tt)* } => { op_trait! { impl(normal) Div::div $($stuff)* } };
1971	{ impl(helper) neg $($stuff:tt)* } => { op_trait! { impl(normal) Neg::neg $($stuff)* } };
1972
1973	{ impl(helper) add_checked $($stuff:tt)* } => { op_trait! { impl(checked) AddChecked::add_checked $($stuff)* } };
1974	{ impl(helper) sub_checked $($stuff:tt)* } => { op_trait! { impl(checked) SubChecked::sub_checked $($stuff)* } };
1975	{ impl(helper) mul_checked $($stuff:tt)* } => { op_trait! { impl(checked) MulChecked::mul_checked $($stuff)* } };
1976	{ impl(helper) div_checked $($stuff:tt)* } => { op_trait! { impl(checked) DivChecked::div_checked $($stuff)* } };
1977	{ impl(helper) neg_checked $($stuff:tt)* } => { op_trait! { impl(checked) NegChecked::neg_checked $($stuff)* } };
1978
1979	{ impl(helper) add_overflowing $($stuff:tt)* } => { op_trait! { impl(overflowing) AddOverflowing::add_overflowing $($stuff)* } };
1980	{ impl(helper) sub_overflowing $($stuff:tt)* } => { op_trait! { impl(overflowing) SubOverflowing::sub_overflowing $($stuff)* } };
1981	{ impl(helper) mul_overflowing $($stuff:tt)* } => { op_trait! { impl(overflowing) MulOverflowing::mul_overflowing $($stuff)* } };
1982	{ impl(helper) div_overflowing $($stuff:tt)* } => { op_trait! { impl(overflowing) DivOverflowing::div_overflowing $($stuff)* } };
1983	{ impl(helper) neg_overflowing $($stuff:tt)* } => { op_trait! { impl(overflowing) NegOverflowing::neg_overflowing $($stuff)* } };
1984
1985	{ impl(helper) add_saturating $($stuff:tt)* } => { op_trait! { impl(saturating) AddSaturating::add_saturating $($stuff)* } };
1986	{ impl(helper) sub_saturating $($stuff:tt)* } => { op_trait! { impl(saturating) SubSaturating::sub_saturating $($stuff)* } };
1987	{ impl(helper) mul_saturating $($stuff:tt)* } => { op_trait! { impl(saturating) MulSaturating::mul_saturating $($stuff)* } };
1988	{ impl(helper) div_saturating $($stuff:tt)* } => { op_trait! { impl(saturating) DivSaturating::div_saturating $($stuff)* } };
1989	{ impl(helper) neg_saturating $($stuff:tt)* } => { op_trait! { impl(saturating) NegSaturating::neg_saturating $($stuff)* } };
1990
1991	{ impl(helper) add_unchecked $($stuff:tt)* } => { op_trait! { impl(unchecked) AddUnchecked::add_unchecked $($stuff)* } };
1992	{ impl(helper) sub_unchecked $($stuff:tt)* } => { op_trait! { impl(unchecked) SubUnchecked::sub_unchecked $($stuff)* } };
1993	{ impl(helper) mul_unchecked $($stuff:tt)* } => { op_trait! { impl(unchecked) MulUnchecked::mul_unchecked $($stuff)* } };
1994	{ impl(helper) div_unchecked $($stuff:tt)* } => { op_trait! { impl(unchecked) DivUnchecked::div_unchecked $($stuff)* } };
1995	{ impl(helper) neg_unchecked $($stuff:tt)* } => { op_trait! { impl(unchecked) NegUnchecked::neg_unchecked $($stuff)* } };
1996
1997	{ impl(helper) add_wrapping $($stuff:tt)* } => { op_trait! { impl(wrapping) AddWrapping::add_wrapping $($stuff)* } };
1998	{ impl(helper) sub_wrapping $($stuff:tt)* } => { op_trait! { impl(wrapping) SubWrapping::sub_wrapping $($stuff)* } };
1999	{ impl(helper) mul_wrapping $($stuff:tt)* } => { op_trait! { impl(wrapping) MulWrapping::mul_wrapping $($stuff)* } };
2000	{ impl(helper) div_wrapping $($stuff:tt)* } => { op_trait! { impl(wrapping) DivWrapping::div_wrapping $($stuff)* } };
2001	{ impl(helper) neg_wrapping $($stuff:tt)* } => { op_trait! { impl(wrapping) NegWrapping::neg_wrapping $($stuff)* } };
2002}
2003
2004op_trait! {
2005	impl
2006
2007	lhs: u8 {
2008		#[cfg(any(
2009			target_pointer_width = "16",
2010			target_pointer_width = "32",
2011			target_pointer_width = "64"
2012		))]
2013		rhs: u8 {
2014			add() -> u8 { lhs + rhs }
2015			sub() -> u8 { lhs - rhs }
2016			mul() -> u8 { lhs * rhs }
2017			div() -> u8 { lhs / rhs }
2018
2019			add_checked() -> u8 { lhs.checked_add(rhs) }
2020			sub_checked() -> u8 { lhs.checked_sub(rhs) }
2021			mul_checked() -> u8 { lhs.checked_mul(rhs) }
2022			div_checked() -> u8 { lhs.checked_div(rhs) }
2023
2024			add_overflowing() -> u8 { lhs.overflowing_add(rhs) }
2025			sub_overflowing() -> u8 { lhs.overflowing_sub(rhs) }
2026			mul_overflowing() -> u8 { lhs.overflowing_mul(rhs) }
2027			div_overflowing() -> u8 { lhs.overflowing_div(rhs) }
2028
2029			add_saturating() -> u8 { lhs.saturating_add(rhs) }
2030			sub_saturating() -> u8 { lhs.saturating_sub(rhs) }
2031			mul_saturating() -> u8 { lhs.saturating_mul(rhs) }
2032			div_saturating() -> u8 { lhs.saturating_div(rhs) }
2033
2034			// SAFETY: invariants upheld by caller
2035			add_unchecked() -> u8 { unsafe { lhs.unchecked_add(rhs) } }
2036			// SAFETY: invariants upheld by caller
2037			sub_unchecked() -> u8 { unsafe { lhs.unchecked_sub(rhs) } }
2038			// SAFETY: invariants upheld by caller
2039			mul_unchecked() -> u8 { unsafe { lhs.unchecked_mul(rhs) } }
2040			div_unchecked() -> u8 { lhs / rhs }
2041
2042			add_wrapping() -> u8 { lhs.wrapping_add(rhs) }
2043			sub_wrapping() -> u8 { lhs.wrapping_sub(rhs) }
2044			mul_wrapping() -> u8 { lhs.wrapping_mul(rhs) }
2045			div_wrapping() -> u8 { lhs.wrapping_div(rhs) }
2046		}
2047
2048		#[cfg(any(
2049			target_pointer_width = "16",
2050			target_pointer_width = "32",
2051			target_pointer_width = "64"
2052		))]
2053		rhs: u16 {
2054			add() -> u16 { lhs.into_u16() + rhs }
2055			sub() -> u16 { lhs.into_u16() - rhs }
2056			mul() -> u16 { lhs.into_u16() * rhs }
2057			div() -> u16 { lhs.into_u16() / rhs }
2058
2059			add_checked() -> u16 { lhs.into_u16().checked_add(rhs) }
2060			sub_checked() -> u16 { lhs.into_u16().checked_sub(rhs) }
2061			mul_checked() -> u16 { lhs.into_u16().checked_mul(rhs) }
2062			div_checked() -> u16 { lhs.into_u16().checked_div(rhs) }
2063		}
2064
2065		#[cfg(any(
2066			target_pointer_width = "16",
2067			target_pointer_width = "32",
2068			target_pointer_width = "64"
2069		))]
2070		rhs: u32 {
2071			add() -> u32 { lhs.into_u32() + rhs }
2072			sub() -> u32 { lhs.into_u32() - rhs }
2073			mul() -> u32 { lhs.into_u32() * rhs }
2074			div() -> u32 { lhs.into_u32() / rhs }
2075
2076			add_checked() -> u32 { lhs.into_u32().checked_add(rhs) }
2077			sub_checked() -> u32 { lhs.into_u32().checked_sub(rhs) }
2078			mul_checked() -> u32 { lhs.into_u32().checked_mul(rhs) }
2079			div_checked() -> u32 { lhs.into_u32().checked_div(rhs) }
2080		}
2081
2082		#[cfg(any(
2083			target_pointer_width = "16",
2084			target_pointer_width = "32",
2085			target_pointer_width = "64"
2086		))]
2087		rhs: u64 {
2088			add() -> u64 { lhs.into_u64() + rhs }
2089			sub() -> u64 { lhs.into_u64() - rhs }
2090			mul() -> u64 { lhs.into_u64() * rhs }
2091			div() -> u64 { lhs.into_u64() / rhs }
2092
2093			add_checked() -> u64 { lhs.into_u64().checked_add(rhs) }
2094			sub_checked() -> u64 { lhs.into_u64().checked_sub(rhs) }
2095			mul_checked() -> u64 { lhs.into_u64().checked_mul(rhs) }
2096			div_checked() -> u64 { lhs.into_u64().checked_div(rhs) }
2097		}
2098
2099		#[cfg(any(
2100			target_pointer_width = "16",
2101			target_pointer_width = "32",
2102			target_pointer_width = "64"
2103		))]
2104		rhs: u128 {
2105			add() -> u128 { lhs.into_u128() + rhs }
2106			sub() -> u128 { lhs.into_u128() - rhs }
2107			mul() -> u128 { lhs.into_u128() * rhs }
2108			div() -> u128 { lhs.into_u128() / rhs }
2109
2110			add_checked() -> u128 { lhs.into_u128().checked_add(rhs) }
2111			sub_checked() -> u128 { lhs.into_u128().checked_sub(rhs) }
2112			mul_checked() -> u128 { lhs.into_u128().checked_mul(rhs) }
2113			div_checked() -> u128 { lhs.into_u128().checked_div(rhs) }
2114		}
2115	}
2116
2117	lhs: i8 {
2118		#[cfg(any(
2119			target_pointer_width = "16",
2120			target_pointer_width = "32",
2121			target_pointer_width = "64"
2122		))]
2123		rhs: i8 {
2124			add() -> i8 { lhs + rhs }
2125			sub() -> i8 { lhs - rhs }
2126			mul() -> i8 { lhs * rhs }
2127			div() -> i8 { lhs / rhs }
2128
2129			add_checked() -> i8 { lhs.checked_add(rhs) }
2130			sub_checked() -> i8 { lhs.checked_sub(rhs) }
2131			mul_checked() -> i8 { lhs.checked_mul(rhs) }
2132			div_checked() -> i8 { lhs.checked_div(rhs) }
2133
2134			add_overflowing() -> i8 { lhs.overflowing_add(rhs) }
2135			sub_overflowing() -> i8 { lhs.overflowing_sub(rhs) }
2136			mul_overflowing() -> i8 { lhs.overflowing_mul(rhs) }
2137			div_overflowing() -> i8 { lhs.overflowing_div(rhs) }
2138
2139			add_saturating() -> i8 { lhs.saturating_add(rhs) }
2140			sub_saturating() -> i8 { lhs.saturating_sub(rhs) }
2141			mul_saturating() -> i8 { lhs.saturating_mul(rhs) }
2142			div_saturating() -> i8 { lhs.saturating_div(rhs) }
2143
2144			// SAFETY: invariants upheld by caller
2145			add_unchecked() -> i8 { unsafe { lhs.unchecked_add(rhs) } }
2146			// SAFETY: invariants upheld by caller
2147			sub_unchecked() -> i8 { unsafe { lhs.unchecked_sub(rhs) } }
2148			// SAFETY: invariants upheld by caller
2149			mul_unchecked() -> i8 { unsafe { lhs.unchecked_mul(rhs) } }
2150			div_unchecked() -> i8 { lhs / rhs }
2151
2152			add_wrapping() -> i8 { lhs.wrapping_add(rhs) }
2153			sub_wrapping() -> i8 { lhs.wrapping_sub(rhs) }
2154			mul_wrapping() -> i8 { lhs.wrapping_mul(rhs) }
2155			div_wrapping() -> i8 { lhs.wrapping_div(rhs) }
2156		}
2157	}
2158}
2159*/
2160
2161/// notouchie
2162mod private {
2163	use super::*;
2164
2165	/// notouchie
2166	pub trait Sealed
2167	where
2168		Self: Sized
2169	{}
2170
2171	macro_rules! impl_sealed {
2172		{ $($type:ident)* } => {
2173			$(
2174				impl Sealed for $type {}
2175			)*
2176		}
2177	}
2178
2179	impl_sealed! {
2180		u8 u16 u32 u64 u128 usize
2181		i8 i16 i32 i64 i128 isize
2182		f32 f64
2183		bool
2184	}
2185
2186	impl<T> Sealed for &T
2187	where
2188		T: Sealed
2189	{}
2190
2191	impl<T> Sealed for &mut T
2192	where
2193		T: Sealed
2194	{}
2195}