godot_core/meta/
method_info.rs

1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use godot_ffi::conv::u32_to_usize;
9
10use crate::builtin::{StringName, Variant};
11use crate::global::MethodFlags;
12use crate::meta::{ClassId, PropertyInfo};
13use crate::sys;
14
15/// Describes a method in Godot.
16///
17/// Abstraction of the low-level `sys::GDExtensionMethodInfo`.
18// Currently used for ScriptInstance.
19// TODO check overlap with (private) ClassMethodInfo.
20#[derive(Clone, Debug)]
21pub struct MethodInfo {
22    pub id: i32,
23    pub method_name: StringName,
24    pub class_name: ClassId,
25    pub return_type: PropertyInfo,
26    pub arguments: Vec<PropertyInfo>,
27    /// Whether default arguments are real "arguments" is controversial. From the function PoV they are, but for the caller,
28    /// they are just pre-set values to fill in for missing arguments.
29    pub default_arguments: Vec<Variant>,
30    pub flags: MethodFlags,
31}
32
33impl MethodInfo {
34    /// Consumes self and turns it into a `sys::GDExtensionMethodInfo`, should be used together with
35    /// [`free_owned_method_sys`](Self::free_owned_method_sys).
36    ///
37    /// This will leak memory unless used together with `free_owned_method_sys`.
38    pub fn into_owned_method_sys(self) -> sys::GDExtensionMethodInfo {
39        use crate::obj::EngineBitfield as _;
40
41        // Destructure self to ensure all fields are used.
42        let Self {
43            id,
44            method_name,
45            // TODO: Do we need this?
46            class_name: _class_name,
47            return_type,
48            arguments,
49            default_arguments,
50            flags,
51        } = self;
52
53        let argument_count: u32 = arguments
54            .len()
55            .try_into()
56            .expect("cannot have more than `u32::MAX` arguments");
57        let arguments = arguments
58            .into_iter()
59            .map(|arg| arg.into_owned_property_sys())
60            .collect::<Box<[_]>>();
61        let arguments = Box::leak(arguments).as_mut_ptr();
62
63        let default_argument_count: u32 = default_arguments
64            .len()
65            .try_into()
66            .expect("cannot have more than `u32::MAX` default arguments");
67        let default_argument = default_arguments
68            .into_iter()
69            .map(|arg| arg.into_owned_var_sys())
70            .collect::<Box<[_]>>();
71        let default_arguments = Box::leak(default_argument).as_mut_ptr();
72
73        sys::GDExtensionMethodInfo {
74            id,
75            name: method_name.into_owned_string_sys(),
76            return_value: return_type.into_owned_property_sys(),
77            argument_count,
78            arguments,
79            default_argument_count,
80            default_arguments,
81            flags: flags.ord().try_into().expect("flags should be valid"),
82        }
83    }
84
85    /// Properly frees a `sys::GDExtensionMethodInfo` created by [`into_owned_method_sys`](Self::into_owned_method_sys).
86    ///
87    /// # Safety
88    ///
89    /// * Must only be used on a struct returned from a call to `into_owned_method_sys`, without modification.
90    /// * Must not be called more than once on a `sys::GDExtensionMethodInfo` struct.
91    #[deny(unsafe_op_in_unsafe_fn)]
92    pub unsafe fn free_owned_method_sys(info: sys::GDExtensionMethodInfo) {
93        // Destructure info to ensure all fields are used.
94        let sys::GDExtensionMethodInfo {
95            name,
96            return_value,
97            flags: _flags,
98            id: _id,
99            argument_count,
100            arguments,
101            default_argument_count,
102            default_arguments,
103        } = info;
104
105        // SAFETY: `name` is a pointer that was returned from `StringName::into_owned_string_sys`, and has not been freed before this.
106        let _name = unsafe { StringName::from_owned_string_sys(name) };
107
108        // SAFETY: `return_value` is a pointer that was returned from `PropertyInfo::into_owned_property_sys`, and has not been freed before
109        // this.
110        unsafe { PropertyInfo::free_owned_property_sys(return_value) };
111
112        // SAFETY:
113        // - `from_raw_parts_mut`: `arguments` comes from `as_mut_ptr()` on a mutable slice of length `argument_count`, and no other
114        //    accesses to the pointer happens for the lifetime of the slice.
115        // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
116        let arguments = unsafe {
117            let slice = std::slice::from_raw_parts_mut(arguments, u32_to_usize(argument_count));
118
119            Box::from_raw(slice)
120        };
121
122        for info in arguments.iter() {
123            // SAFETY: These infos were originally created from a call to `PropertyInfo::into_owned_property_sys`, and this method
124            // will not be called again on this pointer.
125            unsafe { PropertyInfo::free_owned_property_sys(*info) }
126        }
127
128        // SAFETY:
129        // - `from_raw_parts_mut`: `default_arguments` comes from `as_mut_ptr()` on a mutable slice of length `default_argument_count`, and no
130        //    other accesses to the pointer happens for the lifetime of the slice.
131        // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
132        let default_arguments = unsafe {
133            let slice = std::slice::from_raw_parts_mut(
134                default_arguments,
135                u32_to_usize(default_argument_count),
136            );
137
138            Box::from_raw(slice)
139        };
140
141        for variant in default_arguments.iter() {
142            // SAFETY: These pointers were originally created from a call to `Variant::into_owned_var_sys`, and this method will not be
143            // called again on this pointer.
144            let _variant = unsafe { Variant::from_owned_var_sys(*variant) };
145        }
146    }
147}