Skip to content

Commit bbe459b

Browse files
committed
Follow-up changes to "func collections"
1 parent 0edf6e3 commit bbe459b

File tree

6 files changed

+68
-75
lines changed

6 files changed

+68
-75
lines changed

Diff for: godot-macros/src/class/data_models/field_var.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::class::{
1212
into_signature_info, make_existence_check, make_method_registration, Field, FieldHint,
1313
FuncDefinition,
1414
};
15-
use crate::util::make_func_name_constant;
15+
use crate::util::make_funcs_collection_constant;
1616
use crate::util::KvParser;
1717
use crate::{util, ParseResult};
1818

@@ -167,7 +167,7 @@ pub struct GetterSetterImpl {
167167
pub function_name: Ident,
168168
pub function_impl: TokenStream,
169169
pub export_token: TokenStream,
170-
pub func_name_const: TokenStream,
170+
pub funcs_collection_const: TokenStream,
171171
}
172172

173173
impl GetterSetterImpl {
@@ -208,7 +208,8 @@ impl GetterSetterImpl {
208208
}
209209
};
210210

211-
let func_name_const = make_func_name_constant(class_name, &function_name, None, &[]);
211+
let funcs_collection_const =
212+
make_funcs_collection_constant(class_name, &function_name, None, &[]);
212213

213214
let signature = util::parse_signature(signature);
214215
let export_token = make_method_registration(
@@ -234,7 +235,7 @@ impl GetterSetterImpl {
234235
function_name,
235236
function_impl,
236237
export_token,
237-
func_name_const,
238+
funcs_collection_const,
238239
}
239240
}
240241

@@ -243,7 +244,7 @@ impl GetterSetterImpl {
243244
function_name: function_name.clone(),
244245
function_impl: TokenStream::new(),
245246
export_token: make_existence_check(function_name),
246-
func_name_const: TokenStream::new(),
247+
funcs_collection_const: TokenStream::new(),
247248
}
248249
}
249250
}

Diff for: godot-macros/src/class/data_models/inherent_impl.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ use crate::class::{
1111
SignatureInfo, TransferMode,
1212
};
1313
use crate::util::{
14-
bail, c_str, error_fn, format_func_name_struct_name, ident, make_func_name_constants,
14+
bail, c_str, format_funcs_collection_struct, ident, make_func_name_constants,
1515
replace_class_in_path, require_api_version, KvParser,
1616
};
1717
use crate::{handle_mutually_exclusive_keys, util, ParseResult};
1818

1919
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
2020
use quote::spanned::Spanned;
2121
use quote::{format_ident, quote};
22-
use venial::Path;
2322

2423
/// Attribute for user-declared function.
2524
enum ItemAttrType {
@@ -79,6 +78,7 @@ pub struct InherentImplAttr {
7978
pub fn transform_inherent_impl(
8079
meta: InherentImplAttr,
8180
mut impl_block: venial::Impl,
81+
self_path: venial::Path,
8282
) -> ParseResult<TokenStream> {
8383
let class_name = util::validate_impl(&impl_block, None, "godot_api")?;
8484
let class_name_obj = util::class_name_obj(&class_name);
@@ -93,19 +93,15 @@ pub fn transform_inherent_impl(
9393
#[cfg(not(all(feature = "register-docs", since_api = "4.3")))]
9494
let docs = quote! {};
9595

96-
// This is the container struct that holds the names of all registered #[func]s.
97-
// (The struct is declared by the macro derive_godot_class.)
98-
let class_functions_name = format_func_name_struct_name(&class_name);
99-
// As the impl block could be of the form "path::class", and we add a second impl block below, we need the full path, not just the class name.
100-
let this_class_full_path = impl_block.self_ty.as_path().ok_or(error_fn(
101-
"unexpected: the function already checked 'as_path' above in validate_impl",
102-
&impl_block,
103-
))?;
104-
let class_functions_path: Path =
105-
replace_class_in_path(this_class_full_path, class_functions_name);
106-
// For each #[func] in this impl block, we create one constant.
107-
let func_name_constants = make_func_name_constants(&funcs, &class_name);
96+
// Container struct holding names of all registered #[func]s.
97+
// The struct is declared by #[derive(GodotClass)].
98+
let funcs_collection = {
99+
let struct_name = format_funcs_collection_struct(&class_name);
100+
replace_class_in_path(self_path, struct_name)
101+
};
108102

103+
// For each #[func] in this impl block, create one constant.
104+
let func_name_constants = make_func_name_constants(&funcs, &class_name);
109105
let signal_registrations = make_signal_registrations(signals, &class_name_obj);
110106

111107
#[cfg(feature = "codegen-full")]
@@ -181,8 +177,8 @@ pub fn transform_inherent_impl(
181177
#trait_impl
182178
#fill_storage
183179
#class_registration
184-
impl #class_functions_path {
185-
#( #func_name_constants )*
180+
impl #funcs_collection {
181+
#( #func_name_constants )*
186182
}
187183
};
188184

@@ -194,8 +190,8 @@ pub fn transform_inherent_impl(
194190
let result = quote! {
195191
#impl_block
196192
#fill_storage
197-
impl #class_functions_path {
198-
#( #func_name_constants )*
193+
impl #funcs_collection {
194+
#( #func_name_constants )*
199195
}
200196
};
201197

Diff for: godot-macros/src/class/data_models/property.rs

+20-28
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8-
//! Parsing the `var` and `export` attributes on fields.
8+
//! Parses the `#[var]` and `#[export]` attributes on fields.
99
1010
use crate::class::{Field, FieldVar, Fields, GetSet, GetterSetterImpl, UsageFlags};
11-
use crate::util::{format_func_name_constant_name, format_func_name_struct_name, ident};
11+
use crate::util::{format_funcs_collection_constant, format_funcs_collection_struct};
1212
use proc_macro2::{Ident, TokenStream};
1313
use quote::quote;
1414

@@ -136,7 +136,7 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
136136
},
137137
};
138138

139-
// Note: (getter/setter)_tokens can be either a path ``Class_Functions::constant_name`` or an empty string ``""``.
139+
// Note: {getter,setter}_tokens can be either a path `Class_Functions::constant_name` or an empty string `""`.
140140

141141
let getter_tokens = make_getter_setter(
142142
getter.to_impl(class_name, GetSet::Get, field),
@@ -164,9 +164,9 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
164164
});
165165
}
166166

167-
// For each generated #[func], add a const.
168-
// This is the name of the container struct, which is declared by the derive macro GodotClass.
169-
let class_functions_name = format_func_name_struct_name(class_name);
167+
// For each generated #[func], add a const declaration.
168+
// This is the name of the container struct, which is declared by #[derive(GodotClass)].
169+
let class_functions_name = format_funcs_collection_struct(class_name);
170170

171171
quote! {
172172
impl #class_name {
@@ -196,26 +196,18 @@ fn make_getter_setter(
196196
export_tokens: &mut Vec<TokenStream>,
197197
class_name: &Ident,
198198
) -> TokenStream {
199-
if let Some(getter_impl) = getter_setter_impl {
200-
let GetterSetterImpl {
201-
function_name,
202-
function_impl,
203-
export_token,
204-
func_name_const,
205-
} = getter_impl;
206-
207-
getter_setter_impls.push(function_impl);
208-
func_name_consts.push(func_name_const);
209-
export_tokens.push(export_token);
210-
211-
let getter_setter_name = function_name.to_string();
212-
213-
let class_functions_name = format_func_name_struct_name(class_name);
214-
215-
let getter_setter_fn_const =
216-
format_func_name_constant_name(class_name, &ident(&getter_setter_name));
217-
quote! { #class_functions_name::#getter_setter_fn_const }
218-
} else {
219-
quote! { "" }
220-
}
199+
let Some(gs) = getter_setter_impl else {
200+
return quote! { "" };
201+
};
202+
203+
getter_setter_impls.push(gs.function_impl);
204+
func_name_consts.push(gs.funcs_collection_const);
205+
export_tokens.push(gs.export_token);
206+
207+
// Getters/setters are, like #[func]s, subject to additional code generation: a constant inside a "funcs collection" struct
208+
// stores their Godot name and can be used as an indirection to refer to their true name from other procedural macros.
209+
let funcs_collection = format_funcs_collection_struct(class_name);
210+
let constant = format_funcs_collection_constant(class_name, &gs.function_name);
211+
212+
quote! { #funcs_collection::#constant }
221213
}

Diff for: godot-macros/src/class/derive_godot_class.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use crate::class::{
1313
FieldVar, Fields, SignatureInfo,
1414
};
1515
use crate::util::{
16-
bail, error, format_func_name_struct_name, ident, path_ends_with_complex, require_api_version,
17-
KvParser,
16+
bail, error, format_funcs_collection_struct, ident, path_ends_with_complex,
17+
require_api_version, KvParser,
1818
};
1919
use crate::{handle_mutually_exclusive_keys, util, ParseResult};
2020

@@ -138,7 +138,7 @@ pub fn derive_godot_class(item: venial::Item) -> ParseResult<TokenStream> {
138138
}
139139

140140
// Declares a dummy struct that, for each #[func], holds a constant that maps the rust name to the name under which it is registered in godot.
141-
let class_functions_name = format_func_name_struct_name(class_name);
141+
let class_functions_name = format_funcs_collection_struct(class_name);
142142
let class_functions_struct = quote! {
143143
#[doc(hidden)]
144144
pub struct #class_functions_name { }

Diff for: godot-macros/src/class/godot_api.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn attribute_godot_api(
4141
)?;
4242
}
4343

44-
if decl.self_ty.as_path().is_none() {
44+
let Some(self_path) = decl.self_ty.as_path() else {
4545
return bail!(decl, "invalid Self type for #[godot_api] impl");
4646
};
4747

@@ -57,7 +57,7 @@ pub fn attribute_godot_api(
5757
transform_trait_impl(decl)
5858
} else {
5959
match parse_inherent_impl_attr(meta) {
60-
Ok(meta) => transform_inherent_impl(meta, decl),
60+
Ok(meta) => transform_inherent_impl(meta, decl, self_path),
6161
Err(err) => Err(err),
6262
}
6363
}

Diff for: godot-macros/src/util/mod.rs

+23-19
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::ParseResult;
1212
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, TokenStream, TokenTree};
1313
use quote::spanned::Spanned;
1414
use quote::{format_ident, quote, ToTokens, TokenStreamExt};
15-
use venial::{Attribute, Path, PathSegment};
1615

1716
mod kv_parser;
1817
mod list_parser;
@@ -248,14 +247,17 @@ pub(crate) fn extract_cfg_attrs(
248247
let Some(attr_name) = attr.get_single_path_segment() else {
249248
return false;
250249
};
250+
251251
// #[cfg(condition)]
252252
if attr_name == "cfg" {
253253
return true;
254254
}
255-
// #[cfg_attr(condition, attributes...)], note that there can be multiple attributes seperated by comma.
255+
256+
// #[cfg_attr(condition, attributes...)]. Multiple attributes can be seperated by comma.
256257
if attr_name == "cfg_attr" && attr.value.to_token_stream().to_string().contains("cfg(") {
257258
return true;
258259
}
260+
259261
false
260262
})
261263
}
@@ -329,7 +331,7 @@ pub fn make_func_name_constants(funcs: &[FuncDefinition], class_name: &Ident) ->
329331
.into_iter()
330332
.collect::<Vec<_>>();
331333

332-
make_func_name_constant(
334+
make_funcs_collection_constant(
333335
class_name,
334336
&func.signature_info.method_name,
335337
func.registered_name.as_ref(),
@@ -339,15 +341,17 @@ pub fn make_func_name_constants(funcs: &[FuncDefinition], class_name: &Ident) ->
339341
.collect()
340342
}
341343

342-
/// Funcs can be renamed with `#[func(rename=new_name) fn f();`.
343-
/// To be able to access the renamed function name at a later point, it is saved in a string constant.
344-
pub fn make_func_name_constant(
344+
/// Returns a `const` declaration for the funcs collection struct.
345+
///
346+
/// User-defined functions can be renamed with `#[func(rename=new_name)]`. To be able to access the renamed function name from another macro,
347+
/// a constant is used as indirection.
348+
pub fn make_funcs_collection_constant(
345349
class_name: &Ident,
346350
func_name: &Ident,
347351
registered_name: Option<&String>,
348-
attributes: &[&Attribute],
352+
attributes: &[&venial::Attribute],
349353
) -> TokenStream {
350-
let const_name = format_func_name_constant_name(class_name, func_name);
354+
let const_name = format_funcs_collection_constant(class_name, func_name);
351355
let const_value = match &registered_name {
352356
Some(renamed) => renamed.to_string(),
353357
None => func_name.to_string(),
@@ -365,14 +369,14 @@ pub fn make_func_name_constant(
365369
}
366370
}
367371

368-
/// Converts "path::class" to "path::new_class".
369-
pub fn replace_class_in_path(path: Path, new_class: Ident) -> Path {
372+
/// Converts `path::class` to `path::new_class`.
373+
pub fn replace_class_in_path(path: venial::Path, new_class: Ident) -> venial::Path {
370374
match path.segments.as_slice() {
371375
// Can't happen, you have at least one segment (the class name).
372-
[] => panic!("unexpected: empty path"),
376+
[] => unreachable!("empty path"),
373377

374-
[_single] => Path {
375-
segments: vec![PathSegment {
378+
[_single] => venial::Path {
379+
segments: vec![venial::PathSegment {
376380
ident: new_class,
377381
generic_args: None,
378382
tk_separator_colons: None,
@@ -382,25 +386,25 @@ pub fn replace_class_in_path(path: Path, new_class: Ident) -> Path {
382386
[path @ .., _last] => {
383387
let mut segments = vec![];
384388
segments.extend(path.iter().cloned());
385-
segments.push(PathSegment {
389+
segments.push(venial::PathSegment {
386390
ident: new_class,
387391
generic_args: None,
388392
tk_separator_colons: Some([
389393
Punct::new(':', Spacing::Joint),
390394
Punct::new(':', Spacing::Alone),
391395
]),
392396
});
393-
Path { segments }
397+
venial::Path { segments }
394398
}
395399
}
396400
}
397401

398-
/// Returns the name of the constant that will be autogenerated.
399-
pub fn format_func_name_constant_name(_class_name: &Ident, func_name: &Ident) -> Ident {
402+
/// Returns the name of the constant inside the func "collection" struct.
403+
pub fn format_funcs_collection_constant(_class_name: &Ident, func_name: &Ident) -> Ident {
400404
format_ident!("{func_name}")
401405
}
402406

403-
/// Returns the name of the dummy struct that's used as container for all function name constants.
404-
pub fn format_func_name_struct_name(class_name: &Ident) -> Ident {
407+
/// Returns the name of the struct used as collection for all function name constants.
408+
pub fn format_funcs_collection_struct(class_name: &Ident) -> Ident {
405409
format_ident!("__gdext_{class_name}_Functions")
406410
}

0 commit comments

Comments
 (0)