1 use proc_macro2::{Span, TokenStream};
6 // We parse the input and emit the output in a single step.
7 // This field stores the final macro output
8 struct Newtype(TokenStream);
10 impl Parse for Newtype {
11 fn parse(input: ParseStream<'_>) -> Result<Self> {
12 let mut attrs = input.call(Attribute::parse_outer)?;
13 let vis: Visibility = input.parse()?;
14 input.parse::<Token![struct]>()?;
15 let name: Ident = input.parse()?;
18 braced!(body in input);
20 // Any additional `#[derive]` macro paths to apply
21 let mut derive_paths: Vec<Path> = Vec::new();
22 let mut debug_format: Option<Lit> = None;
24 let mut consts = Vec::new();
25 let mut encodable = true;
28 // Parse an optional trailing comma
29 let try_comma = || -> Result<()> {
30 if body.lookahead1().peek(Token![,]) {
31 body.parse::<Token![,]>()?;
36 attrs.retain(|attr| match attr.path.get_ident() {
37 Some(ident) => match &*ident.to_string() {
38 "custom_encodable" => {
47 let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
48 panic!("#[max = NUMBER] attribute requires max value");
51 if let Some(old) = max.replace(literal.lit) {
52 panic!("Specified multiple max: {:?}", old);
58 let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
59 panic!("#[debug_format = FMT] attribute requires a format");
62 if let Some(old) = debug_format.replace(literal.lit) {
63 panic!("Specified multiple debug format options: {:?}", old);
73 if body.lookahead1().peek(Token![..]) {
74 body.parse::<Token![..]>()?;
77 // We've parsed everything that the user provided, so we're done
82 // Otherwise, we are parsing a user-defined constant
83 let const_attrs = body.call(Attribute::parse_outer)?;
84 body.parse::<Token![const]>()?;
85 let const_name: Ident = body.parse()?;
86 body.parse::<Token![=]>()?;
87 let const_val: Expr = body.parse()?;
89 consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); });
94 debug_format.unwrap_or_else(|| Lit::Str(LitStr::new("{}", Span::call_site())));
96 // shave off 256 indices at the end to allow space for packing these indices into enums
97 let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site())));
99 let encodable_impls = if encodable {
101 impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name {
102 fn decode(d: &mut D) -> Self {
103 Self::from_u32(d.read_u32())
106 impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
107 fn encode(&self, e: &mut E) {
108 e.emit_u32(self.private);
117 derive_paths.push(parse_quote!(Ord));
118 derive_paths.push(parse_quote!(PartialOrd));
123 impl ::std::iter::Step for #name {
125 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
126 <usize as ::std::iter::Step>::steps_between(
127 &Self::index(*start),
133 fn forward_checked(start: Self, u: usize) -> Option<Self> {
134 Self::index(start).checked_add(u).map(Self::from_usize)
138 fn backward_checked(start: Self, u: usize) -> Option<Self> {
139 Self::index(start).checked_sub(u).map(Self::from_usize)
143 // Safety: The implementation of `Step` upholds all invariants.
144 unsafe impl ::std::iter::TrustedStep for #name {}
150 let debug_impl = quote! {
151 impl ::std::fmt::Debug for #name {
152 fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
153 write!(fmt, #debug_format, self.as_u32())
158 let spec_partial_eq_impl = if let Lit::Int(max) = &max {
159 if let Ok(max_val) = max.base10_parse::<u32>() {
161 impl core::option::SpecOptionPartialEq for #name {
163 fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
164 if #max_val < u32::MAX {
165 l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1)
168 (Some(l), Some(r)) => r == l,
169 (None, None) => true,
185 #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
186 #[rustc_layout_scalar_valid_range_end(#max)]
187 #[rustc_pass_by_value]
195 /// Maximum value the index can take, as a `u32`.
196 #vis const MAX_AS_U32: u32 = #max;
198 /// Maximum value the index can take.
199 #vis const MAX: Self = Self::from_u32(#max);
201 /// Creates a new index from a given `usize`.
205 /// Will panic if `value` exceeds `MAX`.
207 #vis const fn from_usize(value: usize) -> Self {
208 assert!(value <= (#max as usize));
209 // SAFETY: We just checked that `value <= max`.
211 Self::from_u32_unchecked(value as u32)
215 /// Creates a new index from a given `u32`.
219 /// Will panic if `value` exceeds `MAX`.
221 #vis const fn from_u32(value: u32) -> Self {
222 assert!(value <= #max);
223 // SAFETY: We just checked that `value <= max`.
225 Self::from_u32_unchecked(value)
229 /// Creates a new index from a given `u32`.
233 /// The provided value must be less than or equal to the maximum value for the newtype.
234 /// Providing a value outside this range is undefined due to layout restrictions.
236 /// Prefer using `from_u32`.
238 #vis const unsafe fn from_u32_unchecked(value: u32) -> Self {
239 Self { private: value }
242 /// Extracts the value of this index as a `usize`.
244 #vis const fn index(self) -> usize {
248 /// Extracts the value of this index as a `u32`.
250 #vis const fn as_u32(self) -> u32 {
254 /// Extracts the value of this index as a `usize`.
256 #vis const fn as_usize(self) -> usize {
257 self.as_u32() as usize
261 impl std::ops::Add<usize> for #name {
264 fn add(self, other: usize) -> Self {
265 Self::from_usize(self.index() + other)
269 impl rustc_index::vec::Idx for #name {
271 fn new(value: usize) -> Self {
272 Self::from_usize(value)
276 fn index(self) -> usize {
283 #spec_partial_eq_impl
285 impl From<#name> for u32 {
287 fn from(v: #name) -> u32 {
292 impl From<#name> for usize {
294 fn from(v: #name) -> usize {
299 impl From<usize> for #name {
301 fn from(value: usize) -> Self {
302 Self::from_usize(value)
306 impl From<u32> for #name {
308 fn from(value: u32) -> Self {
309 Self::from_u32(value)
319 pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
320 let input = parse_macro_input!(input as Newtype);