Skip to content

Commit 728fc6f

Browse files
committed
Callable: allow R: ToGodot return types
No longer requires pointless Variant::nil() for unit return types.
1 parent f25b07b commit 728fc6f

File tree

8 files changed

+22
-25
lines changed

8 files changed

+22
-25
lines changed

godot-core/src/builtin/callable.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ impl Callable {
154154
///
155155
/// This constructor only allows the callable to be invoked from the same thread as creating it. If you need to invoke it from any thread,
156156
/// use [`from_sync_fn`][Self::from_sync_fn] instead (requires crate feature `experimental-threads`; only enable if really needed).
157-
#[cfg(since_api = "4.2")]
158157
pub fn from_local_fn<R, F, S>(name: S, rust_function: F) -> Self
159158
where
160159
R: ToGodot,
@@ -201,9 +200,10 @@ impl Callable {
201200
///
202201
/// After the first invocation, subsequent calls will panic with a message indicating the callable has already been consumed. This is
203202
/// useful for deferred operations that should only execute once. For repeated execution, use [`from_local_fn()][Self::from_local_fn].
204-
pub(crate) fn from_once_fn<F, S>(name: S, rust_function: F) -> Self
203+
pub(crate) fn from_once_fn<R, F, S>(name: S, rust_function: F) -> Self
205204
where
206-
F: 'static + FnOnce(&[&Variant]) -> Variant,
205+
R: ToGodot,
206+
F: 'static + FnOnce(&[&Variant]) -> R,
207207
S: meta::AsArg<GString>,
208208
{
209209
meta::arg_into_owned!(name);
@@ -213,6 +213,7 @@ impl Callable {
213213
let rust_fn_once = rust_fn_once
214214
.take()
215215
.expect("callable created with from_once_fn() has already been consumed");
216+
216217
rust_fn_once(args)
217218
})
218219
}
@@ -265,14 +266,15 @@ impl Callable {
265266
/// });
266267
/// ```
267268
#[cfg(feature = "experimental-threads")]
268-
pub fn from_sync_fn<F, S>(name: S, rust_function: F) -> Self
269+
pub fn from_sync_fn<R, F, S>(name: S, rust_function: F) -> Self
269270
where
270-
F: 'static + Send + Sync + FnMut(&[&Variant]) -> Variant,
271+
R: ToGodot,
272+
F: 'static + Send + Sync + FnMut(&[&Variant]) -> R,
271273
S: meta::AsArg<GString>,
272274
{
273275
meta::arg_into_owned!(name);
274276

275-
Self::from_fn_wrapper::<F, Variant>(FnWrapper {
277+
Self::from_fn_wrapper::<F, R>(FnWrapper {
276278
rust_function,
277279
name,
278280
thread_id: None,

godot-core/src/obj/base.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
1414
use std::mem::ManuallyDrop;
1515
use std::rc::Rc;
1616

17-
use crate::builtin::{Callable, Variant};
17+
use crate::builtin::Callable;
1818
use crate::obj::{bounds, Gd, GodotClass, InstanceId, PassiveGd};
1919
use crate::{classes, sys};
2020

@@ -226,7 +226,6 @@ impl<T: GodotClass> Base<T> {
226226
let name = format!("Base<{}> deferred unref", T::class_id());
227227
let callable = Callable::from_once_fn(&name, move |_args| {
228228
Self::drop_strong_ref(instance_id);
229-
Variant::nil()
230229
});
231230

232231
// Use Callable::call_deferred() instead of Gd::apply_deferred(). The latter implicitly borrows &mut self,

godot-core/src/obj/gd.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,6 @@ impl<T: GodotClass> Gd<T> {
711711

712712
let callable = Callable::from_once_fn("run_deferred", move |_| {
713713
gd_function(obj);
714-
Variant::nil()
715714
});
716715
callable.call_deferred(&[]);
717716
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -562,9 +562,9 @@ fn array_bsearch_custom() {
562562
}
563563

564564
fn backwards_sort_callable() -> Callable {
565-
Callable::from_local_fn("sort backwards", |args: &[&Variant]| {
566-
let res = args[0].to::<i32>() > args[1].to::<i32>();
567-
res.to_variant()
565+
// No &[&Variant] explicit type in arguments.
566+
Callable::from_local_fn("sort backwards", |args| {
567+
args[0].to::<i32>() > args[1].to::<i32>()
568568
})
569569
}
570570

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,6 @@ pub mod custom_callable {
407407

408408
let callable = Callable::from_local_fn("change_global", |_args| {
409409
*GLOBAL.lock() = 777;
410-
Variant::nil()
411410
});
412411

413412
// Note that Callable itself isn't Sync/Send, so we have to transfer it unsafely.
@@ -469,11 +468,9 @@ pub mod custom_callable {
469468
}
470469

471470
#[itest]
472-
fn callable_custom_with_err() {
473-
let callable_with_err =
474-
Callable::from_local_fn("on_error_doesnt_crash", |_args: &[&Variant]| Variant::nil());
471+
fn callable_from_fn_nil() {
472+
let callable_with_err = Callable::from_local_fn("returns_nil", |_args: &[&Variant]| {});
475473

476-
// Causes error in Godot, but should not crash.
477474
assert_eq!(callable_with_err.callv(&varray![]), Variant::nil());
478475
}
479476

@@ -487,9 +484,9 @@ pub mod custom_callable {
487484
assert_ne!(a, c, "same function, different instance -> not equal");
488485
}
489486

490-
fn sum(args: &[&Variant]) -> Variant {
491-
let sum: i32 = args.iter().map(|arg| arg.to::<i32>()).sum();
492-
sum.to_variant()
487+
// Now non-Variant return type.
488+
fn sum(args: &[&Variant]) -> i32 {
489+
args.iter().map(|arg| arg.to::<i32>()).sum()
493490
}
494491

495492
#[itest]
@@ -588,11 +585,10 @@ pub mod custom_callable {
588585
fn callable_callv_panic_from_fn() {
589586
let received = Arc::new(AtomicU32::new(0));
590587
let received_callable = received.clone();
591-
let callable = Callable::from_local_fn("test", move |_args| -> Variant {
588+
let callable = Callable::from_local_fn("test", move |_args| {
592589
suppress_panic_log(|| {
593590
panic!("TEST: {}", received_callable.fetch_add(1, Ordering::SeqCst))
594591
});
595-
Variant::nil()
596592
});
597593

598594
assert_eq!(Variant::nil(), callable.callv(&varray![]));

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,8 @@ mod custom_callable {
819819
}
820820

821821
fn connect_signal_panic_from_fn(received: Arc<AtomicU32>) -> Callable {
822+
// Explicit `Variant` return type to avoid following warning becoming a hard error in edition 2024.
823+
// warning: this function depends on never type fallback being `()`
822824
Callable::from_local_fn("test", move |_args| -> Variant {
823825
panic!("TEST: {}", received.fetch_add(1, Ordering::SeqCst))
824826
})

itest/rust/src/engine_tests/async_test.rs

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

88
use std::ops::Deref;
99

10-
use godot::builtin::{array, vslice, Array, Callable, Signal, Variant};
10+
use godot::builtin::{array, vslice, Array, Callable, Signal};
1111
use godot::classes::{Object, RefCounted};
1212
use godot::obj::{Base, Gd, NewAlloc, NewGd};
1313
use godot::prelude::{godot_api, GodotClass};
@@ -211,7 +211,7 @@ fn resolver_callabable_equality() {
211211

212212
let callable = Callable::from_custom(resolver.clone());
213213
let cloned_callable = Callable::from_custom(resolver.clone());
214-
let unrelated_callable = Callable::from_local_fn("unrelated", |_| Variant::nil());
214+
let unrelated_callable = Callable::from_local_fn("unrelated", |_| {});
215215

216216
assert_eq!(callable, cloned_callable);
217217
assert_ne!(callable, unrelated_callable);

itest/rust/src/framework/runner.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,6 @@ fn check_async_test_task(
483483
.expect("Callable should not be called multiple times!"),
484484
&next_ctx,
485485
);
486-
Variant::nil()
487486
});
488487

489488
ctx.scene_tree

0 commit comments

Comments
 (0)