Skip to content

Commit b4e6fd6

Browse files
authored
Merge pull request #378 from you-win/feature/func-renaming
Feature/func renaming
2 parents 63fdd6b + d6589fc commit b4e6fd6

File tree

7 files changed

+113
-18
lines changed

7 files changed

+113
-18
lines changed

godot-macros/src/derive_godot_class/property/field_var.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use crate::derive_godot_class::{make_existence_check, Field, FieldHint};
88
use crate::method_registration::make_method_registration;
9+
use crate::method_registration::FuncDefinition;
910
use crate::util::KvParser;
1011
use crate::{util, ParseResult};
1112
use proc_macro2::{Ident, TokenStream};
@@ -188,7 +189,13 @@ impl GetterSetterImpl {
188189
};
189190

190191
let signature = util::parse_signature(signature);
191-
let export_token = make_method_registration(class_name, signature);
192+
let export_token = make_method_registration(
193+
class_name,
194+
FuncDefinition {
195+
func: signature,
196+
rename: None,
197+
},
198+
);
192199

193200
Self {
194201
function_name,

godot-macros/src/godot_api.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7-
use crate::method_registration::{make_method_registration, make_virtual_method_callback};
7+
use crate::method_registration::{
8+
make_method_registration, make_virtual_method_callback, FuncDefinition,
9+
};
810
use crate::util;
911
use crate::util::bail;
12+
use crate::util::KvParser;
1013
use proc_macro2::{Ident, TokenStream};
1114
use quote::quote;
1215
use quote::spanned::Spanned;
@@ -46,7 +49,7 @@ pub fn transform(input_decl: Declaration) -> Result<TokenStream, Error> {
4649

4750
/// Attribute for user-declared function
4851
enum BoundAttrType {
49-
Func(AttributeValue),
52+
Func { rename: Option<String> },
5053
Signal(AttributeValue),
5154
Const(AttributeValue),
5255
}
@@ -108,7 +111,7 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
108111

109112
let methods_registration = funcs
110113
.into_iter()
111-
.map(|func| make_method_registration(&class_name, func));
114+
.map(|func_def| make_method_registration(&class_name, func_def));
112115

113116
let consts = process_godot_constants(&mut decl)?;
114117
let mut integer_constant_names = Vec::new();
@@ -198,8 +201,8 @@ fn transform_inherent_impl(mut decl: Impl) -> Result<TokenStream, Error> {
198201
Ok(result)
199202
}
200203

201-
fn process_godot_fns(decl: &mut Impl) -> Result<(Vec<Function>, Vec<Function>), Error> {
202-
let mut func_signatures = vec![];
204+
fn process_godot_fns(decl: &mut Impl) -> Result<(Vec<FuncDefinition>, Vec<Function>), Error> {
205+
let mut func_definitions = vec![];
203206
let mut signal_signatures = vec![];
204207

205208
let mut removed_indexes = vec![];
@@ -229,10 +232,10 @@ fn process_godot_fns(decl: &mut Impl) -> Result<(Vec<Function>, Vec<Function>),
229232
}
230233

231234
match attr.ty {
232-
BoundAttrType::Func(_attr) => {
235+
BoundAttrType::Func { rename } => {
233236
// Signatures are the same thing without body
234237
let sig = util::reduce_to_signature(method);
235-
func_signatures.push(sig);
238+
func_definitions.push(FuncDefinition { func: sig, rename });
236239
}
237240
BoundAttrType::Signal(ref _attr_val) => {
238241
if method.return_ty.is_some() {
@@ -259,7 +262,7 @@ fn process_godot_fns(decl: &mut Impl) -> Result<(Vec<Function>, Vec<Function>),
259262
decl.body_items.remove(index);
260263
}
261264

262-
Ok((func_signatures, signal_signatures))
265+
Ok((func_definitions, signal_signatures))
263266
}
264267

265268
fn process_godot_constants(decl: &mut Impl) -> Result<Vec<Constant>, Error> {
@@ -275,7 +278,7 @@ fn process_godot_constants(decl: &mut Impl) -> Result<Vec<Constant>, Error> {
275278
constant.attributes.remove(attr.index);
276279

277280
match attr.ty {
278-
BoundAttrType::Func(_) => {
281+
BoundAttrType::Func { .. } => {
279282
return bail!(constant, "#[func] can only be used on functions")
280283
}
281284
BoundAttrType::Signal(_) => {
@@ -308,11 +311,20 @@ where
308311
.expect("get_single_path_segment");
309312

310313
let new_found = match attr_name {
311-
name if name == "func" => Some(BoundAttr {
312-
attr_name: attr_name.clone(),
313-
index,
314-
ty: BoundAttrType::Func(attr.value.clone()),
315-
}),
314+
name if name == "func" => {
315+
// TODO you-win (August 8, 2023): handle default values here as well?
316+
317+
// Safe unwrap since #[func] must be present if we got to this point
318+
let mut parser = KvParser::parse(attributes, "func")?.unwrap();
319+
320+
let rename = parser.handle_expr("rename")?.map(|ts| ts.to_string());
321+
322+
Some(BoundAttr {
323+
attr_name: attr_name.clone(),
324+
index,
325+
ty: BoundAttrType::Func { rename },
326+
})
327+
}
316328
name if name == "signal" => {
317329
// TODO once parameters are supported, this should probably be moved to the struct definition
318330
// E.g. a zero-sized type Signal<(i32, String)> with a provided emit(i32, String) method

godot-macros/src/method_registration/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ struct SignatureInfo {
2727
pub ret_type: TokenStream,
2828
}
2929

30+
/// Information used for registering a Rust function with Godot.
31+
pub struct FuncDefinition {
32+
/// Raw information about the Rust function.
33+
pub func: venial::Function,
34+
/// The name the function will be exposed as in Godot. If `None`, the Rust function name is used.
35+
pub rename: Option<String>,
36+
}
37+
3038
/// Returns a closure expression that forwards the parameters to the Rust instance.
3139
fn make_forwarding_closure(class_name: &Ident, signature_info: &SignatureInfo) -> TokenStream {
3240
let method_name = &signature_info.method_name;

godot-macros/src/method_registration/register_method.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use quote::quote;
1515
/// Generates code that registers the specified method for the given class.
1616
pub fn make_method_registration(
1717
class_name: &Ident,
18-
method_signature: venial::Function,
18+
func_definition: super::FuncDefinition,
1919
) -> TokenStream {
20-
let signature_info = get_signature_info(&method_signature);
20+
let signature_info = get_signature_info(&func_definition.func);
2121
let sig_tuple =
2222
util::make_signature_tuple_type(&signature_info.ret_type, &signature_info.param_types);
2323

@@ -33,7 +33,11 @@ pub fn make_method_registration(
3333

3434
// String literals
3535
let class_name_str = class_name.to_string();
36-
let method_name_str = method_name.to_string();
36+
let method_name_str = if let Some(rename) = func_definition.rename {
37+
rename
38+
} else {
39+
method_name.to_string()
40+
};
3741
let param_ident_strs = param_idents.iter().map(|ident| ident.to_string());
3842

3943
quote! {

itest/godot/ManualFfiTests.gd

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,18 @@ func test_option_export():
289289
assert_eq(obj.optional_export, null)
290290

291291
test_node.free()
292+
293+
func test_func_rename():
294+
var func_rename := FuncRename.new()
295+
296+
assert_eq(func_rename.has_method("long_function_name_for_is_true"), false)
297+
assert_eq(func_rename.has_method("is_true"), true)
298+
assert_eq(func_rename.is_true(), true)
299+
300+
assert_eq(func_rename.has_method("give_one_inner"), false)
301+
assert_eq(func_rename.has_method("give_one"), true)
302+
assert_eq(func_rename.give_one(), 1)
303+
304+
assert_eq(func_rename.has_method("renamed_static"), false)
305+
assert_eq(func_rename.has_method("spell_static"), true)
306+
assert_eq(func_rename.spell_static(), "static")

itest/rust/src/func_test.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
use godot::prelude::*;
8+
9+
#[derive(GodotClass)]
10+
#[class(base=RefCounted)]
11+
struct FuncRename;
12+
13+
#[godot_api]
14+
impl FuncRename {
15+
#[func(rename=is_true)]
16+
fn long_function_name_for_is_true(&self) -> bool {
17+
true
18+
}
19+
20+
#[func(rename=give_one)]
21+
fn give_one_inner(&self) -> i32 {
22+
self.give_one()
23+
}
24+
25+
#[func(rename=spell_static)]
26+
fn renamed_static() -> GodotString {
27+
GodotString::from("static")
28+
}
29+
}
30+
31+
impl FuncRename {
32+
/// Unused but present to demonstrate how `rename = ...` can be used to avoid name clashes.
33+
#[allow(dead_code)]
34+
fn is_true(&self) -> bool {
35+
false
36+
}
37+
38+
fn give_one(&self) -> i32 {
39+
1
40+
}
41+
}
42+
43+
#[godot_api]
44+
impl RefCountedVirtual for FuncRename {
45+
fn init(_base: Base<Self::Base>) -> Self {
46+
Self
47+
}
48+
}

itest/rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ mod color_test;
1919
mod derive_variant;
2020
mod dictionary_test;
2121
mod enum_test;
22+
mod func_test;
2223
mod gdscript_ffi_test;
2324
mod init_test;
2425
mod native_structures_test;

0 commit comments

Comments
 (0)