1 use proc_macro2::{Span, TokenStream};
7 syn::custom_keyword!(DEBUG_FORMAT);
8 syn::custom_keyword!(MAX);
9 syn::custom_keyword!(ENCODABLE);
10 syn::custom_keyword!(custom);
11 syn::custom_keyword!(ORD_IMPL);
16 // The user will provide a custom `Debug` impl, so we shouldn't generate
19 // Use the specified format string in the generated `Debug` impl
20 // By default, this is "{}"
24 // We parse the input and emit the output in a single step.
25 // This field stores the final macro output
26 struct Newtype(TokenStream);
28 impl Parse for Newtype {
29 fn parse(input: ParseStream<'_>) -> Result<Self> {
30 let attrs = input.call(Attribute::parse_outer)?;
31 let vis: Visibility = input.parse()?;
32 input.parse::<Token![struct]>()?;
33 let name: Ident = input.parse()?;
36 braced!(body in input);
38 // Any additional `#[derive]` macro paths to apply
39 let mut derive_paths: Vec<Path> = Vec::new();
40 let mut debug_format: Option<DebugFormat> = None;
42 let mut consts = Vec::new();
43 let mut encodable = true;
46 // Parse an optional trailing comma
47 let try_comma = || -> Result<()> {
48 if body.lookahead1().peek(Token![,]) {
49 body.parse::<Token![,]>()?;
54 if body.lookahead1().peek(Token![..]) {
55 body.parse::<Token![..]>()?;
58 if body.lookahead1().peek(kw::DEBUG_FORMAT) {
59 body.parse::<kw::DEBUG_FORMAT>()?;
60 body.parse::<Token![=]>()?;
61 let new_debug_format = if body.lookahead1().peek(kw::custom) {
62 body.parse::<kw::custom>()?;
65 let format_str: LitStr = body.parse()?;
66 DebugFormat::Format(format_str.value())
69 if let Some(old) = debug_format.replace(new_debug_format) {
70 panic!("Specified multiple debug format options: {:?}", old);
74 if body.lookahead1().peek(kw::MAX) {
75 body.parse::<kw::MAX>()?;
76 body.parse::<Token![=]>()?;
77 let val: Lit = body.parse()?;
79 if let Some(old) = max.replace(val) {
80 panic!("Specified multiple MAX: {:?}", old);
84 if body.lookahead1().peek(kw::ENCODABLE) {
85 body.parse::<kw::ENCODABLE>()?;
86 body.parse::<Token![=]>()?;
87 body.parse::<kw::custom>()?;
92 if body.lookahead1().peek(kw::ORD_IMPL) {
93 body.parse::<kw::ORD_IMPL>()?;
94 body.parse::<Token![=]>()?;
95 body.parse::<kw::custom>()?;
100 // We've parsed everything that the user provided, so we're done
105 // Otherwise, we are parsing a user-defined constant
106 let const_attrs = body.call(Attribute::parse_outer)?;
107 body.parse::<Token![const]>()?;
108 let const_name: Ident = body.parse()?;
109 body.parse::<Token![=]>()?;
110 let const_val: Expr = body.parse()?;
112 consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); });
116 let debug_format = debug_format.unwrap_or(DebugFormat::Format("{}".to_string()));
117 // shave off 256 indices at the end to allow space for packing these indices into enums
118 let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site())));
120 let encodable_impls = if encodable {
122 impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name {
123 fn decode(d: &mut D) -> Self {
124 Self::from_u32(d.read_u32())
127 impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
128 fn encode(&self, e: &mut E) {
129 e.emit_u32(self.private);
138 derive_paths.push(parse_quote!(Ord));
139 derive_paths.push(parse_quote!(PartialOrd));
144 impl ::std::iter::Step for #name {
146 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
147 <usize as ::std::iter::Step>::steps_between(
148 &Self::index(*start),
154 fn forward_checked(start: Self, u: usize) -> Option<Self> {
155 Self::index(start).checked_add(u).map(Self::from_usize)
159 fn backward_checked(start: Self, u: usize) -> Option<Self> {
160 Self::index(start).checked_sub(u).map(Self::from_usize)
164 // Safety: The implementation of `Step` upholds all invariants.
165 unsafe impl ::std::iter::TrustedStep for #name {}
171 let debug_impl = match debug_format {
172 DebugFormat::Custom => quote! {},
173 DebugFormat::Format(format) => {
175 impl ::std::fmt::Debug for #name {
176 fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
177 write!(fmt, #format, self.as_u32())
183 let spec_partial_eq_impl = if let Lit::Int(max) = &max {
184 if let Ok(max_val) = max.base10_parse::<u32>() {
186 impl core::option::SpecOptionPartialEq for #name {
188 fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
189 if #max_val < u32::MAX {
190 l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1)
193 (Some(l), Some(r)) => r == l,
194 (None, None) => true,
210 #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
211 #[rustc_layout_scalar_valid_range_end(#max)]
212 #[rustc_pass_by_value]
220 /// Maximum value the index can take, as a `u32`.
221 #vis const MAX_AS_U32: u32 = #max;
223 /// Maximum value the index can take.
224 #vis const MAX: Self = Self::from_u32(#max);
226 /// Creates a new index from a given `usize`.
230 /// Will panic if `value` exceeds `MAX`.
232 #vis const fn from_usize(value: usize) -> Self {
233 assert!(value <= (#max as usize));
234 // SAFETY: We just checked that `value <= max`.
236 Self::from_u32_unchecked(value as u32)
240 /// Creates a new index from a given `u32`.
244 /// Will panic if `value` exceeds `MAX`.
246 #vis const fn from_u32(value: u32) -> Self {
247 assert!(value <= #max);
248 // SAFETY: We just checked that `value <= max`.
250 Self::from_u32_unchecked(value)
254 /// Creates a new index from a given `u32`.
258 /// The provided value must be less than or equal to the maximum value for the newtype.
259 /// Providing a value outside this range is undefined due to layout restrictions.
261 /// Prefer using `from_u32`.
263 #vis const unsafe fn from_u32_unchecked(value: u32) -> Self {
264 Self { private: value }
267 /// Extracts the value of this index as a `usize`.
269 #vis const fn index(self) -> usize {
273 /// Extracts the value of this index as a `u32`.
275 #vis const fn as_u32(self) -> u32 {
279 /// Extracts the value of this index as a `usize`.
281 #vis const fn as_usize(self) -> usize {
282 self.as_u32() as usize
286 impl std::ops::Add<usize> for #name {
289 fn add(self, other: usize) -> Self {
290 Self::from_usize(self.index() + other)
294 impl rustc_index::vec::Idx for #name {
296 fn new(value: usize) -> Self {
297 Self::from_usize(value)
301 fn index(self) -> usize {
308 #spec_partial_eq_impl
310 impl From<#name> for u32 {
312 fn from(v: #name) -> u32 {
317 impl From<#name> for usize {
319 fn from(v: #name) -> usize {
324 impl From<usize> for #name {
326 fn from(value: usize) -> Self {
327 Self::from_usize(value)
331 impl From<u32> for #name {
333 fn from(value: u32) -> Self {
334 Self::from_u32(value)
344 pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
345 let input = parse_macro_input!(input as Newtype);