1 use proc_macro2::{Span, TokenStream};
7 syn::custom_keyword!(DEBUG_FORMAT);
8 syn::custom_keyword!(MAX);
9 syn::custom_keyword!(custom);
14 // The user will provide a custom `Debug` impl, so we shouldn't generate
17 // Use the specified format string in the generated `Debug` impl
18 // By default, this is "{}"
22 // We parse the input and emit the output in a single step.
23 // This field stores the final macro output
24 struct Newtype(TokenStream);
26 impl Parse for Newtype {
27 fn parse(input: ParseStream<'_>) -> Result<Self> {
28 let mut attrs = input.call(Attribute::parse_outer)?;
29 let vis: Visibility = input.parse()?;
30 input.parse::<Token![struct]>()?;
31 let name: Ident = input.parse()?;
34 braced!(body in input);
36 // Any additional `#[derive]` macro paths to apply
37 let mut derive_paths: Vec<Path> = Vec::new();
38 let mut debug_format: Option<DebugFormat> = None;
40 let mut consts = Vec::new();
41 let mut encodable = true;
44 // Parse an optional trailing comma
45 let try_comma = || -> Result<()> {
46 if body.lookahead1().peek(Token![,]) {
47 body.parse::<Token![,]>()?;
52 attrs.retain(|attr| match attr.path.get_ident() {
53 Some(ident) => match &*ident.to_string() {
54 "custom_encodable" => {
63 let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
64 panic!("#[max = NUMBER] attribute requires max value");
67 if let Some(old) = max.replace(literal.lit) {
68 panic!("Specified multiple MAX: {:?}", old);
78 if body.lookahead1().peek(Token![..]) {
79 body.parse::<Token![..]>()?;
82 if body.lookahead1().peek(kw::DEBUG_FORMAT) {
83 body.parse::<kw::DEBUG_FORMAT>()?;
84 body.parse::<Token![=]>()?;
85 let new_debug_format = if body.lookahead1().peek(kw::custom) {
86 body.parse::<kw::custom>()?;
89 let format_str: LitStr = body.parse()?;
90 DebugFormat::Format(format_str.value())
93 if let Some(old) = debug_format.replace(new_debug_format) {
94 panic!("Specified multiple debug format options: {:?}", old);
99 // We've parsed everything that the user provided, so we're done
104 // Otherwise, we are parsing a user-defined constant
105 let const_attrs = body.call(Attribute::parse_outer)?;
106 body.parse::<Token![const]>()?;
107 let const_name: Ident = body.parse()?;
108 body.parse::<Token![=]>()?;
109 let const_val: Expr = body.parse()?;
111 consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); });
115 let debug_format = debug_format.unwrap_or(DebugFormat::Format("{}".to_string()));
116 // shave off 256 indices at the end to allow space for packing these indices into enums
117 let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site())));
119 let encodable_impls = if encodable {
121 impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name {
122 fn decode(d: &mut D) -> Self {
123 Self::from_u32(d.read_u32())
126 impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
127 fn encode(&self, e: &mut E) {
128 e.emit_u32(self.private);
137 derive_paths.push(parse_quote!(Ord));
138 derive_paths.push(parse_quote!(PartialOrd));
143 impl ::std::iter::Step for #name {
145 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
146 <usize as ::std::iter::Step>::steps_between(
147 &Self::index(*start),
153 fn forward_checked(start: Self, u: usize) -> Option<Self> {
154 Self::index(start).checked_add(u).map(Self::from_usize)
158 fn backward_checked(start: Self, u: usize) -> Option<Self> {
159 Self::index(start).checked_sub(u).map(Self::from_usize)
163 // Safety: The implementation of `Step` upholds all invariants.
164 unsafe impl ::std::iter::TrustedStep for #name {}
170 let debug_impl = match debug_format {
171 DebugFormat::Custom => quote! {},
172 DebugFormat::Format(format) => {
174 impl ::std::fmt::Debug for #name {
175 fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
176 write!(fmt, #format, self.as_u32())
182 let spec_partial_eq_impl = if let Lit::Int(max) = &max {
183 if let Ok(max_val) = max.base10_parse::<u32>() {
185 impl core::option::SpecOptionPartialEq for #name {
187 fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
188 if #max_val < u32::MAX {
189 l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1)
192 (Some(l), Some(r)) => r == l,
193 (None, None) => true,
209 #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
210 #[rustc_layout_scalar_valid_range_end(#max)]
211 #[rustc_pass_by_value]
219 /// Maximum value the index can take, as a `u32`.
220 #vis const MAX_AS_U32: u32 = #max;
222 /// Maximum value the index can take.
223 #vis const MAX: Self = Self::from_u32(#max);
225 /// Creates a new index from a given `usize`.
229 /// Will panic if `value` exceeds `MAX`.
231 #vis const fn from_usize(value: usize) -> Self {
232 assert!(value <= (#max as usize));
233 // SAFETY: We just checked that `value <= max`.
235 Self::from_u32_unchecked(value as u32)
239 /// Creates a new index from a given `u32`.
243 /// Will panic if `value` exceeds `MAX`.
245 #vis const fn from_u32(value: u32) -> Self {
246 assert!(value <= #max);
247 // SAFETY: We just checked that `value <= max`.
249 Self::from_u32_unchecked(value)
253 /// Creates a new index from a given `u32`.
257 /// The provided value must be less than or equal to the maximum value for the newtype.
258 /// Providing a value outside this range is undefined due to layout restrictions.
260 /// Prefer using `from_u32`.
262 #vis const unsafe fn from_u32_unchecked(value: u32) -> Self {
263 Self { private: value }
266 /// Extracts the value of this index as a `usize`.
268 #vis const fn index(self) -> usize {
272 /// Extracts the value of this index as a `u32`.
274 #vis const fn as_u32(self) -> u32 {
278 /// Extracts the value of this index as a `usize`.
280 #vis const fn as_usize(self) -> usize {
281 self.as_u32() as usize
285 impl std::ops::Add<usize> for #name {
288 fn add(self, other: usize) -> Self {
289 Self::from_usize(self.index() + other)
293 impl rustc_index::vec::Idx for #name {
295 fn new(value: usize) -> Self {
296 Self::from_usize(value)
300 fn index(self) -> usize {
307 #spec_partial_eq_impl
309 impl From<#name> for u32 {
311 fn from(v: #name) -> u32 {
316 impl From<#name> for usize {
318 fn from(v: #name) -> usize {
323 impl From<usize> for #name {
325 fn from(value: usize) -> Self {
326 Self::from_usize(value)
330 impl From<u32> for #name {
332 fn from(value: u32) -> Self {
333 Self::from_u32(value)
343 pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
344 let input = parse_macro_input!(input as Newtype);