Skip to content

Commit cb6577f

Browse files
committed
Module organization
1 parent 1193b6f commit cb6577f

File tree

10 files changed

+135
-85
lines changed

10 files changed

+135
-85
lines changed

godot-core/src/meta/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pub use class_name::ClassName;
6060
pub use godot_convert::{FromGodot, GodotConvert, ToGodot};
6161
pub use traits::{ArrayElement, GodotType, PackedArrayElement};
6262

63+
#[cfg(since_api = "4.2")]
64+
pub use crate::registry::signal::variadic::ParamTuple;
65+
6366
pub(crate) use array_type_info::ArrayTypeInfo;
6467
pub(crate) use traits::{
6568
element_godot_type_name, element_variant_type, GodotFfiVariant, GodotNullableFfi,

godot-core/src/registry/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ pub mod plugin;
1616
pub mod property;
1717

1818
#[cfg(since_api = "4.2")]
19-
pub mod functional;
19+
pub mod signal;
2020

2121
// Contents re-exported in `godot` crate; just keep empty.
2222
#[cfg(before_api = "4.2")]
23-
pub mod functional {}
23+
pub mod signal {}
2424

2525
// RpcConfig uses MultiplayerPeer::TransferMode and MultiplayerApi::RpcMode, which are only enabled in `codegen-full` feature.
2626
#[cfg(feature = "codegen-full")]

godot-core/src/registry/functional/connect_builder.rs renamed to godot-core/src/registry/signal/connect_builder.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use crate::builtin::{Callable, GString, Variant};
99
use crate::classes::object::ConnectFlags;
1010
use crate::obj::{bounds, Bounds, Gd, GodotClass, WithBaseField};
11-
use crate::registry::functional::{AsFunc, ParamTuple, TypedSignal};
11+
use crate::registry::signal::{SignalReceiver, TypedSignal};
1212
use crate::{meta, sys};
1313

1414
/// Type-state builder for customizing signal connections.
@@ -63,7 +63,7 @@ pub struct ConnectBuilder<'ts, 'c, CSig: GodotClass, CRcv, Ps, GodotFn> {
6363
godot_fn: GodotFn,
6464
}
6565

66-
impl<'ts, 'c, CSig: WithBaseField, Ps: ParamTuple> ConnectBuilder<'ts, 'c, CSig, (), Ps, ()> {
66+
impl<'ts, 'c, CSig: WithBaseField, Ps: meta::ParamTuple> ConnectBuilder<'ts, 'c, CSig, (), Ps, ()> {
6767
pub(super) fn new(parent_sig: &'ts mut TypedSignal<'c, CSig, Ps>) -> Self {
6868
ConnectBuilder {
6969
parent_sig,
@@ -86,7 +86,7 @@ impl<'ts, 'c, CSig: WithBaseField, Ps: ParamTuple> ConnectBuilder<'ts, 'c, CSig,
8686
/* GodotFn= */ impl FnMut(&[&Variant]) -> Result<Variant, ()> + 'static,
8787
>
8888
where
89-
F: AsFunc<(), Ps>,
89+
F: SignalReceiver<(), Ps>,
9090
{
9191
let godot_fn = move |variant_args: &[&Variant]| -> Result<Variant, ()> {
9292
let args = Ps::from_variant_array(variant_args);
@@ -132,7 +132,7 @@ impl<'ts, 'c, CSig: WithBaseField, Ps: ParamTuple> ConnectBuilder<'ts, 'c, CSig,
132132
}
133133
}
134134

135-
impl<'ts, 'c, CSig: WithBaseField, CRcv: GodotClass, Ps: ParamTuple>
135+
impl<'ts, 'c, CSig: WithBaseField, CRcv: GodotClass, Ps: meta::ParamTuple>
136136
ConnectBuilder<'ts, 'c, CSig, Gd<CRcv>, Ps, ()>
137137
{
138138
/// **Stage 2:** method taking `&mut self`.
@@ -150,7 +150,7 @@ impl<'ts, 'c, CSig: WithBaseField, CRcv: GodotClass, Ps: ParamTuple>
150150
>
151151
where
152152
CRcv: GodotClass + Bounds<Declarer = bounds::DeclUser>,
153-
for<'c_rcv> F: AsFunc<&'c_rcv mut CRcv, Ps>,
153+
for<'c_rcv> F: SignalReceiver<&'c_rcv mut CRcv, Ps>,
154154
{
155155
let mut gd: Gd<CRcv> = self.receiver_obj;
156156

@@ -189,7 +189,7 @@ impl<'ts, 'c, CSig: WithBaseField, CRcv: GodotClass, Ps: ParamTuple>
189189
>
190190
where
191191
CRcv: GodotClass + Bounds<Declarer = bounds::DeclUser>,
192-
for<'c_rcv> F: AsFunc<&'c_rcv CRcv, Ps>,
192+
for<'c_rcv> F: SignalReceiver<&'c_rcv CRcv, Ps>,
193193
{
194194
let gd: Gd<CRcv> = self.receiver_obj;
195195

@@ -218,7 +218,7 @@ impl<'ts, 'c, CSig: WithBaseField, CRcv: GodotClass, Ps: ParamTuple>
218218
impl<'ts, 'c, CSig, CRcv, Ps, GodotFn> ConnectBuilder<'ts, 'c, CSig, CRcv, Ps, GodotFn>
219219
where
220220
CSig: WithBaseField,
221-
Ps: ParamTuple,
221+
Ps: meta::ParamTuple,
222222
GodotFn: FnMut(&[&Variant]) -> Result<Variant, ()> + 'static,
223223
{
224224
/// **Stage 3:** allow signal to be called across threads.

godot-core/src/registry/functional/mod.rs renamed to godot-core/src/registry/signal/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77

88
mod connect_builder;
99
mod typed_signal;
10-
mod variadic;
10+
pub(crate) mod variadic;
1111

1212
pub use connect_builder::*;
1313
pub use typed_signal::*;
14-
pub use variadic::*;
14+
pub use variadic::SignalReceiver;
15+
// ParamTuple re-exported in crate::meta.

godot-core/src/registry/functional/typed_signal.rs renamed to godot-core/src/registry/signal/typed_signal.rs

+52-17
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,18 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8-
// Maybe move this to builtin::functional module?
9-
108
use crate::builtin::{Callable, GString, Variant};
119
use crate::classes::object::ConnectFlags;
1210
use crate::obj::{bounds, Bounds, Gd, GodotClass, WithBaseField};
13-
use crate::registry::functional::{AsFunc, ConnectBuilder, ParamTuple};
11+
use crate::registry::signal::{ConnectBuilder, SignalReceiver};
1412
use crate::{classes, meta};
1513
use std::borrow::Cow;
1614
use std::marker::PhantomData;
1715

16+
/// Links to a Godot object, either via reference (for `&mut self` uses) or via `Gd`.
1817
#[doc(hidden)]
1918
pub enum ObjectRef<'a, C: GodotClass> {
20-
/// Helpful for emit: reuse `&self` from within the `impl` block, goes through `base()` re-borrowing and thus allows re-entrant calls
19+
/// Helpful for emit: reuse `&mut self` from within the `impl` block, goes through `base_mut()` re-borrowing and thus allows re-entrant calls
2120
/// through Godot.
2221
Internal { obj_mut: &'a mut C },
2322

@@ -46,15 +45,38 @@ where
4645

4746
// ----------------------------------------------------------------------------------------------------------------------------------------------
4847

48+
/// Type-safe version of a Godot signal.
49+
///
50+
/// Short-lived type, only valid in the scope of its surrounding object type `C`, for lifetime `'c`. The generic argument `Ps` represents
51+
/// the parameters of the signal, thus ensuring the type safety.
52+
///
53+
/// The [`WithSignals::signals()`][crate::obj::WithSignals::signals] collection returns multiple signals with distinct, code-generated types,
54+
/// but they all implement `Deref` and `DerefMut` to `TypedSignal`. This allows you to either use the concrete APIs of the generated types,
55+
/// or the more generic ones of `TypedSignal`.
56+
///
57+
/// # Connecting a signal to a receiver
58+
/// Receiver functions are functions that are called when a signal is emitted. You can connect a signal in many different ways:
59+
/// - [`connect()`][Self::connect] for global functions, associated functions or closures.
60+
/// - [`connect_self()`][Self::connect_self] for methods with `&mut self` as the first parameter.
61+
/// - [`connect_obj()`][Self::connect_obj] for methods with any `Gd<T>` (not `self`) as the first parameter.
62+
/// - [`connect_builder()`][Self::connect_builder] for more complex setups.
63+
///
64+
/// # Emitting a signal
65+
/// Code-generated signal types provide a method `emit(...)`, which adopts the names and types of the `#[signal]` parameter list.
66+
/// In most cases, that's the method you are looking for.
67+
///
68+
/// For generic use, you can also use [`emit_tuple()`][Self::emit_tuple], which does not provide parameter names.
69+
///
70+
/// # More information
71+
/// See the [Signals](https://godot-rust.github.io/book/register/signals.html) chapter in the book for a detailed introduction and examples.
4972
pub struct TypedSignal<'c, C: GodotClass, Ps> {
50-
//signal: Signal,
5173
/// In Godot, valid signals (unlike funcs) are _always_ declared in a class and become part of each instance. So there's always an object.
5274
owner: ObjectRef<'c, C>,
5375
name: Cow<'static, str>,
5476
_signature: PhantomData<Ps>,
5577
}
5678

57-
impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
79+
impl<'c, C: WithBaseField, Ps: meta::ParamTuple> TypedSignal<'c, C, Ps> {
5880
#[doc(hidden)]
5981
pub fn new(owner: ObjectRef<'c, C>, name: &'static str) -> Self {
6082
Self {
@@ -68,11 +90,15 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
6890
self.owner.to_owned()
6991
}
7092

71-
pub fn emit(&mut self, params: Ps) {
93+
/// Emit the signal with the given parameters.
94+
///
95+
/// This is intended for generic use. Typically, you'll want to use the more specific `emit()` method of the code-generated signal
96+
/// type, which also has named parameters.
97+
pub fn emit_tuple(&mut self, args: Ps) {
7298
let name = self.name.as_ref();
7399

74100
self.owner.with_object_mut(|obj| {
75-
obj.emit_signal(name, &params.to_variant_array());
101+
obj.emit_signal(name, &args.to_variant_array());
76102
});
77103
}
78104

@@ -85,10 +111,11 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
85111
/// sig.connect(|arg| { /* closure */ });
86112
/// ```
87113
///
88-
/// To connect to a method of the own object `self`, use [`connect_self()`][Self::connect_self].
114+
/// To connect to a method of the own object `self`, use [`connect_self()`][Self::connect_self]. \
115+
/// If you need cross-thread signals or connect flags, use [`connect_builder()`][Self::connect_builder].
89116
pub fn connect<F>(&mut self, mut function: F)
90117
where
91-
F: AsFunc<(), Ps>,
118+
F: SignalReceiver<(), Ps>,
92119
{
93120
let callable_name = std::any::type_name_of_val(&function);
94121

@@ -103,9 +130,12 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
103130
}
104131

105132
/// Connect a method (member function) with `&mut self` as the first parameter.
133+
///
134+
/// To connect to methods on other objects, use [`connect_obj()`][Self::connect_obj]. \
135+
/// If you need a `&self` receiver, cross-thread signals or connect flags, use [`connect_builder()`][Self::connect_builder].
106136
pub fn connect_self<F>(&mut self, mut function: F)
107137
where
108-
for<'c_rcv> F: AsFunc<&'c_rcv mut C, Ps>,
138+
for<'c_rcv> F: SignalReceiver<&'c_rcv mut C, Ps>,
109139
{
110140
// When using sys::short_type_name() in the future, make sure global "func" and member "MyClass::func" are rendered as such.
111141
// PascalCase heuristic should then be good enough.
@@ -132,11 +162,12 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
132162

133163
/// Connect a method (member function) with any `Gd<T>` (not `self`) as the first parameter.
134164
///
135-
/// To connect to methods on the same object, use [`connect_self()`][Self::connect_self].
165+
/// To connect to methods on the same object that declares the `#[signal]`, use [`connect_self()`][Self::connect_self]. \
166+
/// If you need cross-thread signals or connect flags, use [`connect_builder()`][Self::connect_builder].
136167
pub fn connect_obj<F, OtherC>(&mut self, object: &Gd<OtherC>, mut function: F)
137168
where
138169
OtherC: GodotClass + Bounds<Declarer = bounds::DeclUser>,
139-
for<'c_rcv> F: AsFunc<&'c_rcv mut OtherC, Ps>,
170+
for<'c_rcv> F: SignalReceiver<&'c_rcv mut OtherC, Ps>,
140171
{
141172
let callable_name = std::any::type_name_of_val(&function);
142173

@@ -154,6 +185,14 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
154185
self.inner_connect_local(callable_name, godot_fn);
155186
}
156187

188+
/// Fully customizable connection setup.
189+
///
190+
/// The returned builder provides several methods to configure how to connect the signal. It needs to be finalized with a call to
191+
/// [`ConnectBuilder::done()`].
192+
pub fn connect_builder(&mut self) -> ConnectBuilder<'_, 'c, C, (), Ps, ()> {
193+
ConnectBuilder::new(self)
194+
}
195+
157196
fn inner_connect_local<F>(&mut self, callable_name: impl meta::AsArg<GString>, godot_fn: F)
158197
where
159198
F: FnMut(&[&Variant]) -> Result<Variant, ()> + 'static,
@@ -179,8 +218,4 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
179218
c.done();
180219
});
181220
}
182-
183-
pub fn connect_builder(&mut self) -> ConnectBuilder<'_, 'c, C, (), Ps, ()> {
184-
ConnectBuilder::new(self)
185-
}
186221
}

godot-core/src/registry/functional/variadic.rs renamed to godot-core/src/registry/signal/variadic.rs

+62-43
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,65 @@
1414
use crate::builtin::Variant;
1515
use crate::meta;
1616

17-
pub trait AsFunc<I, Ps>: 'static {
17+
/// Trait that is implemented for functions that can be connected to signals.
18+
///
19+
// Direct RustDoc link doesn't work, for whatever reason again...
20+
/// This is used in [`ConnectBuilder`](struct.ConnectBuilder.html). There are three variations of the `I` (instance) parameter:
21+
/// - `()` for global and associated ("static") functions.
22+
/// - `&C` for `&self` methods.
23+
/// - `&mut C` for `&mut self` methods.
24+
///
25+
/// See also [Signals](https://godot-rust.github.io/book/register/signals.html) in the book.
26+
pub trait SignalReceiver<I, Ps>: 'static {
27+
/// Invoke the receiver on the given instance (possibly `()`) with `params`.
1828
fn call(&mut self, maybe_instance: I, params: Ps);
1929
}
2030

31+
/// Represents a parameter list as Rust tuple.
32+
///
33+
/// Each tuple element is one parameter. This trait provides conversions to and from `Variant` arrays.
34+
// Re-exported under crate::meta. Might be worth splitting, but depends a bit on SignatureVarcall/Ptrcall refactoring.
35+
pub trait ParamTuple {
36+
fn to_variant_array(&self) -> Vec<Variant>;
37+
fn from_variant_array(array: &[&Variant]) -> Self;
38+
}
39+
40+
// ----------------------------------------------------------------------------------------------------------------------------------------------
41+
// Generated impls
42+
2143
macro_rules! impl_signal_recipient {
2244
($( $args:ident : $Ps:ident ),*) => {
45+
// --------------------------------------------------------------------------------------------------------------------------------------
46+
// ParamTuple
47+
48+
impl<$($Ps),*> ParamTuple for ($($Ps,)*)
49+
where
50+
$($Ps: meta::ToGodot + meta::FromGodot),*
51+
{
52+
fn to_variant_array(&self) -> Vec<Variant> {
53+
let ($($args,)*) = self;
54+
55+
vec![
56+
$( $args.to_variant(), )*
57+
]
58+
}
59+
60+
#[allow(unused_variables, unused_mut, clippy::unused_unit)]
61+
fn from_variant_array(array: &[&Variant]) -> Self {
62+
let mut iter = array.iter();
63+
( $(
64+
<$Ps>::from_variant(
65+
iter.next().unwrap_or_else(|| panic!("ParamTuple: {} access out-of-bounds (len {})", stringify!($args), array.len()))
66+
),
67+
)* )
68+
}
69+
}
70+
71+
// --------------------------------------------------------------------------------------------------------------------------------------
72+
// SignalReceiver
73+
2374
// Global and associated functions.
24-
impl<F, R, $($Ps,)*> AsFunc<(), ( $($Ps,)* )> for F
75+
impl<F, R, $($Ps,)*> SignalReceiver<(), ( $($Ps,)* )> for F
2576
where F: FnMut( $($Ps,)* ) -> R + 'static
2677
{
2778
fn call(&mut self, _no_instance: (), ($($args,)*): ( $($Ps,)* )) {
@@ -30,7 +81,7 @@ macro_rules! impl_signal_recipient {
3081
}
3182

3283
// Methods with mutable receiver - &mut self.
33-
impl<F, R, C, $($Ps,)*> AsFunc<&mut C, ( $($Ps,)* )> for F
84+
impl<F, R, C, $($Ps,)*> SignalReceiver<&mut C, ( $($Ps,)* )> for F
3485
where F: FnMut( &mut C, $($Ps,)* ) -> R + 'static
3586
{
3687
fn call(&mut self, instance: &mut C, ($($args,)*): ( $($Ps,)* )) {
@@ -39,7 +90,7 @@ macro_rules! impl_signal_recipient {
3990
}
4091

4192
// Methods with immutable receiver - &self.
42-
impl<F, R, C, $($Ps,)*> AsFunc<&C, ( $($Ps,)* )> for F
93+
impl<F, R, C, $($Ps,)*> SignalReceiver<&C, ( $($Ps,)* )> for F
4394
where F: FnMut( &C, $($Ps,)* ) -> R + 'static
4495
{
4596
fn call(&mut self, instance: &C, ($($args,)*): ( $($Ps,)* )) {
@@ -53,42 +104,10 @@ impl_signal_recipient!();
53104
impl_signal_recipient!(arg0: P0);
54105
impl_signal_recipient!(arg0: P0, arg1: P1);
55106
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2);
56-
57-
// ----------------------------------------------------------------------------------------------------------------------------------------------
58-
59-
pub trait ParamTuple {
60-
fn to_variant_array(&self) -> Vec<Variant>;
61-
fn from_variant_array(array: &[&Variant]) -> Self;
62-
}
63-
64-
macro_rules! impl_param_tuple {
65-
($($args:ident : $Ps:ident),*) => {
66-
impl<$($Ps),*> ParamTuple for ($($Ps,)*)
67-
where
68-
$($Ps: meta::ToGodot + meta::FromGodot),*
69-
{
70-
fn to_variant_array(&self) -> Vec<Variant> {
71-
let ($($args,)*) = self;
72-
73-
vec![
74-
$( $args.to_variant(), )*
75-
]
76-
}
77-
78-
#[allow(unused_variables, unused_mut, clippy::unused_unit)]
79-
fn from_variant_array(array: &[&Variant]) -> Self {
80-
let mut iter = array.iter();
81-
( $(
82-
<$Ps>::from_variant(
83-
iter.next().unwrap_or_else(|| panic!("ParamTuple: {} access out-of-bounds (len {})", stringify!($args), array.len()))
84-
),
85-
)* )
86-
}
87-
}
88-
};
89-
}
90-
91-
impl_param_tuple!();
92-
impl_param_tuple!(arg0: P0);
93-
impl_param_tuple!(arg0: P0, arg1: P1);
94-
impl_param_tuple!(arg0: P0, arg1: P1, arg2: P2);
107+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3);
108+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3, arg4: P4);
109+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3, arg4: P4, arg5: P5);
110+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3, arg4: P4, arg5: P5, arg6: P6);
111+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3, arg4: P4, arg5: P5, arg6: P6, arg7: P7);
112+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3, arg4: P4, arg5: P5, arg6: P6, arg7: P7, arg8: P8);
113+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2, arg3: P3, arg4: P4, arg5: P5, arg6: P6, arg7: P7, arg8: P8, arg9: P9);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ fn make_signal_individual_struct(details: &SignalDetails) -> TokenStream {
257257
#(#signal_cfg_attrs)*
258258
impl #individual_struct_name<'_> {
259259
pub fn emit(&mut self, #emit_params) {
260-
self.typed.emit((#( #param_names, )*));
260+
self.typed.emit_tuple((#( #param_names, )*));
261261
}
262262
}
263263

0 commit comments

Comments
 (0)