Skip to content

Commit 99b76e6

Browse files
committed
Change #[hint(typed_signals = false)] to #[godot_api(no_typed_signals)]
#[hint] should really be hints: injecting information that the proc-macro cannot infer, like with #[hint(no_base)] fields. We could use #[hint(has_base_field = true, class_visibility = pub)] or so in the future. For now, disabling entire typed-signal API (including traits) can be done on #[godot_api] itself.
1 parent 0c716ce commit 99b76e6

File tree

5 files changed

+44
-33
lines changed

5 files changed

+44
-33
lines changed

godot-macros/src/class/data_models/inherent_impl.rs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::{handle_mutually_exclusive_keys, util, ParseResult};
1919
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
2020
use quote::spanned::Spanned;
2121
use quote::{format_ident, quote};
22-
use venial::Impl;
2322

2423
/// Attribute for user-declared function.
2524
enum ItemAttrType {
@@ -72,19 +71,17 @@ struct SignalAttr {
7271
pub no_builder: bool,
7372
}
7473

75-
#[derive(Default)]
76-
pub(crate) struct GodotApiHints {
77-
pub has_typed_signals: Option<bool>,
78-
}
79-
80-
// ----------------------------------------------------------------------------------------------------------------------------------------------
81-
82-
pub struct InherentImplAttr {
74+
pub(crate) struct InherentImplAttr {
8375
/// For implementation reasons, there can be a single 'primary' impl block and 0 or more 'secondary' impl blocks.
8476
/// For now, this is controlled by a key in the 'godot_api' attribute.
8577
pub secondary: bool,
78+
79+
/// When typed signal generation is explicitly disabled by the user.
80+
pub no_typed_signals: bool,
8681
}
8782

83+
// ----------------------------------------------------------------------------------------------------------------------------------------------
84+
8885
/// Codegen for `#[godot_api] impl MyType`
8986
pub fn transform_inherent_impl(
9087
meta: InherentImplAttr,
@@ -95,8 +92,6 @@ pub fn transform_inherent_impl(
9592
let class_name_obj = util::class_name_obj(&class_name);
9693
let prv = quote! { ::godot::private };
9794

98-
let hints = extract_hint_attribute(&mut impl_block)?;
99-
10095
// Can add extra functions to the end of the impl block.
10196
let (funcs, signals) = process_godot_fns(&class_name, &mut impl_block, meta.secondary)?;
10297
let consts = process_godot_constants(&mut impl_block)?;
@@ -115,8 +110,12 @@ pub fn transform_inherent_impl(
115110

116111
// For each #[func] in this impl block, create one constant.
117112
let func_name_constants = make_funcs_collection_constants(&funcs, &class_name);
118-
let (signal_registrations, signal_symbol_types) =
119-
make_signal_registrations(&signals, &class_name, &class_name_obj, hints)?;
113+
let (signal_registrations, signal_symbol_types) = make_signal_registrations(
114+
&signals,
115+
&class_name,
116+
&class_name_obj,
117+
meta.no_typed_signals,
118+
)?;
120119

121120
#[cfg(feature = "codegen-full")]
122121
let rpc_registrations = crate::class::make_rpc_registrations_fn(&class_name, &funcs);
@@ -214,19 +213,22 @@ pub fn transform_inherent_impl(
214213
}
215214
}
216215

217-
fn extract_hint_attribute(impl_block: &mut Impl) -> ParseResult<GodotApiHints> {
218-
// Could possibly be extended with #[hint(signal_vis = pub)] or so.
219-
220-
// #[hint(typed_signals)]
221-
let has_typed_signals;
216+
/* Re-enable if we allow controlling declarative macros for signals (base_field_macro, visibility_macros).
217+
fn extract_hint_attribute(impl_block: &mut venial:: Impl) -> ParseResult<GodotApiHints> {
218+
// #[hint(has_base_field = BOOL)]
219+
let has_base_field;
222220
if let Some(mut hints) = KvParser::parse_remove(&mut impl_block.attributes, "hint")? {
223-
has_typed_signals = hints.handle_bool("typed_signals")?;
221+
has_base_field = hints.handle_bool("has_base_field")?;
224222
} else {
225-
has_typed_signals = None;
223+
has_base_field = None;
226224
}
227225
228-
Ok(GodotApiHints { has_typed_signals })
226+
// #[hint(class_visibility = pub(crate))]
227+
// ...
228+
229+
Ok(GodotApiHints { has_base_field })
229230
}
231+
*/
230232

231233
fn process_godot_fns(
232234
class_name: &Ident,

godot-macros/src/class/data_models/signal.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
// Some duplication with godot-codegen/signals.rs; see comments there.
99

10-
use crate::class::GodotApiHints;
1110
use crate::util::bail;
1211
use crate::{util, ParseResult};
1312
use proc_macro2::{Delimiter, Ident, TokenStream, TokenTree};
@@ -183,7 +182,7 @@ pub fn make_signal_registrations(
183182
signals: &[SignalDefinition],
184183
class_name: &Ident,
185184
class_name_obj: &TokenStream,
186-
hints: GodotApiHints,
185+
no_typed_signals: bool,
187186
) -> ParseResult<(Vec<TokenStream>, Option<TokenStream>)> {
188187
let mut signal_registrations = Vec::new();
189188

@@ -212,8 +211,11 @@ pub fn make_signal_registrations(
212211
signal_registrations.push(registration);
213212
}
214213

214+
// Rewrite the above using #[cfg].
215215
#[cfg(since_api = "4.2")]
216-
let signal_symbols = Some(make_signal_symbols(class_name, collection_api, hints));
216+
let signal_symbols =
217+
(!no_typed_signals).then(|| make_signal_symbols(class_name, collection_api));
218+
217219
#[cfg(before_api = "4.2")]
218220
let signal_symbols = None;
219221

@@ -389,13 +391,7 @@ fn make_signal_symbols(
389391
class_name: &Ident,
390392
collection_api: SignalCollection,
391393
// max_visibility: SignalVisibility,
392-
hints: GodotApiHints,
393394
) -> TokenStream {
394-
// Return early if typed signals are explicitly disabled.
395-
if hints.has_typed_signals == Some(false) {
396-
return TokenStream::new();
397-
}
398-
399395
// Earlier implementation generated a simplified code when no #[signal] was declared: only WithSignals/WithUserSignals impl, but no own
400396
// collection, instead the associated type pointing to the base class. This has however some problems:
401397
// * Part of the reason for user-defined collection is to store UserSignalObject instead of Gd, which can store &mut self.

godot-macros/src/class/godot_api.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,20 @@ fn parse_inherent_impl_attr(meta: TokenStream) -> Result<super::InherentImplAttr
1717
let item = venial_parse_meta(&meta, format_ident!("godot_api"), &quote! { fn func(); })?;
1818
let mut attr = KvParser::parse_required(item.attributes(), "godot_api", &meta)?;
1919
let secondary = attr.handle_alone("secondary")?;
20+
let no_typed_signals = attr.handle_alone("no_typed_signals")?;
2021
attr.finish()?;
2122

22-
Ok(super::InherentImplAttr { secondary })
23+
if no_typed_signals && secondary {
24+
return bail!(
25+
meta,
26+
"#[godot_api]: keys `secondary` and `no_typed_signals` are mutually exclusive; secondary blocks allow no signals anyway"
27+
)?;
28+
}
29+
30+
Ok(super::InherentImplAttr {
31+
secondary,
32+
no_typed_signals,
33+
})
2334
}
2435

2536
pub fn attribute_godot_api(

godot-macros/src/util/kv_parser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ impl KvParser {
6464
/// Like `parse()`, but removes the attribute from the list.
6565
///
6666
/// Useful for `#[proc_macro_attributes]`, where handled attributes must not show up in resulting code.
67+
// Currently unused.
6768
pub fn parse_remove(
6869
attributes: &mut Vec<venial::Attribute>,
6970
expected: &str,

itest/rust/src/object_tests/object_test.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,8 +997,9 @@ pub mod object_test_gd {
997997
}
998998
use nested::ObjectTest;
999999

1000-
#[godot_api]
1001-
#[hint(typed_signals = false)] // Allows nested::ObjectTest, which would fail otherwise due to generated decl-macro being out-of-scope.
1000+
// Disabling signals allows nested::ObjectTest, which would fail otherwise due to generated decl-macro being out-of-scope.
1001+
#[godot_api(no_typed_signals)]
1002+
// #[hint(has_base_field = false)] // if we allow more fine-grained control in the future
10021003
impl nested::ObjectTest {
10031004
#[func]
10041005
fn pass_object(&self, object: Gd<Object>) -> i64 {

0 commit comments

Comments
 (0)