Skip to content

Commit 56dd4a5

Browse files
authored
Merge pull request #1346 from godot-rust/qol/deprecated-from-local-fn
`Callable`: rename `from_local_fn` -> `from_fn`, keep deprecated `from_local_fn` with old signature
2 parents cad71b9 + a6dd69e commit 56dd4a5

File tree

8 files changed

+44
-25
lines changed

8 files changed

+44
-25
lines changed

godot-core/src/builtin/callable.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl Callable {
116116
let callable = Self::from_sync_fn(&callable_name, function);
117117

118118
#[cfg(not(feature = "experimental-threads"))]
119-
let callable = Self::from_local_fn(&callable_name, function);
119+
let callable = Self::from_fn(&callable_name, function);
120120

121121
callable
122122
}
@@ -154,7 +154,9 @@ 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-
pub fn from_local_fn<R, F, S>(name: S, rust_function: F) -> Self
157+
///
158+
/// You can also couple the callable to the lifetime of an object, see [`from_linked_fn()`][Self::from_linked_fn].
159+
pub fn from_fn<R, F, S>(name: S, rust_function: F) -> Self
158160
where
159161
R: ToGodot,
160162
F: 'static + FnMut(&[&Variant]) -> R,
@@ -177,7 +179,7 @@ impl Callable {
177179
/// Such a callable will be automatically invalidated by Godot when a linked object is freed.
178180
/// Prefer using [`Gd::linked_callable()`] instead.
179181
///
180-
/// If you need a callable which can live indefinitely use [`Callable::from_local_fn()`].
182+
/// If you need a callable which can live indefinitely, use [`Callable::from_fn()`].
181183
pub fn from_linked_fn<R, F, T, S>(name: S, linked_object: &Gd<T>, rust_function: F) -> Self
182184
where
183185
R: ToGodot,
@@ -195,12 +197,29 @@ impl Callable {
195197
})
196198
}
197199

200+
/// This constructor is being phased out in favor of [`from_fn()`][Self::from_fn], but kept through v0.4 for smoother migration.
201+
///
202+
/// `from_fn()` accepts any `R: ToGodot` return type directly instead of requiring `Result<Variant, ()>`.
203+
#[deprecated = "Migrate to `from_fn()`, which returns `R: ToGodot` directly."]
204+
pub fn from_local_fn<F, S>(name: S, mut rust_function: F) -> Self
205+
where
206+
F: 'static + FnMut(&[&Variant]) -> Result<Variant, ()>,
207+
S: meta::AsArg<GString>,
208+
{
209+
meta::arg_into_owned!(name);
210+
211+
Self::from_fn(&name, move |args| {
212+
// Ignore errors.
213+
rust_function(args).unwrap_or_else(|()| Variant::nil())
214+
})
215+
}
216+
198217
/// Create callable from **single-threaded** Rust function or closure that can only be called once.
199218
///
200219
/// `name` is used for the string representation of the closure, which helps debugging.
201220
///
202221
/// After the first invocation, subsequent calls will panic with a message indicating the callable has already been consumed. This is
203-
/// useful for deferred operations that should only execute once. For repeated execution, use [`from_local_fn()][Self::from_local_fn].
222+
/// useful for deferred operations that should only execute once. For repeated execution, use [`from_fn()][Self::from_fn].
204223
pub(crate) fn from_once_fn<R, F, S>(name: S, rust_function: F) -> Self
205224
where
206225
R: ToGodot,
@@ -210,7 +229,7 @@ impl Callable {
210229
meta::arg_into_owned!(name);
211230

212231
let mut rust_fn_once = Some(rust_function);
213-
Self::from_local_fn(&name, move |args| {
232+
Self::from_fn(&name, move |args| {
214233
let rust_fn_once = rust_fn_once
215234
.take()
216235
.expect("callable created with from_once_fn() has already been consumed");
@@ -252,9 +271,9 @@ impl Callable {
252271
/// `name` is used for the string representation of the closure, which helps debugging.
253272
///
254273
/// This constructor requires `Send` + `Sync` bound and allows the callable to be invoked from any thread. If you guarantee that you invoke
255-
/// it from the same thread as creating it, use [`from_local_fn`][Self::from_local_fn] instead.
274+
/// it from the same thread as creating it, use [`from_fn`][Self::from_fn] instead.
256275
///
257-
/// Callables created through multiple `from_local_fn` or `from_sync_fn()` calls are never equal, even if they refer to the same function.
276+
/// Callables created through multiple `from_fn` or `from_sync_fn()` calls are never equal, even if they refer to the same function.
258277
/// If you want to use equality, either clone an existing `Callable` instance, or define your own `PartialEq` impl with
259278
/// [`Callable::from_custom`].
260279
///
@@ -680,7 +699,7 @@ mod custom_callable {
680699
// NOTE: this panic is currently not propagated to the caller, but results in an error message and Nil return.
681700
// See comments in itest callable_call() for details.
682701
panic!(
683-
"Callable '{}' created with from_local_fn() must be called from the same thread it was created in.\n\
702+
"Callable '{}' created with from_fn() must be called from the same thread it was created in.\n\
684703
If you need to call it from any thread, use from_sync_fn() instead (requires `experimental-threads` feature).",
685704
w.name
686705
);

godot-core/src/obj/gd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ impl<T: GodotClass> Gd<T> {
583583
/// `name` is used for the string representation of the closure, which helps with debugging.
584584
///
585585
/// Such a callable will be automatically invalidated by Godot when a linked Object is freed.
586-
/// If you need a Callable which can live indefinitely use [`Callable::from_local_fn()`].
586+
/// If you need a Callable which can live indefinitely, use [`Callable::from_fn()`].
587587
pub fn linked_callable<R, F>(
588588
&self,
589589
method_name: impl AsArg<GString>,

godot-core/src/task/async_runtime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ impl Wake for GodotWaker {
506506
}
507507

508508
#[cfg(not(feature = "experimental-threads"))]
509-
let create_callable = Callable::from_local_fn;
509+
let create_callable = Callable::from_fn;
510510

511511
#[cfg(feature = "experimental-threads")]
512512
let create_callable = Callable::from_sync_fn;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ fn array_bsearch_custom() {
563563

564564
fn backwards_sort_callable() -> Callable {
565565
// No &[&Variant] explicit type in arguments.
566-
Callable::from_local_fn("sort backwards", |args| {
566+
Callable::from_fn("sort backwards", |args| {
567567
args[0].to::<i32>() > args[1].to::<i32>()
568568
})
569569
}

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,8 @@ pub mod custom_callable {
382382
use crate::framework::{assert_eq_self, quick_thread, suppress_panic_log, ThreadCrosser};
383383

384384
#[itest]
385-
fn callable_from_local_fn() {
386-
let callable = Callable::from_local_fn("sum", sum);
385+
fn callable_from_fn() {
386+
let callable = Callable::from_fn("sum", sum);
387387

388388
assert!(callable.is_valid());
389389
assert!(!callable.is_null());
@@ -398,14 +398,14 @@ pub mod custom_callable {
398398
assert_eq!(sum2, 0.to_variant());
399399
}
400400

401-
// Without this feature, any access to the global binding from another thread fails; so the from_local_fn() cannot be tested in isolation.
401+
// Without this feature, any access to the global binding from another thread fails; so the from_fn() cannot be tested in isolation.
402402
#[itest]
403-
fn callable_from_local_fn_crossthread() {
403+
fn callable_from_fn_crossthread() {
404404
// This static is a workaround for not being able to propagate failed `Callable` invocations as panics.
405405
// See note in itest callable_call() for further info.
406406
static GLOBAL: sys::Global<i32> = sys::Global::default();
407407

408-
let callable = Callable::from_local_fn("change_global", |_args| {
408+
let callable = Callable::from_fn("change_global", |_args| {
409409
*GLOBAL.lock() = 777;
410410
});
411411

@@ -423,7 +423,7 @@ pub mod custom_callable {
423423
if !cfg!(feature = "experimental-threads") && cfg!(debug_assertions) {
424424
// Single-threaded and Debug.
425425
crate::framework::expect_panic(
426-
"Callable created with from_local_fn() must panic when invoked on other thread",
426+
"Callable created with from_fn() must panic when invoked on other thread",
427427
|| {
428428
quick_thread(|| {
429429
let callable = unsafe { crosser.extract() };
@@ -442,7 +442,7 @@ pub mod custom_callable {
442442
assert_eq!(
443443
*GLOBAL.lock(),
444444
0,
445-
"Callable created with from_local_fn() must not run when invoked on other thread"
445+
"Callable created with from_fn() must not run when invoked on other thread"
446446
);
447447
}
448448

@@ -469,16 +469,16 @@ pub mod custom_callable {
469469

470470
#[itest]
471471
fn callable_from_fn_nil() {
472-
let callable_with_err = Callable::from_local_fn("returns_nil", |_args: &[&Variant]| {});
472+
let callable_with_err = Callable::from_fn("returns_nil", |_args: &[&Variant]| {});
473473

474474
assert_eq!(callable_with_err.callv(&varray![]), Variant::nil());
475475
}
476476

477477
#[itest]
478478
fn callable_from_fn_eq() {
479-
let a = Callable::from_local_fn("sum", sum);
479+
let a = Callable::from_fn("sum", sum);
480480
let b = a.clone();
481-
let c = Callable::from_local_fn("sum", sum);
481+
let c = Callable::from_fn("sum", sum);
482482

483483
assert_eq!(a, b, "same function, same instance -> equal");
484484
assert_ne!(a, c, "same function, different instance -> not equal");
@@ -585,7 +585,7 @@ pub mod custom_callable {
585585
fn callable_callv_panic_from_fn() {
586586
let received = Arc::new(AtomicU32::new(0));
587587
let received_callable = received.clone();
588-
let callable = Callable::from_local_fn("test", move |_args| {
588+
let callable = Callable::from_fn("test", move |_args| {
589589
suppress_panic_log(|| {
590590
panic!("TEST: {}", received_callable.fetch_add(1, Ordering::SeqCst))
591591
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ mod custom_callable {
821821
fn connect_signal_panic_from_fn(received: Arc<AtomicU32>) -> Callable {
822822
// Explicit `Variant` return type to avoid following warning becoming a hard error in edition 2024.
823823
// warning: this function depends on never type fallback being `()`
824-
Callable::from_local_fn("test", move |_args| -> Variant {
824+
Callable::from_fn("test", move |_args| -> Variant {
825825
panic!("TEST: {}", received.fetch_add(1, Ordering::SeqCst))
826826
})
827827
}

itest/rust/src/engine_tests/async_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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", |_| {});
214+
let unrelated_callable = Callable::from_fn("unrelated", |_| {});
215215

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

itest/rust/src/framework/runner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ fn check_async_test_task(
473473
let mut callback = Some(on_test_finished);
474474
let mut probably_task_handle = Some(task_handle);
475475

476-
let deferred = Callable::from_local_fn("run_async_rust_test", move |_| {
476+
let deferred = Callable::from_fn("run_async_rust_test", move |_| {
477477
check_async_test_task(
478478
probably_task_handle
479479
.take()

0 commit comments

Comments
 (0)