@@ -241,50 +241,114 @@ pub struct MethodInfo {
241241}
242242
243243impl 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).
251246 ///
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 {
255249 use crate :: obj:: EngineBitfield as _;
256250
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 ( ) ;
278282
279283 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 ( ) ,
283287 argument_count,
284288 arguments,
285289 default_argument_count,
286290 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" ) ,
288292 }
289293 }
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+ }
290354}
0 commit comments