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}