@@ -241,50 +241,114 @@ pub struct MethodInfo {
241
241
}
242
242
243
243
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.
248
- ///
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.
244
+ /// Consumes self and turns it into a `sys::GDExtensionMethodInfo`, should be used together with
245
+ /// [`free_owned_method_sys`](Self::free_owned_method_sys).
251
246
///
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 {
247
+ /// This will leak memory unless used together with `free_owned_method_sys`.
248
+ pub fn into_owned_method_sys ( self ) -> sys:: GDExtensionMethodInfo {
255
249
use crate :: obj:: EngineBitfield as _;
256
250
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 ( ) } ;
251
+ // Destructure self to ensure all fields are used.
252
+ let Self {
253
+ id,
254
+ method_name,
255
+ // TODO: Do we need this?
256
+ class_name : _class_name,
257
+ return_type,
258
+ arguments,
259
+ default_arguments,
260
+ flags,
261
+ } = self ;
262
+
263
+ let argument_count: u32 = arguments
264
+ . len ( )
265
+ . try_into ( )
266
+ . expect ( "cannot have more than `u32::MAX` arguments" ) ;
267
+ let arguments = arguments
268
+ . into_iter ( )
269
+ . map ( |arg| arg. into_owned_property_sys ( ) )
270
+ . collect :: < Box < [ _ ] > > ( ) ;
271
+ let arguments = Box :: leak ( arguments) . as_mut_ptr ( ) ;
272
+
273
+ let default_argument_count: u32 = default_arguments
274
+ . len ( )
275
+ . try_into ( )
276
+ . expect ( "cannot have more than `u32::MAX` default arguments" ) ;
277
+ let default_argument = default_arguments
278
+ . into_iter ( )
279
+ . map ( |arg| arg. into_owned_var_sys ( ) )
280
+ . collect :: < Box < [ _ ] > > ( ) ;
281
+ let default_arguments = Box :: leak ( default_argument) . as_mut_ptr ( ) ;
278
282
279
283
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 ( ) ,
284
+ id,
285
+ name : method_name. into_owned_string_sys ( ) ,
286
+ return_value : return_type. into_owned_property_sys ( ) ,
283
287
argument_count,
284
288
arguments,
285
289
default_argument_count,
286
290
default_arguments,
287
- flags : u32 :: try_from ( self . flags . ord ( ) ) . expect ( "flags should be valid" ) ,
291
+ flags : flags. ord ( ) . try_into ( ) . expect ( "flags should be valid" ) ,
288
292
}
289
293
}
294
+
295
+ /// Properly frees a `sys::GDExtensionMethodInfo` created by [`into_owned_method_sys`](Self::into_owned_method_sys).
296
+ ///
297
+ /// # Safety
298
+ ///
299
+ /// * Must only be used on a struct returned from a call to `into_owned_method_sys`, without modification.
300
+ /// * Must not be called more than once on a `sys::GDExtensionMethodInfo` struct.
301
+ #[ deny( unsafe_op_in_unsafe_fn) ]
302
+ pub unsafe fn free_owned_method_sys ( info : sys:: GDExtensionMethodInfo ) {
303
+ // Destructure info to ensure all fields are used.
304
+ let sys:: GDExtensionMethodInfo {
305
+ name,
306
+ return_value,
307
+ flags : _flags,
308
+ id : _id,
309
+ argument_count,
310
+ arguments,
311
+ default_argument_count,
312
+ default_arguments,
313
+ } = info;
314
+
315
+ // SAFETY: `name` and `return_value` were created from the appropriate method calls, and have not been freed before this.
316
+ unsafe {
317
+ let _name = StringName :: from_owned_string_sys ( name) ;
318
+ PropertyInfo :: free_owned_property_sys ( return_value) ;
319
+ }
320
+
321
+ // SAFETY: These pointers were both created from a call to `as_mut_ptr` on a slice. Additionally these pointer will not be accessed
322
+ // again after this function call.
323
+ let ( arguments_slice, default_arguments_slice) = unsafe {
324
+ (
325
+ std:: slice:: from_raw_parts_mut (
326
+ arguments,
327
+ argument_count
328
+ . try_into ( )
329
+ . expect ( "gdext only supports targets where u32 <= usize" ) ,
330
+ ) ,
331
+ std:: slice:: from_raw_parts_mut (
332
+ default_arguments,
333
+ default_argument_count
334
+ . try_into ( )
335
+ . expect ( "gdext only supports targets where u32 <= usize" ) ,
336
+ ) ,
337
+ )
338
+ } ;
339
+
340
+ // SAFETY: We have exclusive ownership of these slices, and they were originally created from a call to `Box::leak`.
341
+ let ( _arguments, default_arguments) = unsafe {
342
+ (
343
+ Box :: from_raw ( arguments_slice) ,
344
+ Box :: from_raw ( default_arguments_slice) ,
345
+ )
346
+ } ;
347
+
348
+ default_arguments. iter ( ) . for_each ( |ptr| {
349
+ // SAFETY: These pointers were originally created from a call to `Variant::into_owner_var_sys`, and this method will not be
350
+ // called again on this pointer.
351
+ let _variant = unsafe { Variant :: from_owned_var_sys ( * ptr) } ;
352
+ } ) ;
353
+ }
290
354
}
0 commit comments