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 pub default_arguments: Vec<Variant>,
28 pub flags: MethodFlags,
29}
30
31impl MethodInfo {
32 /// Consumes self and turns it into a `sys::GDExtensionMethodInfo`, should be used together with
33 /// [`free_owned_method_sys`](Self::free_owned_method_sys).
34 ///
35 /// This will leak memory unless used together with `free_owned_method_sys`.
36 pub fn into_owned_method_sys(self) -> sys::GDExtensionMethodInfo {
37 use crate::obj::EngineBitfield as _;
38
39 // Destructure self to ensure all fields are used.
40 let Self {
41 id,
42 method_name,
43 // TODO: Do we need this?
44 class_name: _class_name,
45 return_type,
46 arguments,
47 default_arguments,
48 flags,
49 } = self;
50
51 let argument_count: u32 = arguments
52 .len()
53 .try_into()
54 .expect("cannot have more than `u32::MAX` arguments");
55 let arguments = arguments
56 .into_iter()
57 .map(|arg| arg.into_owned_property_sys())
58 .collect::<Box<[_]>>();
59 let arguments = Box::leak(arguments).as_mut_ptr();
60
61 let default_argument_count: u32 = default_arguments
62 .len()
63 .try_into()
64 .expect("cannot have more than `u32::MAX` default arguments");
65 let default_argument = default_arguments
66 .into_iter()
67 .map(|arg| arg.into_owned_var_sys())
68 .collect::<Box<[_]>>();
69 let default_arguments = Box::leak(default_argument).as_mut_ptr();
70
71 sys::GDExtensionMethodInfo {
72 id,
73 name: method_name.into_owned_string_sys(),
74 return_value: return_type.into_owned_property_sys(),
75 argument_count,
76 arguments,
77 default_argument_count,
78 default_arguments,
79 flags: flags.ord().try_into().expect("flags should be valid"),
80 }
81 }
82
83 /// Properly frees a `sys::GDExtensionMethodInfo` created by [`into_owned_method_sys`](Self::into_owned_method_sys).
84 ///
85 /// # Safety
86 ///
87 /// * Must only be used on a struct returned from a call to `into_owned_method_sys`, without modification.
88 /// * Must not be called more than once on a `sys::GDExtensionMethodInfo` struct.
89 #[deny(unsafe_op_in_unsafe_fn)]
90 pub unsafe fn free_owned_method_sys(info: sys::GDExtensionMethodInfo) {
91 // Destructure info to ensure all fields are used.
92 let sys::GDExtensionMethodInfo {
93 name,
94 return_value,
95 flags: _flags,
96 id: _id,
97 argument_count,
98 arguments,
99 default_argument_count,
100 default_arguments,
101 } = info;
102
103 // SAFETY: `name` is a pointer that was returned from `StringName::into_owned_string_sys`, and has not been freed before this.
104 let _name = unsafe { StringName::from_owned_string_sys(name) };
105
106 // SAFETY: `return_value` is a pointer that was returned from `PropertyInfo::into_owned_property_sys`, and has not been freed before
107 // this.
108 unsafe { PropertyInfo::free_owned_property_sys(return_value) };
109
110 // SAFETY:
111 // - `from_raw_parts_mut`: `arguments` comes from `as_mut_ptr()` on a mutable slice of length `argument_count`, and no other
112 // accesses to the pointer happens for the lifetime of the slice.
113 // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
114 let arguments = unsafe {
115 let slice = std::slice::from_raw_parts_mut(arguments, u32_to_usize(argument_count));
116
117 Box::from_raw(slice)
118 };
119
120 for info in arguments.iter() {
121 // SAFETY: These infos were originally created from a call to `PropertyInfo::into_owned_property_sys`, and this method
122 // will not be called again on this pointer.
123 unsafe { PropertyInfo::free_owned_property_sys(*info) }
124 }
125
126 // SAFETY:
127 // - `from_raw_parts_mut`: `default_arguments` comes from `as_mut_ptr()` on a mutable slice of length `default_argument_count`, and no
128 // other accesses to the pointer happens for the lifetime of the slice.
129 // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
130 let default_arguments = unsafe {
131 let slice = std::slice::from_raw_parts_mut(
132 default_arguments,
133 u32_to_usize(default_argument_count),
134 );
135
136 Box::from_raw(slice)
137 };
138
139 for variant in default_arguments.iter() {
140 // SAFETY: These pointers were originally created from a call to `Variant::into_owned_var_sys`, and this method will not be
141 // called again on this pointer.
142 let _variant = unsafe { Variant::from_owned_var_sys(*variant) };
143 }
144 }
145}