Skip to content

Commit 73f520f

Browse files
committed
Own module for typed signals + variadic args
1 parent 340a165 commit 73f520f

File tree

7 files changed

+107
-152
lines changed

7 files changed

+107
-152
lines changed

godot-core/src/registry/as_func.rs

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (c) godot-rust; Bromeon and contributors.
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
mod typed_signal;
9+
mod variadic;
10+
11+
pub use typed_signal::*;
12+
pub use variadic::*;

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

Lines changed: 2 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -9,51 +9,11 @@
99

1010
use crate::builtin::{Callable, Variant};
1111
use crate::obj::{Gd, GodotClass, WithBaseField};
12-
use crate::registry::as_func::AsFunc;
13-
use crate::{classes, meta, sys};
12+
use crate::registry::functional::{AsFunc, ParamTuple};
13+
use crate::{classes, sys};
1414
use std::borrow::Cow;
1515
use std::fmt;
1616

17-
pub trait ParamTuple {
18-
fn to_variant_array(&self) -> Vec<Variant>;
19-
fn from_variant_array(array: &[&Variant]) -> Self;
20-
}
21-
22-
macro_rules! impl_param_tuple {
23-
// Recursive case for tuple with N elements
24-
($($args:ident : $Ps:ident),*) => {
25-
impl<$($Ps),*> ParamTuple for ($($Ps,)*)
26-
where
27-
$($Ps: meta::ToGodot + meta::FromGodot),*
28-
{
29-
fn to_variant_array(&self) -> Vec<Variant> {
30-
let ($($args,)*) = self;
31-
32-
vec![
33-
$( $args.to_variant(), )*
34-
]
35-
}
36-
37-
#[allow(unused_variables, unused_mut, clippy::unused_unit)]
38-
fn from_variant_array(array: &[&Variant]) -> Self {
39-
let mut iter = array.iter();
40-
( $(
41-
<$Ps>::from_variant(
42-
iter.next().unwrap_or_else(|| panic!("ParamTuple: {} access out-of-bounds (len {})", stringify!($args), array.len()))
43-
),
44-
)* )
45-
}
46-
}
47-
};
48-
}
49-
50-
impl_param_tuple!();
51-
impl_param_tuple!(arg0: P0);
52-
impl_param_tuple!(arg0: P0, arg1: P1);
53-
impl_param_tuple!(arg0: P0, arg1: P1, arg2: P2);
54-
55-
// ----------------------------------------------------------------------------------------------------------------------------------------------
56-
5717
#[doc(hidden)]
5818
pub enum ObjectRef<'a, C: GodotClass> {
5919
/// Helpful for emit: reuse `&self` from within the `impl` block, goes through `base()` re-borrowing and thus allows re-entrant calls
@@ -167,62 +127,6 @@ impl<'a, C: WithBaseField, Ps: ParamTuple> TypedSignal<'a, C, Ps> {
167127
}
168128
}
169129

170-
// ----------------------------------------------------------------------------------------------------------------------------------------------
171-
/* Previous impl based on assumption, Signal would be used. Could maybe be combined within an enum.
172-
173-
pub struct TypedSignal<Ps> {
174-
signal: Signal,
175-
_signature: std::marker::PhantomData<Ps>,
176-
}
177-
178-
impl<Ps: ParamTuple> TypedSignal<Ps> {
179-
pub(crate) fn from_untyped(signal: Signal) -> Self {
180-
Self {
181-
signal,
182-
_signature: std::marker::PhantomData,
183-
}
184-
}
185-
186-
pub fn emit(&self, params: Ps) {
187-
self.signal.emit(&params.to_variant_array());
188-
}
189-
190-
pub fn connect_untyped(&mut self, callable: &Callable, flags: i64) {
191-
self.signal.connect(callable, flags);
192-
}
193-
194-
pub fn to_untyped(&self) -> Signal {
195-
self.signal.clone()
196-
}
197-
}*/
198-
199-
// ----------------------------------------------------------------------------------------------------------------------------------------------
200-
201-
/*
202-
pub struct TypedFunc<C, R, Ps> {
203-
godot_name: &'static str,
204-
_return_type: std::marker::PhantomData<R>,
205-
_param_types: std::marker::PhantomData<(C, Ps)>,
206-
}
207-
208-
impl<C: GodotClass, R, Ps> TypedFunc<C, R, Ps> {
209-
#[doc(hidden)]
210-
pub fn from_godot_name(godot_name: &'static str) -> Self {
211-
Self {
212-
godot_name,
213-
_return_type: std::marker::PhantomData,
214-
_param_types: std::marker::PhantomData,
215-
}
216-
}
217-
218-
pub fn with_object<T: GodotClass>(obj: &Gd<T>) {}
219-
220-
pub fn godot_name(&self) -> &'static str {
221-
self.godot_name
222-
}
223-
}
224-
*/
225-
226130
// ----------------------------------------------------------------------------------------------------------------------------------------------
227131

228132
/// Type-safe `#[func]` reference that is readily callable.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) godot-rust; Bromeon and contributors.
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
//! Emulates variadic argument lists (via tuples), related to functions and signals.
9+
10+
// https://geo-ant.github.io/blog/2021/rust-traits-and-variadic-functions
11+
//
12+
// Could be generalized with R return type, and not special-casing `self`. But keep simple until actually needed.
13+
14+
use crate::builtin::Variant;
15+
use crate::meta;
16+
17+
pub trait AsFunc<I, Ps> {
18+
fn call(&mut self, maybe_instance: I, params: Ps);
19+
}
20+
21+
macro_rules! impl_signal_recipient {
22+
($( $args:ident : $Ps:ident ),*) => {
23+
// Global and associated functions.
24+
impl<F, R, $($Ps,)*> AsFunc<(), ( $($Ps,)* )> for F
25+
where F: FnMut( $($Ps,)* ) -> R
26+
{
27+
fn call(&mut self, _no_instance: (), ($($args,)*): ( $($Ps,)* )) {
28+
self($($args,)*);
29+
}
30+
}
31+
32+
// Methods.
33+
impl<F, R, C, $($Ps,)*> AsFunc<&mut C, ( $($Ps,)* )> for F
34+
where F: FnMut( &mut C, $($Ps,)* ) -> R
35+
{
36+
fn call(&mut self, instance: &mut C, ($($args,)*): ( $($Ps,)* )) {
37+
self(instance, $($args,)*);
38+
}
39+
}
40+
};
41+
}
42+
43+
impl_signal_recipient!();
44+
impl_signal_recipient!(arg0: P0);
45+
impl_signal_recipient!(arg0: P0, arg1: P1);
46+
impl_signal_recipient!(arg0: P0, arg1: P1, arg2: P2);
47+
48+
// ----------------------------------------------------------------------------------------------------------------------------------------------
49+
50+
pub trait ParamTuple {
51+
fn to_variant_array(&self) -> Vec<Variant>;
52+
fn from_variant_array(array: &[&Variant]) -> Self;
53+
}
54+
55+
macro_rules! impl_param_tuple {
56+
($($args:ident : $Ps:ident),*) => {
57+
impl<$($Ps),*> ParamTuple for ($($Ps,)*)
58+
where
59+
$($Ps: meta::ToGodot + meta::FromGodot),*
60+
{
61+
fn to_variant_array(&self) -> Vec<Variant> {
62+
let ($($args,)*) = self;
63+
64+
vec![
65+
$( $args.to_variant(), )*
66+
]
67+
}
68+
69+
#[allow(unused_variables, unused_mut, clippy::unused_unit)]
70+
fn from_variant_array(array: &[&Variant]) -> Self {
71+
let mut iter = array.iter();
72+
( $(
73+
<$Ps>::from_variant(
74+
iter.next().unwrap_or_else(|| panic!("ParamTuple: {} access out-of-bounds (len {})", stringify!($args), array.len()))
75+
),
76+
)* )
77+
}
78+
}
79+
};
80+
}
81+
82+
impl_param_tuple!();
83+
impl_param_tuple!(arg0: P0);
84+
impl_param_tuple!(arg0: P0, arg1: P1);
85+
impl_param_tuple!(arg0: P0, arg1: P1, arg2: P2);

godot-core/src/registry/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ pub mod plugin;
1616
pub mod property;
1717

1818
#[cfg(since_api = "4.2")]
19-
pub mod as_func;
20-
#[cfg(since_api = "4.2")]
21-
pub mod typed_signal;
19+
pub mod functional;
20+
21+
// Contents re-exported in `godot` crate; just keep empty.
22+
#[cfg(before_api = "4.2")]
23+
pub mod functional {}
2224

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

godot/src/lib.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,13 @@ pub mod init {
183183

184184
/// Register/export Rust symbols to Godot: classes, methods, enums...
185185
pub mod register {
186+
pub use godot_core::registry::functional::*;
186187
pub use godot_core::registry::property;
187188
pub use godot_macros::{godot_api, godot_dyn, Export, GodotClass, GodotConvert, Var};
188189

189190
#[cfg(feature = "__codegen-full")]
190191
pub use godot_core::registry::RpcConfig;
191192

192-
#[cfg(since_api = "4.2")]
193-
pub use godot_core::registry::as_func::*;
194-
#[cfg(since_api = "4.2")]
195-
pub use godot_core::registry::typed_signal::*;
196-
197193
/// Re-exports used by proc-macro API.
198194
#[doc(hidden)]
199195
pub mod private {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,14 @@ impl Emitter {
124124

125125
// "Internal" means connect/emit happens from within the class (via &mut self).
126126

127+
#[cfg(since_api = "4.2")]
127128
fn connect_signals_internal(&mut self) {
128129
let mut sig = self.signals().emitter_1();
129130
sig.connect_self(Self::self_receive);
130131
sig.connect(Self::self_receive_static);
131132
}
132133

134+
#[cfg(since_api = "4.2")]
133135
fn emit_signals_internal(&mut self) {
134136
self.signals().emitter_1().emit(1234);
135137
}

0 commit comments

Comments
 (0)