|
5 | 5 | * file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
6 | 6 | */
|
7 | 7 |
|
8 |
| -use std::ops::DerefMut; |
9 |
| - |
10 |
| -use godot_ffi::is_main_thread; |
11 |
| - |
12 |
| -use crate::builtin::{Callable, Variant}; |
13 |
| -use crate::meta::UniformObjectDeref; |
14 |
| -use crate::obj::bounds::Declarer; |
15 |
| -use crate::obj::GodotClass; |
16 |
| -use crate::registry::signal::ToSignalObj; |
| 8 | +use crate::obj::{Gd, GodotClass, WithBaseField}; |
17 | 9 |
|
18 | 10 | // TODO(v0.4): seal this and similar traits.
|
19 | 11 |
|
20 |
| -/// Enables `Gd::apply_deferred()` for type-safe deferred calls. |
| 12 | +/// Enables deferred execution for user classes containing a `Base<T>` field. |
| 13 | +/// |
| 14 | +/// This trait provides `run_deferred()` and `run_deferred_gd()` methods for user class instances. |
| 15 | +/// For `Gd<T>` instances, use the inherent methods [`Gd::run_deferred()`] and [`Gd::run_deferred_gd()`] instead. |
21 | 16 | ///
|
22 |
| -/// The trait is automatically available for all engine-defined Godot classes and user classes containing a `Base<T>` field. |
| 17 | +/// The trait is automatically available for user classes containing a `Base<T>` field. |
23 | 18 | ///
|
24 | 19 | /// # Usage
|
25 | 20 | ///
|
26 | 21 | /// ```no_run
|
27 | 22 | /// # use godot::prelude::*;
|
28 |
| -/// # use std::f32::consts::PI; |
29 |
| -/// fn some_fn(mut node: Gd<Node2D>) { |
30 |
| -/// node.apply_deferred(|n: &mut Node2D| n.rotate(PI)) |
| 23 | +/// # |
| 24 | +/// #[derive(GodotClass)] |
| 25 | +/// #[class(init, base=Node2D)] |
| 26 | +/// struct MyNode { |
| 27 | +/// base: Base<Node2D>, |
| 28 | +/// } |
| 29 | +/// |
| 30 | +/// #[godot_api] |
| 31 | +/// impl MyNode { |
| 32 | +/// fn some_method(&mut self) { |
| 33 | +/// self.run_deferred(|this: &mut MyNode| { |
| 34 | +/// // Direct access to Rust struct. |
| 35 | +/// }); |
| 36 | +/// |
| 37 | +/// self.run_deferred_gd(|gd: Gd<MyNode>| { |
| 38 | +/// // Access to Gd. Needs bind/bind_mut for struct access. |
| 39 | +/// }); |
| 40 | +/// } |
31 | 41 | /// }
|
32 | 42 | /// ```
|
33 |
| -pub trait WithDeferredCall<T: GodotClass> { |
| 43 | +pub trait WithDeferredCall: GodotClass + WithBaseField { |
34 | 44 | /// Defers the given closure to run during [idle time](https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-method-call-deferred).
|
35 | 45 | ///
|
36 | 46 | /// This is a type-safe alternative to [`Object::call_deferred()`][crate::classes::Object::call_deferred].
|
37 | 47 | ///
|
| 48 | + /// The closure receives `&mut Self` allowing direct access to Rust fields and methods. |
| 49 | + /// |
38 | 50 | /// # Panics
|
39 | 51 | /// If called outside the main thread.
|
| 52 | + fn run_deferred<F>(&mut self, mut_self_method: F) |
| 53 | + where |
| 54 | + F: FnOnce(&mut Self) + 'static; |
| 55 | + |
| 56 | + /// Defers the given closure to run during [idle time](https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-method-call-deferred). |
| 57 | + /// |
| 58 | + /// This is a type-safe alternative to [`Object::call_deferred()`][crate::classes::Object::call_deferred]. |
| 59 | + /// |
| 60 | + /// The closure receives `Gd<Self>` which can be used to call engine methods. |
| 61 | + /// |
| 62 | + /// # Panics |
| 63 | + /// If called outside the main thread. |
| 64 | + fn run_deferred_gd<F>(&mut self, gd_function: F) |
| 65 | + where |
| 66 | + F: FnOnce(Gd<Self>) + 'static; |
| 67 | + |
| 68 | + #[deprecated( |
| 69 | + since = "0.4.0", |
| 70 | + note = "Split into `run_deferred()` + `run_deferred_gd`" |
| 71 | + )] |
40 | 72 | fn apply_deferred<F>(&mut self, rust_function: F)
|
41 | 73 | where
|
42 |
| - F: FnOnce(&mut T) + 'static; |
| 74 | + F: FnOnce(&mut Self) + 'static, |
| 75 | + { |
| 76 | + self.run_deferred(rust_function) |
| 77 | + } |
43 | 78 | }
|
44 | 79 |
|
45 |
| -impl<T, S, D> WithDeferredCall<T> for S |
| 80 | +impl<T> WithDeferredCall for T |
46 | 81 | where
|
47 |
| - T: UniformObjectDeref<D, Declarer = D>, |
48 |
| - S: ToSignalObj<T>, |
49 |
| - D: Declarer, |
| 82 | + T: WithBaseField, |
50 | 83 | {
|
51 |
| - fn apply_deferred<'a, F>(&mut self, rust_function: F) |
| 84 | + fn run_deferred<F>(&mut self, mut_self_method: F) |
52 | 85 | where
|
53 |
| - F: FnOnce(&mut T) + 'static, |
| 86 | + F: FnOnce(&mut Self) + 'static, |
54 | 87 | {
|
55 |
| - assert!( |
56 |
| - is_main_thread(), |
57 |
| - "`apply_deferred` must be called on the main thread" |
58 |
| - ); |
| 88 | + // We need to copy the Gd, because the lifetime of `&mut self` does not extend throughout the closure, which will only be called |
| 89 | + // deferred. It might even be freed in-between, causing panic on bind_mut(). |
| 90 | + self.to_gd().run_deferred(mut_self_method) |
| 91 | + } |
59 | 92 |
|
60 |
| - let mut this = self.to_signal_obj().clone(); |
61 |
| - let callable = Callable::from_once_fn("apply_deferred", move |_| { |
62 |
| - let mut this_mut = T::object_as_mut(&mut this); |
63 |
| - rust_function(this_mut.deref_mut()); |
64 |
| - Ok(Variant::nil()) |
65 |
| - }); |
66 |
| - callable.call_deferred(&[]); |
| 93 | + fn run_deferred_gd<F>(&mut self, gd_function: F) |
| 94 | + where |
| 95 | + F: FnOnce(Gd<Self>) + 'static, |
| 96 | + { |
| 97 | + self.to_gd().run_deferred_gd(gd_function) |
67 | 98 | }
|
68 | 99 | }
|
0 commit comments