Skip to content

Commit d725123

Browse files
committed
For classes with #[base] field, add to_gd() utility method
1 parent bf402a3 commit d725123

File tree

5 files changed

+49
-16
lines changed

5 files changed

+49
-16
lines changed

godot-core/src/obj/traits.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ pub trait IndexEnum: EngineEnum {
206206
}
207207
}
208208

209+
/// Trait that's implemented for user-defined classes that provide a `#[base]` field.
210+
///
211+
/// Gives direct access to the containing `Gd<Self>` from `Self`.
212+
// Possible alternative for builder APIs, although even less ergonomic: Base<T> could be Base<T, Self> and return Gd<Self>.
213+
pub trait WithBaseField: GodotClass {
214+
/// Returns the `Gd` pointer containing this object.
215+
///
216+
/// This is intended to be stored or passed to engine methods. You cannot call `bind()` or `bind_mut()` on it, while the method
217+
/// calling `to_gd()` is still running; that would lead to a double borrow panic.
218+
fn to_gd(&self) -> Gd<Self>;
219+
}
220+
209221
// ----------------------------------------------------------------------------------------------------------------------------------------------
210222

211223
/// Capability traits, providing dedicated functionalities for Godot classes
@@ -257,17 +269,6 @@ pub mod cap {
257269
}
258270
}
259271

260-
/// Trait that's implemented for user-defined classes that provide a `#[base]` field.
261-
///
262-
/// Gives direct access to the base pointer without going through upcast FFI.
263-
pub trait WithBaseField: GodotClass {
264-
#[doc(hidden)]
265-
fn __godot_base(&self) -> &Gd<Self::Base>;
266-
267-
#[doc(hidden)]
268-
fn __godot_base_mut(&mut self) -> &mut Gd<Self::Base>;
269-
}
270-
271272
// TODO Evaluate whether we want this public or not
272273
#[doc(hidden)]
273274
pub trait GodotToString: GodotClass {

godot-macros/src/class/derive_godot_class.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ pub fn derive_godot_class(decl: Declaration) -> ParseResult<TokenStream> {
5050
quote! {}
5151
};
5252

53+
let godot_withbase_impl = if let Some(Field { name, .. }) = &fields.base_field {
54+
quote! {
55+
impl ::godot::obj::WithBaseField for #class_name {
56+
fn to_gd(&self) -> Gd<Self> {
57+
::godot::obj::Gd::clone(&*self.#name).cast()
58+
}
59+
}
60+
}
61+
} else {
62+
quote! {}
63+
};
64+
5365
let (godot_init_impl, create_fn, recreate_fn);
5466
if struct_cfg.has_generated_init {
5567
godot_init_impl = make_godot_init_impl(class_name, fields);
@@ -78,11 +90,10 @@ pub fn derive_godot_class(decl: Declaration) -> ParseResult<TokenStream> {
7890
::godot::builtin::meta::ClassName::from_ascii_cstr(#class_name_cstr)
7991
}
8092
}
81-
impl ::godot::obj::UserClass for #class_name {
82-
83-
}
93+
impl ::godot::obj::UserClass for #class_name {}
8494

8595
#godot_init_impl
96+
#godot_withbase_impl
8697
#godot_exports_impl
8798
#config_impl
8899

godot-macros/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ use crate::util::ident;
100100
/// #[class(base = Node2D)]
101101
/// struct MyStruct {
102102
/// #[base]
103-
/// base: Gd<Node2D>,
103+
/// base: Base<Node2D>,
104104
/// }
105105
/// ```
106106
///

godot/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,5 +235,6 @@ pub mod prelude {
235235
// Make trait methods available
236236
pub use super::engine::NodeExt as _;
237237
pub use super::obj::EngineEnum as _;
238-
pub use super::obj::UserClass as _; // new_gd(), self_gd()
238+
pub use super::obj::UserClass as _; // new_gd(), alloc_gd()
239+
pub use super::obj::WithBaseField as _; // to_gd()
239240
}

itest/rust/src/object_tests/base_test.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,19 @@ fn base_with_init() {
9393
obj.free();
9494
}
9595

96+
#[itest]
97+
fn base_gd_self() {
98+
let obj = Based::alloc_gd();
99+
let obj2 = obj.bind().access_gd_self();
100+
101+
assert_eq!(obj, obj2);
102+
assert_eq!(obj.instance_id(), obj2.instance_id());
103+
104+
obj.free();
105+
}
106+
107+
// ----------------------------------------------------------------------------------------------------------------------------------------------
108+
96109
#[derive(GodotClass)]
97110
#[class(init, base=Node2D)]
98111
struct Based {
@@ -102,6 +115,13 @@ struct Based {
102115
i: i32,
103116
}
104117

118+
impl Based {
119+
fn access_gd_self(&self) -> Gd<Self> {
120+
use godot::obj::WithBaseField as _;
121+
self.to_gd()
122+
}
123+
}
124+
105125
#[derive(GodotClass)]
106126
#[class(init, base=Node2D)]
107127
struct Baseless {

0 commit comments

Comments
 (0)