diff options
Diffstat (limited to 'compiler/rustc_macros/src/newtype.rs')
-rw-r--r-- | compiler/rustc_macros/src/newtype.rs | 312 |
1 files changed, 0 insertions, 312 deletions
diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs deleted file mode 100644 index 72b47de1a..000000000 --- a/compiler/rustc_macros/src/newtype.rs +++ /dev/null @@ -1,312 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::quote; -use syn::parse::*; -use syn::*; - -// We parse the input and emit the output in a single step. -// This field stores the final macro output -struct Newtype(TokenStream); - -impl Parse for Newtype { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - input.parse::<Token![struct]>()?; - let name: Ident = input.parse()?; - - let body; - braced!(body in input); - - // Any additional `#[derive]` macro paths to apply - let mut derive_paths: Vec<Path> = Vec::new(); - let mut debug_format: Option<Lit> = None; - let mut max = None; - let mut consts = Vec::new(); - let mut encodable = true; - let mut ord = true; - - attrs.retain(|attr| match attr.path().get_ident() { - Some(ident) => match &*ident.to_string() { - "custom_encodable" => { - encodable = false; - false - } - "no_ord_impl" => { - ord = false; - false - } - "max" => { - let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta - else { - panic!("#[max = NUMBER] attribute requires max value"); - }; - - if let Some(old) = max.replace(lit.lit.clone()) { - panic!("Specified multiple max: {old:?}"); - } - - false - } - "debug_format" => { - let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta - else { - panic!("#[debug_format = FMT] attribute requires a format"); - }; - - if let Some(old) = debug_format.replace(lit.lit.clone()) { - panic!("Specified multiple debug format options: {old:?}"); - } - - false - } - _ => true, - }, - _ => true, - }); - - loop { - // We've parsed everything that the user provided, so we're done - if body.is_empty() { - break; - } - - // Otherwise, we are parsing a user-defined constant - let const_attrs = body.call(Attribute::parse_outer)?; - body.parse::<Token![const]>()?; - let const_name: Ident = body.parse()?; - body.parse::<Token![=]>()?; - let const_val: Expr = body.parse()?; - body.parse::<Token![;]>()?; - consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); }); - } - - let debug_format = - debug_format.unwrap_or_else(|| Lit::Str(LitStr::new("{}", Span::call_site()))); - - // shave off 256 indices at the end to allow space for packing these indices into enums - let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site()))); - - let encodable_impls = if encodable { - quote! { - impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name { - fn decode(d: &mut D) -> Self { - Self::from_u32(d.read_u32()) - } - } - impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name { - fn encode(&self, e: &mut E) { - e.emit_u32(self.private); - } - } - } - } else { - quote! {} - }; - - if ord { - derive_paths.push(parse_quote!(Ord)); - derive_paths.push(parse_quote!(PartialOrd)); - } - - let step = if ord { - quote! { - impl ::std::iter::Step for #name { - #[inline] - fn steps_between(start: &Self, end: &Self) -> Option<usize> { - <usize as ::std::iter::Step>::steps_between( - &Self::index(*start), - &Self::index(*end), - ) - } - - #[inline] - fn forward_checked(start: Self, u: usize) -> Option<Self> { - Self::index(start).checked_add(u).map(Self::from_usize) - } - - #[inline] - fn backward_checked(start: Self, u: usize) -> Option<Self> { - Self::index(start).checked_sub(u).map(Self::from_usize) - } - } - - // Safety: The implementation of `Step` upholds all invariants. - unsafe impl ::std::iter::TrustedStep for #name {} - } - } else { - quote! {} - }; - - let debug_impl = quote! { - impl ::std::fmt::Debug for #name { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(fmt, #debug_format, self.as_u32()) - } - } - }; - - let spec_partial_eq_impl = if let Lit::Int(max) = &max { - if let Ok(max_val) = max.base10_parse::<u32>() { - quote! { - impl core::option::SpecOptionPartialEq for #name { - #[inline] - fn eq(l: &Option<Self>, r: &Option<Self>) -> bool { - if #max_val < u32::MAX { - l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1) - } else { - match (l, r) { - (Some(l), Some(r)) => r == l, - (None, None) => true, - _ => false - } - } - } - } - } - } else { - quote! {} - } - } else { - quote! {} - }; - - Ok(Self(quote! { - #(#attrs)* - #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)] - #[rustc_layout_scalar_valid_range_end(#max)] - #[rustc_pass_by_value] - #vis struct #name { - private: u32, - } - - #(#consts)* - - impl #name { - /// Maximum value the index can take, as a `u32`. - #vis const MAX_AS_U32: u32 = #max; - - /// Maximum value the index can take. - #vis const MAX: Self = Self::from_u32(#max); - - /// Creates a new index from a given `usize`. - /// - /// # Panics - /// - /// Will panic if `value` exceeds `MAX`. - #[inline] - #vis const fn from_usize(value: usize) -> Self { - assert!(value <= (#max as usize)); - // SAFETY: We just checked that `value <= max`. - unsafe { - Self::from_u32_unchecked(value as u32) - } - } - - /// Creates a new index from a given `u32`. - /// - /// # Panics - /// - /// Will panic if `value` exceeds `MAX`. - #[inline] - #vis const fn from_u32(value: u32) -> Self { - assert!(value <= #max); - // SAFETY: We just checked that `value <= max`. - unsafe { - Self::from_u32_unchecked(value) - } - } - - /// Creates a new index from a given `u32`. - /// - /// # Safety - /// - /// The provided value must be less than or equal to the maximum value for the newtype. - /// Providing a value outside this range is undefined due to layout restrictions. - /// - /// Prefer using `from_u32`. - #[inline] - #vis const unsafe fn from_u32_unchecked(value: u32) -> Self { - Self { private: value } - } - - /// Extracts the value of this index as a `usize`. - #[inline] - #vis const fn index(self) -> usize { - self.as_usize() - } - - /// Extracts the value of this index as a `u32`. - #[inline] - #vis const fn as_u32(self) -> u32 { - self.private - } - - /// Extracts the value of this index as a `usize`. - #[inline] - #vis const fn as_usize(self) -> usize { - self.as_u32() as usize - } - } - - impl std::ops::Add<usize> for #name { - type Output = Self; - - fn add(self, other: usize) -> Self { - Self::from_usize(self.index() + other) - } - } - - impl rustc_index::Idx for #name { - #[inline] - fn new(value: usize) -> Self { - Self::from_usize(value) - } - - #[inline] - fn index(self) -> usize { - self.as_usize() - } - } - - #step - - #spec_partial_eq_impl - - impl From<#name> for u32 { - #[inline] - fn from(v: #name) -> u32 { - v.as_u32() - } - } - - impl From<#name> for usize { - #[inline] - fn from(v: #name) -> usize { - v.as_usize() - } - } - - impl From<usize> for #name { - #[inline] - fn from(value: usize) -> Self { - Self::from_usize(value) - } - } - - impl From<u32> for #name { - #[inline] - fn from(value: u32) -> Self { - Self::from_u32(value) - } - } - - #encodable_impls - #debug_impl - })) - } -} - -pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as Newtype); - input.0.into() -} |