@@ -17,6 +17,7 @@ mod traits;
1717pub mod error;
1818pub use class_name:: ClassName ;
1919pub use godot_convert:: { FromGodot , GodotConvert , ToGodot } ;
20+ use sys:: conv:: u32_to_usize;
2021pub use traits:: { ArrayElement , GodotType } ;
2122
2223pub ( crate ) use crate :: impl_godot_as_self;
@@ -241,50 +242,117 @@ pub struct MethodInfo {
241242}
242243
243244impl 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).
248247 ///
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 {
255250 use crate :: obj:: EngineBitfield as _;
256251
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 ( ) ;
278283
279284 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 ( ) ,
283288 argument_count,
284289 arguments,
285290 default_argument_count,
286291 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) } ;
288356 }
289357 }
290358}
0 commit comments