1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use super::Base;

macro_rules! decl_into_lossless {
	{
		trait_name: $trait_name:ident
		fn_name: $fn_name:ident
		into: $into:ident
		$($(#[$meta:meta])* $from:ident)*
	} => {
		/// Lossless conversion into
		#[doc = concat!("`", stringify!($into), "`")]
		///
		/// That is, this trait is implemented for a number type, when it can be
		/// converted into a
		#[doc = concat!("`", stringify!($into), "`")]
		/// while guaranteeing absolutely no losses for all possible values. This
		/// is not the same as an `as` cast!
		pub trait $trait_name: Base {
			/// Losslessly converts `self` into
			#[doc = concat!("`", stringify!($into), "`")]
			fn $fn_name(self) -> $into;
		}

		$(
			$(#[$meta])*
			impl $trait_name for $from {
				#[expect(clippy::as_conversions)]
				#[inline(always)]
				fn $fn_name(self) -> $into { self as _ }
			}
		)*
	}
}

decl_into_lossless! {
	trait_name: IntoU8Lossless
	fn_name: into_u8
	into: u8
	u8
}

decl_into_lossless! {
	trait_name: IntoU16Lossless
	fn_name: into_u16
	into: u16
	u8 u16
	#[cfg(target_pointer_width = "16")] usize
}

decl_into_lossless! {
	trait_name: IntoU32Lossless
	fn_name: into_u32
	into: u32
	u8 u16 u32
	#[cfg(not(target_pointer_width = "64"))] usize
}

decl_into_lossless! {
	trait_name: IntoU64Lossless
	fn_name: into_u64
	into: u64
	u8 u16 u32 u64 usize
}

decl_into_lossless! {
	trait_name: IntoU128Lossless
	fn_name: into_u128
	into: u128
	u8 u16 u32 u64 u128 usize
}

decl_into_lossless! {
	trait_name: IntoUsizeLossless
	fn_name: into_usize
	into: usize
	u8 u16
	#[cfg(not(target_pointer_width = "16"))] u32
	#[cfg(target_pointer_width = "64")] u64
	usize
}

decl_into_lossless! {
	trait_name: IntoI8Lossless
	fn_name: into_i8
	into: i8
	i8
}

decl_into_lossless! {
	trait_name: IntoI16Lossless
	fn_name: into_i16
	into: i16
	u8
	i8 i16
	#[cfg(target_pointer_width = "16")] isize
}

decl_into_lossless! {
	trait_name: IntoI32Lossless
	fn_name: into_i32
	into: i32
	u8 u16
	#[cfg(target_pointer_width = "16")] usize
	i8 i16 i32
	#[cfg(not(target_pointer_width = "64"))] isize
}

decl_into_lossless! {
	trait_name: IntoI64Lossless
	fn_name: into_i64
	into: i64
	u8 u16 u32
	i8 i16 i32 i64 isize
}

decl_into_lossless! {
	trait_name: IntoI128Lossless
	fn_name: into_i128
	into: i128
	u8 u16 u32 u64 usize
	i8 i16 i32 i64 i128 isize
}

decl_into_lossless! {
	trait_name: IntoIsizeLossless
	fn_name: into_isize
	into: isize
	u8
	#[cfg(not(target_pointer_width = "16"))] u16
	#[cfg(target_pointer_width = "64")] u32
	i8 i16
	#[cfg(not(target_pointer_width = "16"))] i32
	#[cfg(target_pointer_width = "64")] i64
	isize
}

decl_into_lossless! {
	trait_name: IntoF32Lossless
	fn_name: into_f32
	into: f32
	u8 u16
	#[cfg(target_pointer_width = "16")] usize
	i8 i16
	#[cfg(target_pointer_width = "16")] isize
	f32
}

decl_into_lossless! {
	trait_name: IntoF64Lossless
	fn_name: into_f64
	into: f64
	u8 u16 u32
	#[cfg(not(target_pointer_width = "64"))] usize
	i8 i16 i32
	#[cfg(not(target_pointer_width = "64"))] isize
	f32 f64
}