|
1 | 1 | use syn::{spanned::Spanned, FnArg, ImplItem, ItemImpl, Pat, PatIdent, Signature, Type};
|
2 | 2 |
|
3 |
| -use proc_macro::TokenStream; |
| 3 | +use proc_macro2::TokenStream as TokenStream2; |
4 | 4 | use quote::{quote, ToTokens};
|
5 | 5 | use std::boxed::Box;
|
6 | 6 |
|
@@ -67,115 +67,89 @@ pub(crate) struct ExportArgs {
|
67 | 67 | pub(crate) rpc_mode: RpcMode,
|
68 | 68 | }
|
69 | 69 |
|
70 |
| -pub(crate) fn derive_methods(meta: TokenStream, input: TokenStream) -> TokenStream { |
71 |
| - let (impl_block, export) = match parse_method_export(meta, input) { |
72 |
| - Ok(val) => val, |
73 |
| - Err(toks) => return toks, |
74 |
| - }; |
| 70 | +pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 { |
| 71 | + let (impl_block, export) = impl_gdnative_expose(item_impl); |
75 | 72 |
|
76 |
| - let output = { |
77 |
| - let class_name = export.class_ty; |
78 |
| - |
79 |
| - let builder = syn::Ident::new("builder", proc_macro2::Span::call_site()); |
80 |
| - |
81 |
| - let methods = export |
82 |
| - .methods |
83 |
| - .into_iter() |
84 |
| - .map(|ExportMethod { sig, args }| { |
85 |
| - let sig_span = sig.ident.span(); |
86 |
| - |
87 |
| - let name = sig.ident; |
88 |
| - let name_string = name.to_string(); |
89 |
| - let ret_span = sig.output.span(); |
90 |
| - let ret_ty = match sig.output { |
91 |
| - syn::ReturnType::Default => quote_spanned!(ret_span => ()), |
92 |
| - syn::ReturnType::Type(_, ty) => quote_spanned!( ret_span => #ty ), |
93 |
| - }; |
94 |
| - |
95 |
| - let arg_count = sig.inputs.len(); |
96 |
| - |
97 |
| - if arg_count < 2 { |
98 |
| - return syn::Error::new( |
99 |
| - sig_span, |
100 |
| - "exported methods must take self and owner as arguments", |
101 |
| - ) |
102 |
| - .to_compile_error(); |
103 |
| - } |
| 73 | + let class_name = export.class_ty; |
104 | 74 |
|
105 |
| - let optional_args = match args.optional_args { |
106 |
| - Some(count) => { |
107 |
| - let max_optional = arg_count - 2; // self and owner |
108 |
| - if count > max_optional { |
109 |
| - let message = format!( |
110 |
| - "there can be at most {} optional arguments, got {}", |
111 |
| - max_optional, count, |
112 |
| - ); |
113 |
| - return syn::Error::new(sig_span, message).to_compile_error(); |
114 |
| - } |
115 |
| - count |
116 |
| - } |
117 |
| - None => 0, |
118 |
| - }; |
| 75 | + let builder = syn::Ident::new("builder", proc_macro2::Span::call_site()); |
119 | 76 |
|
120 |
| - let rpc = args.rpc_mode; |
| 77 | + let methods = export |
| 78 | + .methods |
| 79 | + .into_iter() |
| 80 | + .map(|ExportMethod { sig, args }| { |
| 81 | + let sig_span = sig.ident.span(); |
121 | 82 |
|
122 |
| - let args = sig.inputs.iter().enumerate().map(|(n, arg)| { |
123 |
| - let span = arg.span(); |
124 |
| - if n < arg_count - optional_args { |
125 |
| - quote_spanned!(span => #arg ,) |
126 |
| - } else { |
127 |
| - quote_spanned!(span => #[opt] #arg ,) |
128 |
| - } |
129 |
| - }); |
| 83 | + let name = sig.ident; |
| 84 | + let name_string = name.to_string(); |
| 85 | + let ret_span = sig.output.span(); |
| 86 | + let ret_ty = match sig.output { |
| 87 | + syn::ReturnType::Default => quote_spanned!(ret_span => ()), |
| 88 | + syn::ReturnType::Type(_, ty) => quote_spanned!( ret_span => #ty ), |
| 89 | + }; |
130 | 90 |
|
131 |
| - quote_spanned!( sig_span=> |
132 |
| - { |
133 |
| - let method = ::gdnative::godot_wrap_method!( |
134 |
| - #class_name, |
135 |
| - fn #name ( #( #args )* ) -> #ret_ty |
136 |
| - ); |
| 91 | + let arg_count = sig.inputs.len(); |
137 | 92 |
|
138 |
| - #builder.add_method_with_rpc_mode(#name_string, method, #rpc); |
139 |
| - } |
| 93 | + if arg_count < 2 { |
| 94 | + return syn::Error::new( |
| 95 | + sig_span, |
| 96 | + "exported methods must take self and owner as arguments", |
140 | 97 | )
|
141 |
| - }) |
142 |
| - .collect::<Vec<_>>(); |
| 98 | + .to_compile_error(); |
| 99 | + } |
143 | 100 |
|
144 |
| - quote::quote!( |
| 101 | + let optional_args = match args.optional_args { |
| 102 | + Some(count) => { |
| 103 | + let max_optional = arg_count - 2; // self and owner |
| 104 | + if count > max_optional { |
| 105 | + let message = format!( |
| 106 | + "there can be at most {} optional arguments, got {}", |
| 107 | + max_optional, count, |
| 108 | + ); |
| 109 | + return syn::Error::new(sig_span, message).to_compile_error(); |
| 110 | + } |
| 111 | + count |
| 112 | + } |
| 113 | + None => 0, |
| 114 | + }; |
145 | 115 |
|
146 |
| - #impl_block |
| 116 | + let rpc = args.rpc_mode; |
147 | 117 |
|
148 |
| - impl gdnative::nativescript::NativeClassMethods for #class_name { |
| 118 | + let args = sig.inputs.iter().enumerate().map(|(n, arg)| { |
| 119 | + let span = arg.span(); |
| 120 | + if n < arg_count - optional_args { |
| 121 | + quote_spanned!(span => #arg ,) |
| 122 | + } else { |
| 123 | + quote_spanned!(span => #[opt] #arg ,) |
| 124 | + } |
| 125 | + }); |
149 | 126 |
|
150 |
| - fn register(#builder: &::gdnative::nativescript::init::ClassBuilder<Self>) { |
151 |
| - use gdnative::nativescript::init::*; |
| 127 | + quote_spanned!( sig_span=> |
| 128 | + { |
| 129 | + let method = ::gdnative::godot_wrap_method!( |
| 130 | + #class_name, |
| 131 | + fn #name ( #( #args )* ) -> #ret_ty |
| 132 | + ); |
152 | 133 |
|
153 |
| - #(#methods)* |
| 134 | + #builder.add_method_with_rpc_mode(#name_string, method, #rpc); |
154 | 135 | }
|
| 136 | + ) |
| 137 | + }) |
| 138 | + .collect::<Vec<_>>(); |
155 | 139 |
|
156 |
| - } |
| 140 | + quote::quote!( |
157 | 141 |
|
158 |
| - ) |
159 |
| - }; |
| 142 | + #impl_block |
160 | 143 |
|
161 |
| - TokenStream::from(output) |
162 |
| -} |
| 144 | + impl gdnative::nativescript::NativeClassMethods for #class_name { |
| 145 | + fn register(#builder: &::gdnative::nativescript::init::ClassBuilder<Self>) { |
| 146 | + use gdnative::nativescript::init::*; |
163 | 147 |
|
164 |
| -/// Parse the input. |
165 |
| -/// |
166 |
| -/// Returns the TokenStream of the impl block together with a description of methods to export. |
167 |
| -fn parse_method_export( |
168 |
| - _meta: TokenStream, |
169 |
| - input: TokenStream, |
170 |
| -) -> Result<(ItemImpl, ClassMethodExport), TokenStream> { |
171 |
| - let ast = match syn::parse_macro_input::parse::<ItemImpl>(input) { |
172 |
| - Ok(impl_block) => impl_block, |
173 |
| - Err(err) => { |
174 |
| - return Err(err.to_compile_error().into()); |
| 148 | + #(#methods)* |
| 149 | + } |
175 | 150 | }
|
176 |
| - }; |
177 | 151 |
|
178 |
| - Ok(impl_gdnative_expose(ast)) |
| 152 | + ) |
179 | 153 | }
|
180 | 154 |
|
181 | 155 | /// Extract the data to export from the impl block.
|
|
0 commit comments