Skip to content

Commit 67c8ea7

Browse files
committed
feat(core): support easier, type-safe deferred calls
1 parent 81f9d7c commit 67c8ea7

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

godot-core/src/obj/gd.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,35 @@ impl<T: GodotClass> Gd<T> {
444444
})
445445
}
446446

447+
/// Runs the given Closure deferred.
448+
/// The closure receives a reference to this object back.
449+
/// This can be a type-safe alternative to [`Object::call_deferred`], but does not handle
450+
/// dynamic dispatch, unless explicitly used.
451+
/// If you need error propagation, use [`Self::try_apply_deferred`] instead.
452+
pub fn apply_deferred<F>(&mut self, mut rust_function: F)
453+
where
454+
F: FnMut(Gd<T>) + 'static,
455+
{
456+
self.try_apply_deferred(move |this| {
457+
rust_function(this);
458+
Ok(())
459+
})
460+
}
461+
462+
/// See [`Self::apply_deferred`], this does not handle
463+
pub fn try_apply_deferred<F>(&mut self, mut rust_function: F)
464+
where
465+
F: FnMut(Gd<T>) -> Result<(), ()> + 'static,
466+
{
467+
let this = self.clone();
468+
Callable::from_local_fn(
469+
// todo: naming ?
470+
"apply_deferred",
471+
move |_| rust_function(this.clone()).map(|_| Variant::nil()),
472+
)
473+
.call_deferred(&[]);
474+
}
475+
447476
/// Returns `Ok(cast_obj)` on success, `Err(self)` on error.
448477
// Visibility: used by DynGd.
449478
pub(crate) fn owned_cast<U>(self) -> Result<Gd<U>, Self>

itest/rust/src/object_tests/deferred_call_test.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,20 @@ impl INode for DeferredTestNode {
6262
fn calls_method_names_deferred(ctx: &crate::framework::TestContext) -> TaskHandle {
6363
let mut test_node = DeferredTestNode::new_alloc();
6464
ctx.scene_tree.clone().add_child(&test_node);
65-
65+
6666
test_node.call_deferred("accept", &[]);
6767

6868
let handle = test_node.bind().as_expectation_task();
6969
handle
7070
}
71+
72+
#[itest(async)]
73+
fn calls_closure_deferred(ctx: &crate::framework::TestContext) -> TaskHandle {
74+
let mut test_node = DeferredTestNode::new_alloc();
75+
ctx.scene_tree.clone().add_child(&test_node);
76+
77+
test_node.apply_deferred(|mut this| this.bind_mut().accept());
78+
79+
let handle = test_node.bind().as_expectation_task();
80+
handle
81+
}

0 commit comments

Comments
 (0)