@@ -17,6 +17,7 @@ mod traits;
17
17
pub mod error;
18
18
pub use class_name:: ClassName ;
19
19
pub use godot_convert:: { FromGodot , GodotConvert , ToGodot } ;
20
+ use sys:: conv:: u32_to_usize;
20
21
pub use traits:: { ArrayElement , GodotType } ;
21
22
22
23
pub ( crate ) use crate :: impl_godot_as_self;
@@ -241,50 +242,117 @@ pub struct MethodInfo {
241
242
}
242
243
243
244
impl MethodInfo {
244
- /// Converts to the FFI type. Keep this object allocated while using that!
245
- ///
246
- /// The struct returned by this function contains pointers into the fields of `self`. `self` should therefore not be dropped while the
247
- /// `sys::GDExtensionMethodInfo` is still in use.
245
+ /// Consumes self and turns it into a `sys::GDExtensionMethodInfo`, should be used together with
246
+ /// [`free_owned_method_sys`](Self::free_owned_method_sys).
248
247
///
249
- /// This function also leaks memory that has to be cleaned up by the caller once it is no longer used. Specifically the `arguments` and
250
- /// `default_arguments` vectors have to be reconstructed from the pointer and length and then dropped/freed.
251
- ///
252
- /// Each vector can be reconstructed with `Vec::from_raw_parts` since the pointers were created with `Vec::into_boxed_slice`, which
253
- /// guarantees that the vector capacity and length are equal.
254
- pub fn method_sys ( & self ) -> sys:: GDExtensionMethodInfo {
248
+ /// This will leak memory unless used together with `free_owned_method_sys`.
249
+ pub fn into_owned_method_sys ( self ) -> sys:: GDExtensionMethodInfo {
255
250
use crate :: obj:: EngineBitfield as _;
256
251
257
- let argument_count = self . arguments . len ( ) as u32 ;
258
- let argument_vec = self
259
- . arguments
260
- . iter ( )
261
- . map ( |arg| arg. property_sys ( ) )
262
- . collect :: < Vec < _ > > ( )
263
- . into_boxed_slice ( ) ;
264
-
265
- // SAFETY: dereferencing the new box pointer is fine as it is guaranteed to not be null
266
- let arguments = unsafe { ( * Box :: into_raw ( argument_vec) ) . as_mut_ptr ( ) } ;
267
-
268
- let default_argument_count = self . default_arguments . len ( ) as u32 ;
269
- let default_argument_vec = self
270
- . default_arguments
271
- . iter ( )
272
- . map ( |arg| sys:: SysPtr :: force_mut ( arg. var_sys ( ) ) )
273
- . collect :: < Vec < _ > > ( )
274
- . into_boxed_slice ( ) ;
275
-
276
- // SAFETY: dereferencing the new box pointer is fine as it is guaranteed to not be null
277
- let default_arguments = unsafe { ( * Box :: into_raw ( default_argument_vec) ) . as_mut_ptr ( ) } ;
252
+ // Destructure self to ensure all fields are used.
253
+ let Self {
254
+ id,
255
+ method_name,
256
+ // TODO: Do we need this?
257
+ class_name : _class_name,
258
+ return_type,
259
+ arguments,
260
+ default_arguments,
261
+ flags,
262
+ } = self ;
263
+
264
+ let argument_count: u32 = arguments
265
+ . len ( )
266
+ . try_into ( )
267
+ . expect ( "cannot have more than `u32::MAX` arguments" ) ;
268
+ let arguments = arguments
269
+ . into_iter ( )
270
+ . map ( |arg| arg. into_owned_property_sys ( ) )
271
+ . collect :: < Box < [ _ ] > > ( ) ;
272
+ let arguments = Box :: leak ( arguments) . as_mut_ptr ( ) ;
273
+
274
+ let default_argument_count: u32 = default_arguments
275
+ . len ( )
276
+ . try_into ( )
277
+ . expect ( "cannot have more than `u32::MAX` default arguments" ) ;
278
+ let default_argument = default_arguments
279
+ . into_iter ( )
280
+ . map ( |arg| arg. into_owned_var_sys ( ) )
281
+ . collect :: < Box < [ _ ] > > ( ) ;
282
+ let default_arguments = Box :: leak ( default_argument) . as_mut_ptr ( ) ;
278
283
279
284
sys:: GDExtensionMethodInfo {
280
- id : self . id ,
281
- name : sys :: SysPtr :: force_mut ( self . method_name . string_sys ( ) ) ,
282
- return_value : self . return_type . property_sys ( ) ,
285
+ id,
286
+ name : method_name. into_owned_string_sys ( ) ,
287
+ return_value : return_type. into_owned_property_sys ( ) ,
283
288
argument_count,
284
289
arguments,
285
290
default_argument_count,
286
291
default_arguments,
287
- flags : u32:: try_from ( self . flags . ord ( ) ) . expect ( "flags should be valid" ) ,
292
+ flags : flags. ord ( ) . try_into ( ) . expect ( "flags should be valid" ) ,
293
+ }
294
+ }
295
+
296
+ /// Properly frees a `sys::GDExtensionMethodInfo` created by [`into_owned_method_sys`](Self::into_owned_method_sys).
297
+ ///
298
+ /// # Safety
299
+ ///
300
+ /// * Must only be used on a struct returned from a call to `into_owned_method_sys`, without modification.
301
+ /// * Must not be called more than once on a `sys::GDExtensionMethodInfo` struct.
302
+ #[ deny( unsafe_op_in_unsafe_fn) ]
303
+ pub unsafe fn free_owned_method_sys ( info : sys:: GDExtensionMethodInfo ) {
304
+ // Destructure info to ensure all fields are used.
305
+ let sys:: GDExtensionMethodInfo {
306
+ name,
307
+ return_value,
308
+ flags : _flags,
309
+ id : _id,
310
+ argument_count,
311
+ arguments,
312
+ default_argument_count,
313
+ default_arguments,
314
+ } = info;
315
+
316
+ // SAFETY: `name` is a pointer that was returned from `StringName::into_owned_string_sys`, and has not been freed before this.
317
+ let _name = unsafe { StringName :: from_owned_string_sys ( name) } ;
318
+
319
+ // SAFETY: `return_value` is a pointer that was returned from `PropertyInfo::into_owned_property_sys`, and has not been freed before
320
+ // this.
321
+ unsafe { PropertyInfo :: free_owned_property_sys ( return_value) } ;
322
+
323
+ // SAFETY:
324
+ // - `from_raw_parts_mut`: `arguments` comes from `as_mut_ptr()` on a mutable slice of length `argument_count`, and no other
325
+ // accesses to the pointer happens for the lifetime of the slice.
326
+ // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
327
+ let arguments = unsafe {
328
+ let slice = std:: slice:: from_raw_parts_mut ( arguments, u32_to_usize ( argument_count) ) ;
329
+
330
+ Box :: from_raw ( slice)
331
+ } ;
332
+
333
+ for info in arguments. iter ( ) {
334
+ // SAFETY: These infos were originally created from a call to `PropertyInfo::into_owned_property_sys`, and this method
335
+ // will not be called again on this pointer.
336
+ unsafe { PropertyInfo :: free_owned_property_sys ( * info) }
337
+ }
338
+
339
+ // SAFETY:
340
+ // - `from_raw_parts_mut`: `default_arguments` comes from `as_mut_ptr()` on a mutable slice of length `default_argument_count`, and no
341
+ // other accesses to the pointer happens for the lifetime of the slice.
342
+ // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
343
+ let default_arguments = unsafe {
344
+ let slice = std:: slice:: from_raw_parts_mut (
345
+ default_arguments,
346
+ u32_to_usize ( default_argument_count) ,
347
+ ) ;
348
+
349
+ Box :: from_raw ( slice)
350
+ } ;
351
+
352
+ for variant in default_arguments. iter ( ) {
353
+ // SAFETY: These pointers were originally created from a call to `Variant::into_owned_var_sys`, and this method will not be
354
+ // called again on this pointer.
355
+ let _variant = unsafe { Variant :: from_owned_var_sys ( * variant) } ;
288
356
}
289
357
}
290
358
}
0 commit comments