Skip to content

Commit

Permalink
#[var(get=f, set=f)]: properly handle #[func]s that have been rename…
Browse files Browse the repository at this point in the history
…d with (rename=godot_name)
  • Loading branch information
0x53A committed Jan 20, 2025
1 parent 40186f3 commit e8a3c98
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 8 deletions.
5 changes: 5 additions & 0 deletions godot-macros/src/class/data_models/field_var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::class::{
into_signature_info, make_existence_check, make_method_registration, Field, FieldHint,
FuncDefinition,
};
use crate::util::make_function_registered_name_constant;
use crate::util::KvParser;
use crate::{util, ParseResult};

Expand Down Expand Up @@ -200,10 +201,14 @@ impl GetterSetterImpl {
}
}

let constant_declaration =
make_function_registered_name_constant(class_name, &function_name, &None, &vec![]);

let function_impl = quote! {
pub #signature {
#function_body
}
#constant_declaration
};

let signature = util::parse_signature(signature);
Expand Down
12 changes: 11 additions & 1 deletion godot-macros/src/class/data_models/inherent_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::class::{
make_signal_registrations, ConstDefinition, FuncDefinition, RpcAttr, RpcMode, SignalDefinition,
SignatureInfo, TransferMode,
};
use crate::util::{bail, c_str, ident, require_api_version, KvParser};
use crate::util::{
bail, c_str, ident, make_function_registered_name_constants, require_api_version, KvParser,
};
use crate::{handle_mutually_exclusive_keys, util, ParseResult};

use proc_macro2::{Delimiter, Group, Ident, TokenStream};
Expand Down Expand Up @@ -84,6 +86,8 @@ pub fn transform_inherent_impl(
let (funcs, signals) = process_godot_fns(&class_name, &mut impl_block, meta.secondary)?;
let consts = process_godot_constants(&mut impl_block)?;

let func_export_name_constants = make_function_registered_name_constants(&funcs, &class_name);

#[cfg(all(feature = "register-docs", since_api = "4.3"))]
let docs = crate::docs::make_inherent_impl_docs(&funcs, &consts, &signals);
#[cfg(not(all(feature = "register-docs", since_api = "4.3")))]
Expand Down Expand Up @@ -174,6 +178,9 @@ pub fn transform_inherent_impl(
#trait_impl
#fill_storage
#class_registration
impl #class_name{
#( #func_export_name_constants )*
}
};

Ok(result)
Expand All @@ -184,6 +191,9 @@ pub fn transform_inherent_impl(
let result = quote! {
#impl_block
#fill_storage
impl #class_name{
#( #func_export_name_constants )*
}
};

Ok(result)
Expand Down
22 changes: 15 additions & 7 deletions godot-macros/src/class/data_models/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! Parsing the `var` and `export` attributes on fields.
use crate::class::{Field, FieldVar, Fields, GetSet, GetterSetterImpl, UsageFlags};
use crate::util::{format_function_registered_name_constant, ident};
use proc_macro2::{Ident, TokenStream};
use quote::quote;

Expand Down Expand Up @@ -134,22 +135,24 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
},
};

let getter_name = make_getter_setter(
let getter_tokens = make_getter_setter(
getter.to_impl(class_name, GetSet::Get, field),
&mut getter_setter_impls,
&mut export_tokens,
class_name,
);
let setter_name = make_getter_setter(
let setter_tokens = make_getter_setter(
setter.to_impl(class_name, GetSet::Set, field),
&mut getter_setter_impls,
&mut export_tokens,
class_name,
);

export_tokens.push(quote! {
::godot::register::private::#registration_fn::<#class_name, #field_type>(
#field_name,
#getter_name,
#setter_name,
#getter_tokens,
#setter_tokens,
#hint,
#usage_flags,
);
Expand Down Expand Up @@ -177,7 +180,8 @@ fn make_getter_setter(
getter_setter_impl: Option<GetterSetterImpl>,
getter_setter_impls: &mut Vec<TokenStream>,
export_tokens: &mut Vec<TokenStream>,
) -> String {
class_name: &Ident,
) -> TokenStream {
if let Some(getter_impl) = getter_setter_impl {
let GetterSetterImpl {
function_name,
Expand All @@ -188,8 +192,12 @@ fn make_getter_setter(
getter_setter_impls.push(function_impl);
export_tokens.push(export_token);

function_name.to_string()
let getter_setter_name = function_name.to_string();

let getter_setter_fn_const =
format_function_registered_name_constant(class_name, &ident(&getter_setter_name));
quote! { #class_name::#getter_setter_fn_const }
} else {
String::new()
quote! { "" }
}
}
49 changes: 49 additions & 0 deletions godot-macros/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

// Note: some code duplication with godot-codegen crate.

use crate::class::FuncDefinition;
use crate::ParseResult;
use proc_macro2::{Delimiter, Group, Ident, Literal, TokenStream, TokenTree};
use quote::spanned::Spanned;
use quote::{format_ident, quote, ToTokens, TokenStreamExt};
use venial::Attribute;

mod kv_parser;
mod list_parser;
Expand Down Expand Up @@ -303,3 +305,50 @@ pub fn venial_parse_meta(

venial::parse_item(input)
}

// ----------------------------------------------------------------------------------------------------------------------------------------------

// util functions for handling #[func]s and #[var(get=f, set=f)]

pub fn make_function_registered_name_constants(
funcs: &[FuncDefinition],
class_name: &Ident,
) -> Vec<TokenStream> {
funcs
.iter()
.map(|func| {
make_function_registered_name_constant(
class_name,
&func.signature_info.method_name,
&func.registered_name,
&func.external_attributes,
)
})
.collect()
}

/// funcs can be renamed with `#[func(rename=new_name) fn f();`.
/// To be able to access the renamed function name at a later point, it is saved in a string constant.
pub fn make_function_registered_name_constant(
class_name: &Ident,
func_name: &Ident,
exported_name: &Option<String>,
attributes: &Vec<Attribute>,
) -> TokenStream {
let const_name = format_function_registered_name_constant(class_name, func_name);
let const_value = match &exported_name {
Some(renamed) => renamed.to_string(),
None => func_name.to_string(),
};

quote! {
#(#attributes)*
#[doc(hidden)]
#[allow(non_upper_case_globals)]
pub const #const_name: &str = #const_value;
}
}

pub fn format_function_registered_name_constant(class_name: &Ident, func_name: &Ident) -> Ident {
format_ident!("__gdext_func_{}_{}", class_name, func_name)
}
22 changes: 22 additions & 0 deletions itest/rust/src/object_tests/property_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,3 +482,25 @@ fn override_export() {
fn check_property(property: &Dictionary, key: &str, expected: impl ToGodot) {
assert_eq!(property.get_or_nil(key), expected.to_variant());
}

// ----------------------------------------------------------------------------------------------------------------------------------------------

#[derive(GodotClass)]
#[class(base=Node, init)]
struct RenamedFunc {
#[var(get = get_int_val, set = set_int_val)]
int_val: i32,
}

#[godot_api]
impl RenamedFunc {
#[func(rename=f1)]
pub fn get_int_val(&self) -> i32 {
self.int_val
}

#[func(rename=f2)]
pub fn set_int_val(&mut self, val: i32) {
self.int_val = val;
}
}

0 comments on commit e8a3c98

Please sign in to comment.