@@ -12,8 +12,8 @@ use quote::{format_ident, quote};
12
12
13
13
/// Holds information known from a signal's definition
14
14
pub struct SignalDefinition {
15
- /// The signal's function signature.
16
- pub signature : venial:: Function ,
15
+ /// The signal's function signature (simplified, not original declaration) .
16
+ pub fn_signature : venial:: Function ,
17
17
18
18
/// The signal's non-gdext attributes (all except #[signal]).
19
19
pub external_attributes : Vec < venial:: Attribute > ,
@@ -24,8 +24,8 @@ pub struct SignalDefinition {
24
24
25
25
/// Extracted syntax info for a declared signal.
26
26
struct SignalDetails < ' a > {
27
- /// `fn my_signal(i: i32, s: GString)`
28
- original_decl : & ' a venial:: Function ,
27
+ /// `fn my_signal(i: i32, s: GString)` -- simplified from original declaration.
28
+ fn_signature : & ' a venial:: Function ,
29
29
/// `MyClass`
30
30
class_name : & ' a Ident ,
31
31
/// `i32`, `GString`
@@ -44,19 +44,21 @@ struct SignalDetails<'a> {
44
44
signal_cfg_attrs : Vec < & ' a venial:: Attribute > ,
45
45
/// `MyClass_MySignal`
46
46
individual_struct_name : Ident ,
47
+ /// Visibility, e.g. `pub(crate)`
48
+ vis_marker : Option < venial:: VisMarker > ,
47
49
}
48
50
49
51
impl < ' a > SignalDetails < ' a > {
50
52
pub fn extract (
51
- original_decl : & ' a venial:: Function ,
53
+ fn_signature : & ' a venial:: Function , // *Not* the original #[signal], just the signature part (no attributes, body, etc).
52
54
class_name : & ' a Ident ,
53
55
external_attributes : & ' a [ venial:: Attribute ] ,
54
56
) -> ParseResult < SignalDetails < ' a > > {
55
57
let mut param_types = vec ! [ ] ;
56
58
let mut param_names = vec ! [ ] ;
57
59
let mut param_names_str = vec ! [ ] ;
58
60
59
- for ( param, _punct) in original_decl . params . inner . iter ( ) {
61
+ for ( param, _punct) in fn_signature . params . inner . iter ( ) {
60
62
match param {
61
63
venial:: FnParam :: Typed ( param) => {
62
64
param_types. push ( param. ty . clone ( ) ) ;
@@ -76,20 +78,21 @@ impl<'a> SignalDetails<'a> {
76
78
. collect ( ) ;
77
79
78
80
let param_tuple = quote ! { ( #( #param_types, ) * ) } ;
79
- let signal_name = & original_decl . name ;
81
+ let signal_name = & fn_signature . name ;
80
82
let individual_struct_name = format_ident ! ( "__godot_Signal_{}_{}" , class_name, signal_name) ;
81
83
82
84
Ok ( Self {
83
- original_decl ,
85
+ fn_signature ,
84
86
class_name,
85
87
param_types,
86
88
param_names,
87
89
param_names_str,
88
90
param_tuple,
89
91
signal_name,
90
- signal_name_str : original_decl . name . to_string ( ) ,
92
+ signal_name_str : fn_signature . name . to_string ( ) ,
91
93
signal_cfg_attrs,
92
94
individual_struct_name,
95
+ vis_marker : fn_signature. vis_marker . clone ( ) ,
93
96
} )
94
97
}
95
98
}
@@ -104,12 +107,12 @@ pub fn make_signal_registrations(
104
107
105
108
for signal in signals {
106
109
let SignalDefinition {
107
- signature ,
110
+ fn_signature ,
108
111
external_attributes,
109
112
has_builder,
110
113
} = signal;
111
114
112
- let details = SignalDetails :: extract ( signature , class_name, external_attributes) ?;
115
+ let details = SignalDetails :: extract ( fn_signature , class_name, external_attributes) ?;
113
116
114
117
// Callable custom functions are only supported in 4.2+, upon which custom signals rely.
115
118
#[ cfg( since_api = "4.2" ) ]
@@ -196,13 +199,19 @@ impl SignalCollection {
196
199
signal_name_str,
197
200
signal_cfg_attrs,
198
201
individual_struct_name,
202
+ vis_marker,
199
203
..
200
204
} = details;
201
205
202
206
self . collection_methods . push ( quote ! {
203
207
// Deliberately not #[doc(hidden)] for IDE completion.
204
208
#( #signal_cfg_attrs) *
205
- fn #signal_name( self ) -> #individual_struct_name<' a> {
209
+ // Note: this could be `pub` always and would still compile (maybe warning with the following message).
210
+ // associated function `SignalCollection::my_signal` is reachable at visibility `pub(crate)`
211
+ //
212
+ // However, it would still lead to a compile error when declaring the individual signal struct `pub` (or any other
213
+ // visibility that exceeds the class visibility). So, we can as well declare the visibility here.
214
+ #vis_marker fn #signal_name( self ) -> #individual_struct_name<' a> {
206
215
#individual_struct_name {
207
216
typed: :: godot:: register:: TypedSignal :: new( self . __internal_obj, #signal_name_str)
208
217
}
@@ -219,14 +228,15 @@ impl SignalCollection {
219
228
}
220
229
221
230
fn make_signal_individual_struct ( details : & SignalDetails ) -> TokenStream {
222
- let emit_params = & details. original_decl . params ;
231
+ let emit_params = & details. fn_signature . params ;
223
232
224
233
let SignalDetails {
225
234
class_name,
226
235
param_names,
227
236
param_tuple,
228
237
signal_cfg_attrs,
229
238
individual_struct_name,
239
+ vis_marker,
230
240
..
231
241
} = details;
232
242
@@ -235,9 +245,9 @@ fn make_signal_individual_struct(details: &SignalDetails) -> TokenStream {
235
245
// #(#signal_cfg_attrs)* pub mod #module_name { use super::*; ... }
236
246
// #(#signal_cfg_attrs)* pub(crate) use #module_name::#individual_struct_name;
237
247
// However, there are some challenges:
238
- // - Visibility becomes a pain to handle ( rustc doesn't like re-exporting private symbols as pub, and we can't know the visibility of the
239
- // surrounding class struct). Having signals always-public is much less of a headache, requires less choice on the user side
240
- // (pub/pub(crate)/nothing on #[signal]), and likely good enough for the moment .
248
+ // - Visibility is a pain to handle: rustc doesn't like re-exporting private symbols as pub, and we can't know the visibility of the
249
+ // surrounding class struct. Users must explicitly declare #[signal]s `pub` if they want wider visibility; this must not exceed the
250
+ // visibility of the class itself .
241
251
// - Not yet clear if we should have each signal + related types in separate module. If #[signal] is supported in #[godot_api(secondary)]
242
252
// impl blocks, then we would have to group them by the impl block. Rust doesn't allow partial modules, so they'd need to have individual
243
253
// names as well, possibly explicitly chosen by the user.
@@ -248,7 +258,7 @@ fn make_signal_individual_struct(details: &SignalDetails) -> TokenStream {
248
258
#( #signal_cfg_attrs) *
249
259
#[ allow( non_camel_case_types) ]
250
260
#[ doc( hidden) ] // Signal struct is hidden, but the method returning it is not (IDE completion).
251
- struct #individual_struct_name<' a> {
261
+ #vis_marker struct #individual_struct_name<' a> {
252
262
#[ doc( hidden) ]
253
263
typed: :: godot:: register:: TypedSignal <' a, #class_name, #param_tuple>,
254
264
}
0 commit comments