1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::{format_ident, quote};
4use syn::{parse_quote, spanned::Spanned, Attribute, ItemEnum, ItemStruct};
5
6#[proc_macro_attribute]
21pub fn parse_more(_args: TokenStream, input: TokenStream) -> TokenStream {
22 if let Ok(mut struct_item) = syn::parse::<ItemStruct>(input.clone()) {
23 let struct_ident = &struct_item.ident;
24
25 let mut named_generics = struct_item.generics.clone();
26 named_generics.params.iter_mut().for_each(|param| match param {
27 syn::GenericParam::Type(type_param) => type_param.default = None,
28 syn::GenericParam::Const(const_param) => const_param.default = None,
29 _ => {}
30 });
31 let mut generics = named_generics.clone();
32 generics.params.iter_mut().for_each(|param| match param {
33 syn::GenericParam::Type(type_param) => {
34 type_param.bounds.push(syn::TypeParamBound::Trait(parse_quote!(parse_more::ParseMore)));
35 },
36 _ => {}
37 });
38
39 let mut parsed = vec![];
40 let mut field_idents = vec![];
41
42 let edit_attributes = |attrs: &mut Vec<Attribute>, parsed: &mut Vec<_>| {
43 attrs.iter().cloned().enumerate().filter_map(|(i, attribute)| {
45 if attribute.path().segments.last().is_some_and(|arg | arg.ident == "filler") {
46 let path = attribute.path();
47 let path_struct = format_ident!("__AvoidImportWarning{}", i);
48 match attribute.parse_args::<syn::Type>() {
49 Err(e) => Some(Err(e)),
50 Ok(ty) => {
51 parsed.push(quote! {
52 input.parse::<parse_more::ParseMoreWrapper<#ty>>()?;
53 #[#path]
54 struct #path_struct;
55 });
56 None
57 }
58 }
59 } else {
60 Some(Ok(attribute))
61 }
62 }).collect::<Result<Vec<_>, _>>()
63 };
64
65 for field in &mut struct_item.fields {
66 let field_ident = &field.ident;
67 let field_type = &field.ty;
68
69 field.attrs = match edit_attributes(&mut field.attrs, &mut parsed) {
71 Ok(attrs) => attrs,
72 Err(e) => return e.into_compile_error().into(),
73 };
74
75 field_idents.push(field_ident.clone());
77 parsed.push(quote! {
78 let #field_ident = input.parse::<parse_more::ParseMoreWrapper<#field_type>>()?.0;
79 });
80 }
81
82 quote! {
83 #struct_item
84 impl #generics parse_more::ParseMore for #struct_ident #named_generics {
85 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
86 #(#parsed)*
87 Ok(Self {
88 #(#field_idents),*
89 })
90 }
91 }
92 }
93 } else if let Ok(enum_item) = syn::parse::<ItemEnum>(input) {
94 let enum_ident = &enum_item.ident;
95
96 let mut named_generics = enum_item.generics.clone();
97 named_generics.params.iter_mut().for_each(|param| match param {
98 syn::GenericParam::Type(type_param) => type_param.default = None,
99 syn::GenericParam::Const(const_param) => const_param.default = None,
100 _ => {}
101 });
102 let mut generics = named_generics.clone();
103 generics.params.iter_mut().for_each(|param| match param {
104 syn::GenericParam::Type(type_param) => {
105 type_param.bounds.push(syn::TypeParamBound::Trait(parse_quote!(parse_more::ParseMore)));
106 },
107 _ => {}
108 });
109
110 let mut parsed = vec![];
111
112 for (i, variant) in enum_item.variants.iter().enumerate() {
113 let variant_ident = &variant.ident;
114 if variant.fields.len() != 1 {
117 return syn::Error::new(variant.fields.span(), "ParseMore derive macro require that enum variants contains exactly one type.").into_compile_error().into();
118 }
119 let variant_type = &variant.fields.iter().next().unwrap().ty;
120
121 let error = if i == 0 {
123 quote! {
124 err = e
125 }
126 } else {
127 quote! {
128 err.combine(e)
129 }
130 };
131 parsed.push(quote! {
134 match input.fork().parse::<parse_more::ParseMoreWrapper<#variant_type>>() {
135 Ok(_) => return Ok(Self::#variant_ident(input.parse::<parse_more::ParseMoreWrapper<#variant_type>>().unwrap().0)),
136 Err(e) => #error,
137 }
138 });
139 }
140
141 quote! {
142 #enum_item
143 impl #generics parse_more::ParseMore for #enum_ident #named_generics {
144 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
145 let mut err;
146 #(#parsed)*
147 Err(err)
148 }
149 }
150 }
151 } else {
152 syn::Error::new(
153 Span::call_site(),
154 "This macro attribute must be applied on a struct or an enum",
155 )
156 .into_compile_error()
157 }
158 .into()
159}
160
161#[proc_macro_attribute]
176pub fn filler(_args: TokenStream, _input: TokenStream) -> TokenStream {
177 TokenStream::new()
178}