]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_macros/src/newtype.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_macros / src / newtype.rs
CommitLineData
5e7ed085
FG
1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3use syn::parse::*;
5e7ed085
FG
4use syn::*;
5
5e7ed085
FG
6// We parse the input and emit the output in a single step.
7// This field stores the final macro output
8struct Newtype(TokenStream);
9
10impl Parse for Newtype {
11 fn parse(input: ParseStream<'_>) -> Result<Self> {
9c376795 12 let mut attrs = input.call(Attribute::parse_outer)?;
5e7ed085
FG
13 let vis: Visibility = input.parse()?;
14 input.parse::<Token![struct]>()?;
15 let name: Ident = input.parse()?;
16
17 let body;
18 braced!(body in input);
19
20 // Any additional `#[derive]` macro paths to apply
21 let mut derive_paths: Vec<Path> = Vec::new();
9c376795 22 let mut debug_format: Option<Lit> = None;
5e7ed085
FG
23 let mut max = None;
24 let mut consts = Vec::new();
25 let mut encodable = true;
26 let mut ord = true;
27
9c376795
FG
28 attrs.retain(|attr| match attr.path.get_ident() {
29 Some(ident) => match &*ident.to_string() {
30 "custom_encodable" => {
5e7ed085 31 encodable = false;
9c376795 32 false
5e7ed085 33 }
9c376795 34 "no_ord_impl" => {
5e7ed085 35 ord = false;
9c376795 36 false
5e7ed085 37 }
9c376795
FG
38 "max" => {
39 let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
40 panic!("#[max = NUMBER] attribute requires max value");
41 };
5e7ed085 42
9c376795
FG
43 if let Some(old) = max.replace(literal.lit) {
44 panic!("Specified multiple max: {old:?}");
45 }
46
47 false
5e7ed085 48 }
9c376795
FG
49 "debug_format" => {
50 let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
51 panic!("#[debug_format = FMT] attribute requires a format");
52 };
5e7ed085 53
9c376795
FG
54 if let Some(old) = debug_format.replace(literal.lit) {
55 panic!("Specified multiple debug format options: {old:?}");
56 }
57
58 false
59 }
60 _ => true,
61 },
62 _ => true,
63 });
64
65 loop {
66 // We've parsed everything that the user provided, so we're done
67 if body.is_empty() {
68 break;
5e7ed085 69 }
9c376795
FG
70
71 // Otherwise, we are parsing a user-defined constant
72 let const_attrs = body.call(Attribute::parse_outer)?;
73 body.parse::<Token![const]>()?;
74 let const_name: Ident = body.parse()?;
75 body.parse::<Token![=]>()?;
76 let const_val: Expr = body.parse()?;
77 body.parse::<Token![;]>()?;
78 consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); });
5e7ed085
FG
79 }
80
9c376795
FG
81 let debug_format =
82 debug_format.unwrap_or_else(|| Lit::Str(LitStr::new("{}", Span::call_site())));
83
5e7ed085
FG
84 // shave off 256 indices at the end to allow space for packing these indices into enums
85 let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site())));
86
87 let encodable_impls = if encodable {
88 quote! {
89 impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name {
90 fn decode(d: &mut D) -> Self {
91 Self::from_u32(d.read_u32())
92 }
93 }
94 impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
923072b8
FG
95 fn encode(&self, e: &mut E) {
96 e.emit_u32(self.private);
5e7ed085
FG
97 }
98 }
99 }
100 } else {
101 quote! {}
102 };
103
104 if ord {
105 derive_paths.push(parse_quote!(Ord));
106 derive_paths.push(parse_quote!(PartialOrd));
107 }
108
109 let step = if ord {
110 quote! {
111 impl ::std::iter::Step for #name {
112 #[inline]
113 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
114 <usize as ::std::iter::Step>::steps_between(
115 &Self::index(*start),
116 &Self::index(*end),
117 )
118 }
119
120 #[inline]
121 fn forward_checked(start: Self, u: usize) -> Option<Self> {
122 Self::index(start).checked_add(u).map(Self::from_usize)
123 }
124
125 #[inline]
126 fn backward_checked(start: Self, u: usize) -> Option<Self> {
127 Self::index(start).checked_sub(u).map(Self::from_usize)
128 }
129 }
130
131 // Safety: The implementation of `Step` upholds all invariants.
132 unsafe impl ::std::iter::TrustedStep for #name {}
133 }
134 } else {
135 quote! {}
136 };
137
9c376795
FG
138 let debug_impl = quote! {
139 impl ::std::fmt::Debug for #name {
140 fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
141 write!(fmt, #debug_format, self.as_u32())
5e7ed085
FG
142 }
143 }
144 };
9c376795 145
487cf647
FG
146 let spec_partial_eq_impl = if let Lit::Int(max) = &max {
147 if let Ok(max_val) = max.base10_parse::<u32>() {
148 quote! {
149 impl core::option::SpecOptionPartialEq for #name {
150 #[inline]
151 fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
152 if #max_val < u32::MAX {
153 l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1)
154 } else {
155 match (l, r) {
156 (Some(l), Some(r)) => r == l,
157 (None, None) => true,
158 _ => false
159 }
160 }
161 }
162 }
163 }
164 } else {
165 quote! {}
166 }
167 } else {
168 quote! {}
169 };
5e7ed085
FG
170
171 Ok(Self(quote! {
172 #(#attrs)*
173 #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
174 #[rustc_layout_scalar_valid_range_end(#max)]
175 #[rustc_pass_by_value]
176 #vis struct #name {
177 private: u32,
178 }
179
180 #(#consts)*
181
182 impl #name {
183 /// Maximum value the index can take, as a `u32`.
184 #vis const MAX_AS_U32: u32 = #max;
185
186 /// Maximum value the index can take.
187 #vis const MAX: Self = Self::from_u32(#max);
188
189 /// Creates a new index from a given `usize`.
190 ///
191 /// # Panics
192 ///
193 /// Will panic if `value` exceeds `MAX`.
194 #[inline]
195 #vis const fn from_usize(value: usize) -> Self {
196 assert!(value <= (#max as usize));
197 // SAFETY: We just checked that `value <= max`.
198 unsafe {
199 Self::from_u32_unchecked(value as u32)
200 }
201 }
202
203 /// Creates a new index from a given `u32`.
204 ///
205 /// # Panics
206 ///
207 /// Will panic if `value` exceeds `MAX`.
208 #[inline]
209 #vis const fn from_u32(value: u32) -> Self {
210 assert!(value <= #max);
211 // SAFETY: We just checked that `value <= max`.
212 unsafe {
213 Self::from_u32_unchecked(value)
214 }
215 }
216
217 /// Creates a new index from a given `u32`.
218 ///
219 /// # Safety
220 ///
221 /// The provided value must be less than or equal to the maximum value for the newtype.
222 /// Providing a value outside this range is undefined due to layout restrictions.
223 ///
224 /// Prefer using `from_u32`.
225 #[inline]
226 #vis const unsafe fn from_u32_unchecked(value: u32) -> Self {
227 Self { private: value }
228 }
229
230 /// Extracts the value of this index as a `usize`.
231 #[inline]
232 #vis const fn index(self) -> usize {
233 self.as_usize()
234 }
235
236 /// Extracts the value of this index as a `u32`.
237 #[inline]
238 #vis const fn as_u32(self) -> u32 {
239 self.private
240 }
241
242 /// Extracts the value of this index as a `usize`.
243 #[inline]
244 #vis const fn as_usize(self) -> usize {
245 self.as_u32() as usize
246 }
247 }
248
249 impl std::ops::Add<usize> for #name {
250 type Output = Self;
251
252 fn add(self, other: usize) -> Self {
253 Self::from_usize(self.index() + other)
254 }
255 }
256
257 impl rustc_index::vec::Idx for #name {
258 #[inline]
259 fn new(value: usize) -> Self {
260 Self::from_usize(value)
261 }
262
263 #[inline]
264 fn index(self) -> usize {
265 self.as_usize()
266 }
267 }
268
269 #step
270
487cf647
FG
271 #spec_partial_eq_impl
272
5e7ed085
FG
273 impl From<#name> for u32 {
274 #[inline]
275 fn from(v: #name) -> u32 {
276 v.as_u32()
277 }
278 }
279
280 impl From<#name> for usize {
281 #[inline]
282 fn from(v: #name) -> usize {
283 v.as_usize()
284 }
285 }
286
287 impl From<usize> for #name {
288 #[inline]
289 fn from(value: usize) -> Self {
290 Self::from_usize(value)
291 }
292 }
293
294 impl From<u32> for #name {
295 #[inline]
296 fn from(value: u32) -> Self {
297 Self::from_u32(value)
298 }
299 }
300
301 #encodable_impls
302 #debug_impl
303 }))
304 }
305}
306
307pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
308 let input = parse_macro_input!(input as Newtype);
309 input.0.into()
310}