Skip to content

Commit 289f5df

Browse files
authored
Merge pull request #964 from godot-rust/qol/signal-cleanup
Minor signal cleanup; prevent `#[signal]` from being used in secondary impl blocks
2 parents 032af6e + 7cf2c4e commit 289f5df

File tree

5 files changed

+104
-140
lines changed

5 files changed

+104
-140
lines changed

godot-core/src/init/mod.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::out;
1717
pub use sys::GdextBuild;
1818

1919
#[doc(hidden)]
20-
// TODO consider body safe despite unsafe function, and explicitly mark unsafe {} locations
20+
#[deny(unsafe_op_in_unsafe_fn)]
2121
pub unsafe fn __gdext_load_library<E: ExtensionLibrary>(
2222
get_proc_address: sys::GDExtensionInterfaceGetProcAddress,
2323
library: sys::GDExtensionClassLibraryPtr,
@@ -41,7 +41,10 @@ pub unsafe fn __gdext_load_library<E: ExtensionLibrary>(
4141

4242
let config = sys::GdextConfig::new(tool_only_in_editor);
4343

44-
sys::initialize(get_proc_address, library, config);
44+
// SAFETY: no custom code has run yet + no other thread is accessing global handle.
45+
unsafe {
46+
sys::initialize(get_proc_address, library, config);
47+
}
4548

4649
// Currently no way to express failure; could be exposed to E if necessary.
4750
// No early exit, unclear if Godot still requires output parameters to be set.
@@ -54,7 +57,10 @@ pub unsafe fn __gdext_load_library<E: ExtensionLibrary>(
5457
deinitialize: Some(ffi_deinitialize_layer::<E>),
5558
};
5659

57-
*init = godot_init_params;
60+
// SAFETY: Godot is responsible for passing us a valid pointer.
61+
unsafe {
62+
*init = godot_init_params;
63+
}
5864

5965
success as u8
6066
};

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

+17-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* License, v. 2.0. If a copy of the MPL was not distributed with this
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
7+
78
use crate::class::{
89
into_signature_info, make_constant_registration, make_method_registration,
910
make_signal_registrations, ConstDefinition, FuncDefinition, RpcAttr, RpcMode, SignalDefinition,
@@ -66,7 +67,7 @@ struct FuncAttr {
6667

6768
pub struct InherentImplAttr {
6869
/// For implementation reasons, there can be a single 'primary' impl block and 0 or more 'secondary' impl blocks.
69-
/// For now this is controlled by a key in the the 'godot_api' attribute
70+
/// For now, this is controlled by a key in the 'godot_api' attribute.
7071
pub secondary: bool,
7172
}
7273

@@ -80,7 +81,7 @@ pub fn transform_inherent_impl(
8081
let prv = quote! { ::godot::private };
8182

8283
// Can add extra functions to the end of the impl block.
83-
let (funcs, signals) = process_godot_fns(&class_name, &mut impl_block)?;
84+
let (funcs, signals) = process_godot_fns(&class_name, &mut impl_block, meta.secondary)?;
8485
let consts = process_godot_constants(&mut impl_block)?;
8586

8687
#[cfg(all(feature = "register-docs", since_api = "4.3"))]
@@ -107,16 +108,13 @@ pub fn transform_inherent_impl(
107108

108109
let fill_storage = quote! {
109110
::godot::sys::plugin_execute_pre_main!({
110-
#method_storage_name.lock().unwrap().push(||{
111-
111+
#method_storage_name.lock().unwrap().push(|| {
112112
#( #method_registrations )*
113113
#( #signal_registrations )*
114-
115114
});
116-
#constants_storage_name.lock().unwrap().push(||{
117115

116+
#constants_storage_name.lock().unwrap().push(|| {
118117
#constant_registration
119-
120118
});
121119
});
122120
};
@@ -155,7 +153,6 @@ pub fn transform_inherent_impl(
155153
};
156154

157155
let class_registration = quote! {
158-
159156
::godot::sys::plugin_add!(__GODOT_PLUGIN_REGISTRY in #prv; #prv::ClassPlugin {
160157
class_name: #class_name_obj,
161158
item: #prv::PluginItem::InherentImpl(#prv::InherentImpl {
@@ -169,7 +166,6 @@ pub fn transform_inherent_impl(
169166
}),
170167
init_level: <#class_name as ::godot::obj::GodotClass>::INIT_LEVEL,
171168
});
172-
173169
};
174170

175171
let result = quote! {
@@ -182,7 +178,7 @@ pub fn transform_inherent_impl(
182178

183179
Ok(result)
184180
} else {
185-
// We are in a secondary `impl` block, so most of the work has already been done
181+
// We are in a secondary `impl` block, so most of the work has already been done,
186182
// and we just need to add our registration functions in the storage defined by the primary `impl` block.
187183

188184
let result = quote! {
@@ -197,6 +193,7 @@ pub fn transform_inherent_impl(
197193
fn process_godot_fns(
198194
class_name: &Ident,
199195
impl_block: &mut venial::Impl,
196+
is_secondary_impl: bool,
200197
) -> ParseResult<(Vec<FuncDefinition>, Vec<SignalDefinition>)> {
201198
let mut func_definitions = vec![];
202199
let mut signal_definitions = vec![];
@@ -286,9 +283,16 @@ fn process_godot_fns(
286283
rpc_info,
287284
});
288285
}
286+
289287
ItemAttrType::Signal(ref _attr_val) => {
288+
if is_secondary_impl {
289+
return attr.bail(
290+
"#[signal] is not currently supported in secondary impl blocks",
291+
function,
292+
);
293+
}
290294
if function.return_ty.is_some() {
291-
return attr.bail("return types are not supported", function);
295+
return attr.bail("return types in #[signal] are not supported", function);
292296
}
293297

294298
let external_attributes = function.attributes.clone();
@@ -301,6 +305,7 @@ fn process_godot_fns(
301305

302306
removed_indexes.push(index);
303307
}
308+
304309
ItemAttrType::Const(_) => {
305310
return attr.bail(
306311
"#[constant] can only be used on associated constant",
@@ -541,12 +546,7 @@ where
541546
}
542547

543548
// #[signal]
544-
name if name == "signal" => {
545-
// TODO once parameters are supported, this should probably be moved to the struct definition
546-
// E.g. a zero-sized type Signal<(i32, String)> with a provided emit(i32, String) method
547-
// This could even be made public (callable on the struct obj itself)
548-
AttrParseResult::Signal(attr.value.clone())
549-
}
549+
name if name == "signal" => AttrParseResult::Signal(attr.value.clone()),
550550

551551
// #[constant]
552552
name if name == "constant" => AttrParseResult::Const(attr.value.clone()),

itest/rust/src/builtin_tests/containers/callable_test.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
* License, v. 2.0. If a copy of the MPL was not distributed with this
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
7+
78
use godot::builtin::inner::InnerCallable;
89
use godot::builtin::{varray, Callable, GString, StringName, Variant};
910
use godot::classes::{Node2D, Object};
1011
use godot::meta::ToGodot;
1112
use godot::obj::{NewAlloc, NewGd};
1213
use godot::register::{godot_api, GodotClass};
13-
use std::fmt::{Display, Formatter};
1414
use std::hash::Hasher;
1515
use std::sync::atomic::{AtomicU32, Ordering};
1616

@@ -364,7 +364,7 @@ pub mod custom_callable {
364364
}
365365

366366
impl Hash for Adder {
367-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
367+
fn hash<H: Hasher>(&self, state: &mut H) {
368368
let mut guard = self.tracker.lock().unwrap();
369369
guard.hash_counter += 1;
370370

@@ -378,7 +378,7 @@ pub mod custom_callable {
378378
}
379379
}
380380

381-
impl godot::builtin::RustCallable for Adder {
381+
impl RustCallable for Adder {
382382
fn invoke(&mut self, args: &[&Variant]) -> Result<Variant, ()> {
383383
for arg in args {
384384
self.sum += arg.to::<i32>();
@@ -410,6 +410,7 @@ pub mod custom_callable {
410410
tracker.lock().unwrap().hash_counter
411411
}
412412

413+
// Also used in signal_test.
413414
pub struct PanicCallable(pub Arc<AtomicU32>);
414415

415416
impl PartialEq for PanicCallable {
@@ -424,8 +425,8 @@ pub mod custom_callable {
424425
}
425426
}
426427

427-
impl Display for PanicCallable {
428-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
428+
impl fmt::Display for PanicCallable {
429+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429430
write!(f, "test")
430431
}
431432
}

0 commit comments

Comments
 (0)