@@ -71,14 +71,20 @@ fn make_native_structure(
71
71
) -> builtins:: GeneratedBuiltin {
72
72
let class_name = & class_name. rust_ty ;
73
73
74
+ // TODO for native structures holding object pointers, we should encapsulate the raw object, as follows:
75
+ // - Make raw object pointer field private (and maybe also ID field, to keep in sync).
76
+ // - Add constructor that takes Gd<Object> instead of ID/raw-ptr fields.
77
+ // - Add getter and setter methods with Gd<Object> (already present).
78
+ // - Add Drop impl, which decrements refcount if the constructor was used, and does nothing if FromGodot pointer conversion was used.
79
+
74
80
let imports = util:: make_imports ( ) ;
75
- let ( fields, methods) = make_native_structure_fields_and_methods ( & structure. format , ctx) ;
81
+ let ( fields, methods) = make_native_structure_fields_and_methods ( structure, ctx) ;
76
82
let doc = format ! ( "[`ToGodot`] and [`FromGodot`] are implemented for `*mut {class_name}` and `*const {class_name}`." ) ;
77
83
78
84
// mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub
79
85
let tokens = quote ! {
80
86
#imports
81
- use std:: ffi:: c_void; // for opaque object pointers
87
+ use std:: ffi:: c_void; // for opaque object pointer fields
82
88
use crate :: meta:: { GodotConvert , FromGodot , ToGodot } ;
83
89
84
90
/// Native structure; can be passed via pointer in APIs that are not exposed to GDScript.
@@ -132,10 +138,10 @@ fn make_native_structure(
132
138
}
133
139
134
140
fn make_native_structure_fields_and_methods (
135
- format_str : & str ,
141
+ structure : & NativeStructure ,
136
142
ctx : & mut Context ,
137
143
) -> ( TokenStream , TokenStream ) {
138
- let fields = parse_native_structures_format ( format_str )
144
+ let fields = parse_native_structures_format ( & structure . format )
139
145
. expect ( "Could not parse native_structures format field" ) ;
140
146
141
147
let mut field_definitions = vec ! [ ] ;
@@ -151,6 +157,7 @@ fn make_native_structure_fields_and_methods(
151
157
152
158
let fields = quote ! { #( #field_definitions ) * } ;
153
159
let methods = quote ! { #( #accessors ) * } ;
160
+
154
161
( fields, methods)
155
162
}
156
163
@@ -176,12 +183,15 @@ fn make_native_structure_field_and_accessor(
176
183
field_name = format_ident ! ( "raw_{}_ptr" , snake_field_name) ;
177
184
178
185
// Generate method that converts from instance ID.
179
- let getter_name = & snake_field_name;
186
+ let getter_name = format_ident ! ( "get_{}" , snake_field_name) ;
180
187
let setter_name = format_ident ! ( "set_{}" , snake_field_name) ;
181
188
let id_field_name = format_ident ! ( "{}_id" , snake_field_name) ;
182
189
190
+ // Current native structures treat all object pointers as Object (even if concrete ones like `collider` might be Node).
191
+ // Having node also avoids the lifetime issue with reference-counted objects (unclear if gdext should increment refcount or not).
192
+ // If other fields use different classes in the future, we'll need to update this.
183
193
accessor = Some ( quote ! {
184
- /// Returns the object as a `Gd<T >`, or `None` if it no longer exists.
194
+ /// Returns the object as a `Gd<Node >`, or `None` if it no longer exists.
185
195
pub fn #getter_name( & self ) -> Option <Gd <Object >> {
186
196
crate :: obj:: InstanceId :: try_from_u64( self . #id_field_name. id)
187
197
. and_then( |id| Gd :: try_from_instance_id( id) . ok( ) )
@@ -191,22 +201,16 @@ fn make_native_structure_field_and_accessor(
191
201
// unsafe { Gd::from_obj_sys(ptr) }
192
202
}
193
203
194
- /// Sets the object from a `Gd<T>` pointer.
195
- ///
196
- /// `increment_refcount` is only relevant for ref-counted objects (inheriting `RefCounted`). It is ignored otherwise.
197
- /// - Set it to true if you transfer `self` to Godot, e.g. via output parameter in a virtual function call.
198
- /// In this case, you can drop your own references and the object will remain alive.
199
- /// However, if you drop the native structure `self` without handing it over to Godot, you'll have a memory leak.
200
- /// - Set it to false if you just manage the native structure yourself.
201
- pub fn #setter_name( & mut self , mut obj: Gd <Object >, increment_refcount: bool ) {
204
+ /// Sets the object from a `Gd` pointer holding `Node` or a derived class.
205
+ pub fn #setter_name<T >( & mut self , #snake_field_name: Gd <T >)
206
+ where T : crate :: obj:: Inherits <Object > {
202
207
use crate :: meta:: GodotType as _;
203
208
204
- assert!( obj. is_instance_valid( ) , "provided object is dead" ) ;
209
+ let obj = #snake_field_name. upcast( ) ;
210
+
211
+ assert!( obj. is_instance_valid( ) , "provided node is dead" ) ;
205
212
206
213
let id = obj. instance_id( ) . to_u64( ) ;
207
- if increment_refcount {
208
- obj = obj. with_inc_refcount( ) ;
209
- }
210
214
211
215
self . #id_field_name = ObjectId { id } ;
212
216
self . #field_name = obj. obj_sys( ) as * mut std:: ffi:: c_void;
0 commit comments