diff --git a/ReadMe.md b/ReadMe.md index 293c08e1b..8f985c249 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,6 +1,6 @@ ![logo.png](assets/gdext-ferris.png) -# Rust bindings for GDExtension +# Rust bindings for Godot 4 _**[Website]** | **[API Docs]** | [Discord] | [Mastodon] | [Twitter]_ diff --git a/godot-codegen/src/central_generator.rs b/godot-codegen/src/central_generator.rs index 60d57dac6..81b285384 100644 --- a/godot-codegen/src/central_generator.rs +++ b/godot-codegen/src/central_generator.rs @@ -689,8 +689,8 @@ fn make_builtin_lifecycle_table(builtin_types: &BuiltinTypeMap) -> TokenStream { }, method_decls: Vec::with_capacity(len), method_inits: Vec::with_capacity(len), - class_count: 0, - method_count: len, + class_count: len, + method_count: 0, }; // Note: NIL is not part of this iteration, it will be added manually @@ -705,7 +705,6 @@ fn make_builtin_lifecycle_table(builtin_types: &BuiltinTypeMap) -> TokenStream { table.method_decls.push(decls); table.method_inits.push(inits); - table.class_count += 1; } make_named_method_table(table) diff --git a/godot-codegen/src/class_generator.rs b/godot-codegen/src/class_generator.rs index 0ec57c583..2d3ef8e28 100644 --- a/godot-codegen/src/class_generator.rs +++ b/godot-codegen/src/class_generator.rs @@ -6,8 +6,8 @@ //! Generates a file for each Godot engine + builtin class -use proc_macro2::{Ident, Literal, TokenStream}; -use quote::{format_ident, quote, ToTokens}; +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; use std::path::Path; use crate::api_parser::*; @@ -122,6 +122,20 @@ impl FnReturn { } } } + + fn type_tokens(&self) -> TokenStream { + match &self.type_ { + Some(RustTy::EngineClass { tokens, .. }) => { + quote! { Option<#tokens> } + } + Some(ty) => { + quote! { #ty } + } + _ => { + quote! { () } + } + } + } } // ---------------------------------------------------------------------------------------------------------------------------------------------- @@ -158,6 +172,7 @@ struct FnSignature<'a> { surrounding_class: Option<&'a TyName>, // None if global function is_private: bool, is_virtual: bool, + is_vararg: bool, qualifier: FnQualifier, params: Vec, return_value: FnReturn, @@ -167,8 +182,6 @@ struct FnSignature<'a> { struct FnCode { receiver: FnReceiver, - variant_ffi: Option, - init_code: TokenStream, varcall_invocation: TokenStream, ptrcall_invocation: TokenStream, } @@ -576,16 +589,12 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate }; // mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub + let imports = util::make_imports(); let tokens = quote! { #![doc = #module_doc] - use godot_ffi as sys; + #imports use crate::engine::notify::*; - use crate::builtin::*; - use crate::engine::native::*; - use crate::obj::Gd; - use crate::builtin::meta::ClassName; - use sys::GodotFfi as _; use std::ffi::c_void; pub(super) mod re_export { @@ -751,7 +760,7 @@ fn make_notification_enum( )* /// Since Godot represents notifications as integers, it's always possible that a notification outside the known types - /// is received. For example, the user can manually issue notifications through `Object.notification()`. + /// is received. For example, the user can manually issue notifications through `Object::notify()`. Unknown(i32), } @@ -828,17 +837,13 @@ fn make_builtin_class( ctx, ); + let imports = util::make_imports(); let enums = make_enums(&class_enums, builtin_name, ctx); let special_constructors = make_special_builtin_methods(builtin_name, ctx); // mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub let code = quote! { - use godot_ffi as sys; - use crate::builtin::*; - use crate::engine::native::*; - use crate::obj::Gd; - use crate::sys::GodotFfi as _; - use crate::engine::Object; + #imports #[repr(transparent)] pub struct #inner_class<'a> { @@ -871,16 +876,12 @@ fn make_native_structure( ) -> GeneratedBuiltin { let class_name = &class_name.rust_ty; + let imports = util::make_imports(); let fields = make_native_structure_fields(&structure.format, ctx); // mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub let tokens = quote! { - use godot_ffi as sys; - use crate::builtin::*; - use crate::engine::native::*; - use crate::obj::Gd; - use crate::sys::GodotFfi as _; - use crate::engine::Object; + #imports #[repr(C)] pub struct #class_name { @@ -1100,34 +1101,35 @@ fn make_method_definition( quote! { self.object_ptr }, ); - let is_varcall = method.is_vararg; - let variant_ffi = is_varcall.then(VariantFfi::variant_ptr); - - let function_provider = if method.is_vararg { - // varcall - quote! { sys::interface_fn!(object_method_bind_call) } - } else { - // ptrcall - quote! { sys::interface_fn!(object_method_bind_ptrcall) } - }; - let table_index = ctx.get_table_index(&MethodTableKey::ClassMethod { api_level: *api_level, class_ty: class_name.clone(), method_name: method.name.clone(), }); - let init_code = quote! { - let __method_bind = sys::#get_method_table().fptr_by_index(#table_index); - let __call_fn = #function_provider; + let receiver_ffi_arg = &receiver.ffi_arg; + let ptrcall_invocation = quote! { + let method_bind = sys::#get_method_table().fptr_by_index(#table_index); + let object_ptr = #receiver_ffi_arg; + + ::class_ptrcall::( + method_bind, + object_ptr, + args + ) }; - let receiver_ffi_arg = &receiver.ffi_arg; let varcall_invocation = quote! { - __call_fn(__method_bind, #receiver_ffi_arg, __args_ptr, __args.len() as i64, return_ptr, std::ptr::addr_of_mut!(__err)); - }; - let ptrcall_invocation = quote! { - __call_fn(__method_bind, #receiver_ffi_arg, __args_ptr, return_ptr); + let method_bind = sys::#get_method_table().fptr_by_index(#table_index); + let type_ptr = #receiver_ffi_arg; + + ::out_class_varcall( + method_bind, + #method_name_str, + type_ptr, + args, + varargs + ) }; make_function_definition( @@ -1136,14 +1138,13 @@ fn make_method_definition( surrounding_class: Some(class_name), is_private: special_cases::is_private(class_name, &method.name), is_virtual: false, + is_vararg: method.is_vararg, qualifier: FnQualifier::for_method(method.is_const, method.is_static), params: FnParam::new_range(&method.arguments, ctx), return_value: FnReturn::new(&method.return_value, ctx), }, &FnCode { receiver, - variant_ffi, - init_code, varcall_invocation, ptrcall_invocation, }, @@ -1167,22 +1168,33 @@ fn make_builtin_method_definition( .as_deref() .map(MethodReturn::from_type_no_meta); - let is_varcall = method.is_vararg; - let variant_ffi = is_varcall.then(VariantFfi::type_ptr); - let table_index = ctx.get_table_index(&MethodTableKey::BuiltinMethod { builtin_ty: builtin_name.clone(), method_name: method.name.clone(), }); - let init_code = quote! { - let __call_fn = sys::builtin_method_table().fptr_by_index(#table_index); - }; - let receiver = make_receiver(method.is_static, method.is_const, quote! { self.sys_ptr }); let receiver_ffi_arg = &receiver.ffi_arg; + let ptrcall_invocation = quote! { - __call_fn(#receiver_ffi_arg, __args_ptr, return_ptr, __args.len() as i32); + let method_bind = sys::builtin_method_table().fptr_by_index(#table_index); + let object_ptr = #receiver_ffi_arg; + + ::out_builtin_ptrcall::( + method_bind, + object_ptr, + args + ) + }; + + let varcall_invocation = quote! { + ::out_class_varcall( + method_bind, + #method_name_str, + object_ptr, + args, + varargs + ) }; make_function_definition( @@ -1191,6 +1203,7 @@ fn make_builtin_method_definition( surrounding_class: Some(inner_class_name), is_private: special_cases::is_private(builtin_name, &method.name), is_virtual: false, + is_vararg: method.is_vararg, qualifier: FnQualifier::for_method(method.is_const, method.is_static), // Disable default parameters for builtin classes. @@ -1200,9 +1213,7 @@ fn make_builtin_method_definition( }, &FnCode { receiver, - variant_ffi, - init_code, - varcall_invocation: ptrcall_invocation.clone(), + varcall_invocation, ptrcall_invocation, }, ) @@ -1223,12 +1234,24 @@ pub(crate) fn make_utility_function_definition( .return_type .as_deref() .map(MethodReturn::from_type_no_meta); - let variant_ffi = function.is_vararg.then_some(VariantFfi::type_ptr()); - let init_code = quote! { - let __call_fn = sys::utility_function_table().#fn_ptr; + + let ptrcall_invocation = quote! { + let utility_fn = sys::utility_function_table().#fn_ptr; + + ::out_utility_ptrcall( + utility_fn, + args + ) }; - let invocation = quote! { - __call_fn(return_ptr, __args_ptr, __args.len() as i32); + + let varcall_invocation = quote! { + let utility_fn = sys::utility_function_table().#fn_ptr; + + ::out_utility_ptrcall_varargs( + utility_fn, + args, + varargs + ) }; let definition = make_function_definition( @@ -1237,16 +1260,15 @@ pub(crate) fn make_utility_function_definition( surrounding_class: None, is_private: false, is_virtual: false, + is_vararg: function.is_vararg, qualifier: FnQualifier::Global, params: FnParam::new_range(&function.arguments, ctx), return_value: FnReturn::new(&return_value, ctx), }, &FnCode { receiver: FnReceiver::global_function(), - variant_ffi, - init_code, - varcall_invocation: invocation.clone(), - ptrcall_invocation: invocation, + varcall_invocation, + ptrcall_invocation, }, ); @@ -1254,26 +1276,6 @@ pub(crate) fn make_utility_function_definition( definition.into_functions_only() } -/// Defines which methods to use to convert between `Variant` and FFI (either variant ptr or type ptr) -struct VariantFfi { - sys_method: Ident, - from_sys_init_method: Ident, -} -impl VariantFfi { - fn variant_ptr() -> Self { - Self { - sys_method: ident("var_sys_const"), - from_sys_init_method: ident("from_var_sys_init"), - } - } - fn type_ptr() -> Self { - Self { - sys_method: ident("sys_const"), - from_sys_init_method: ident("from_sys_init_default"), - } - } -} - fn make_vis(is_private: bool) -> TokenStream { if is_private { quote! { pub(crate) } @@ -1296,23 +1298,22 @@ fn make_function_definition(sig: &FnSignature, code: &FnCode) -> FnDefinition { ( quote! { unsafe }, quote! { - #[doc = "# Safety"] - #[doc = ""] - #[doc = "Godot currently does not document safety requirements on this method. Make sure you understand the underlying semantics."] + /// # Safety + /// + /// Godot currently does not document safety requirements on this method. Make sure you understand the underlying semantics. }, ) } else { (TokenStream::new(), TokenStream::new()) }; - let is_varcall = code.variant_ffi.is_some(); - let [params, variant_types, arg_exprs, arg_names] = - make_params_and_impl(&sig.params, is_varcall, false); + let [params, param_types, arg_names] = make_params_exprs(&sig.params); + let godot_fn_name_str = sig.function_name; let primary_fn_name = if has_default_params { - format_ident!("{}_full", safe_ident(sig.function_name)) + format_ident!("{}_full", safe_ident(godot_fn_name_str)) } else { - safe_ident(sig.function_name) + safe_ident(godot_fn_name_str) }; let (default_fn_code, default_structs_code) = if has_default_params { @@ -1321,60 +1322,33 @@ fn make_function_definition(sig: &FnSignature, code: &FnCode) -> FnDefinition { (TokenStream::new(), TokenStream::new()) }; - let args_indices = (0..arg_exprs.len()).map(Literal::usize_unsuffixed); - - let (prepare_arg_types, error_fn_context); - if code.variant_ffi.is_some() { - // varcall (using varargs) - prepare_arg_types = quote! { - let mut __arg_types = Vec::with_capacity(__explicit_args.len() + varargs.len()); - // __arg_types.extend(__explicit_args.iter().map(Variant::get_type)); - __arg_types.extend(varargs.iter().map(Variant::get_type)); - let __vararg_str = varargs.iter().map(|v| format!("{v}")).collect::>().join(", "); - }; - - let joined = arg_names - .iter() - .map(|n| format!("{{{n}:?}}")) - .collect::>() - .join(", "); - - let fmt = format!("{f}({joined}; {{__vararg_str}})", f = sig.function_name); - error_fn_context = quote! { &format!(#fmt) }; - } else { - // ptrcall - prepare_arg_types = quote! { - let __arg_types = [ - #( #variant_types ),* - ]; - }; - error_fn_context = sig.function_name.to_token_stream(); + let return_ty = &sig.return_value.type_tokens(); + let call_sig = quote! { + ( #return_ty, #(#param_types),* ) }; let return_decl = &sig.return_value.decl; - let call_code = make_return_and_impl( - &sig.return_value, - code, - prepare_arg_types, - error_fn_context, - sig.is_virtual, - ); let receiver_param = &code.receiver.param; let primary_function = if sig.is_virtual { + // Virtual functions + quote! { #safety_doc #maybe_unsafe fn #primary_fn_name( #receiver_param #( #params, )* ) #return_decl { - #call_code + unimplemented!() } } - } else if let Some(variant_ffi) = code.variant_ffi.as_ref() { - // varcall (using varargs) - let sys_method = &variant_ffi.sys_method; - let init_code = &code.init_code; + } else if sig.is_vararg { + // Varargs (usually varcall, but not necessarily -- utilities use ptrcall) + + // If the return type is not Variant, then convert to concrete target type + let varcall_invocation = &code.varcall_invocation; + + // TODO use Result instead of panic on error quote! { #safety_doc #vis #maybe_unsafe fn #primary_fn_name( @@ -1382,47 +1356,42 @@ fn make_function_definition(sig: &FnSignature, code: &FnCode) -> FnDefinition { #( #params, )* varargs: &[Variant] ) #return_decl { - unsafe { - #init_code - - let __explicit_args = [ - #( #arg_exprs ),* - ]; + type CallSig = #call_sig; - let mut __args = Vec::with_capacity(__explicit_args.len() + varargs.len()); - __args.extend(__explicit_args.iter().map(Variant::#sys_method)); - __args.extend(varargs.iter().map(Variant::#sys_method)); + let args = (#( #arg_names, )*); - let __args_ptr = __args.as_ptr(); - - #call_code + unsafe { + #varcall_invocation } } } } else { - // ptrcall - let init_code = &code.init_code; + // Always ptrcall, no varargs + + let ptrcall_invocation = &code.ptrcall_invocation; + let maybe_return_ty = &sig.return_value.type_; + + // This differentiation is needed because we need to differentiate between Option>, T and () as return types. + // Rust traits don't provide specialization and thus would encounter overlapping blanket impls, so we cannot use the type system here. + let ret_marshal = match maybe_return_ty { + Some(RustTy::EngineClass { tokens, .. }) => quote! { PtrcallReturnOptionGdT<#tokens> }, + Some(return_ty) => quote! { PtrcallReturnT<#return_ty> }, + None => quote! { PtrcallReturnUnit }, + }; + quote! { #safety_doc #vis #maybe_unsafe fn #primary_fn_name( #receiver_param #( #params, )* ) #return_decl { - unsafe { - #init_code + type RetMarshal = #ret_marshal; + type CallSig = #call_sig; - #[allow(clippy::let_unit_value)] - let __args = ( - #( #arg_exprs, )* - ); + let args = (#( #arg_names, )*); - let __args = [ - #( sys::GodotFfi::as_arg_ptr(&__args.#args_indices) ),* - ]; - - let __args_ptr = __args.as_ptr(); - - #call_code + unsafe { + #ptrcall_invocation } } } @@ -1586,7 +1555,7 @@ fn make_extender_receiver(sig: &FnSignature) -> ExtenderReceiver { // Not exactly EngineClass, but close enough type_: RustTy::EngineClass { tokens: quote! { &'a #builder_mut re_export::#class }, - class: String::new(), + class: ident("unknown"), }, default_value: None, }), @@ -1714,39 +1683,21 @@ fn make_receiver(is_static: bool, is_const: bool, ffi_arg: TokenStream) -> FnRec } } -fn make_params_and_impl( - method_args: &[FnParam], - is_varcall: bool, - skip_defaults: bool, -) -> [Vec; 4] { +fn make_params_exprs(method_args: &[FnParam]) -> [Vec; 3] { let mut params = vec![]; - let mut variant_types = vec![]; - let mut arg_exprs = vec![]; + let mut param_types = vec![]; let mut arg_names = vec![]; for param in method_args.iter() { - if skip_defaults && param.default_value.is_some() { - continue; - } - let param_name = ¶m.name; let param_ty = ¶m.type_; - let arg_expr = if is_varcall { - quote! { <#param_ty as ToVariant>::to_variant(&#param_name) } - } else if let RustTy::EngineClass { tokens: path, .. } = ¶m_ty { - quote! { <#path as sys::GodotFuncMarshal>::try_into_via(#param_name).unwrap() } - } else { - quote! { <#param_ty as sys::GodotFuncMarshal>::try_into_via(#param_name).unwrap() } - }; - params.push(quote! { #param_name: #param_ty }); - variant_types.push(quote! { <#param_ty as VariantMetadata>::variant_type() }); - arg_exprs.push(arg_expr); + param_types.push(quote! { #param_ty }); arg_names.push(quote! { #param_name }); } - [params, variant_types, arg_exprs, arg_names] + [params, param_types, arg_names] } fn make_params_and_args(method_args: &[&FnParam]) -> (Vec, Vec) { @@ -1761,75 +1712,6 @@ fn make_params_and_args(method_args: &[&FnParam]) -> (Vec, Vec TokenStream { - let return_ty = &return_value.type_; - - // Virtual methods - if is_virtual { - return quote! { unimplemented!() }; - } - - // Varcall - if let Some(variant_ffi) = &code.variant_ffi { - // If the return type is not Variant, then convert to concrete target type - let return_expr = match return_ty { - None => TokenStream::new(), // unit return - Some(RustTy::BuiltinIdent(ident)) if ident == "Variant" => quote! { __variant }, - Some(_) => quote! { __variant.to() }, - }; - let from_sys_init_method = &variant_ffi.from_sys_init_method; - let varcall_invocation = &code.varcall_invocation; - - // Note: __err may remain unused if the #call does not handle errors (e.g. utility fn, ptrcall, ...). - // __variant remains unused if the function returns unit. - // TODO use Result instead of panic on error - return quote! { - let __variant = Variant::#from_sys_init_method(|return_ptr| { - let mut __err = sys::default_call_error(); - #varcall_invocation - if __err.error != sys::GDEXTENSION_CALL_OK { - #prepare_arg_types - sys::panic_call_error(&__err, #error_fn_context, &__arg_types); - } - }); - #return_expr - }; - } - - // Ptrcall - let ptrcall_invocation = &code.ptrcall_invocation; - match return_ty { - Some(RustTy::EngineClass { tokens, .. }) => { - let return_ty = tokens; - quote! { - <#return_ty>::from_sys_init_opt(|return_ptr| { - #ptrcall_invocation - }) - } - } - Some(return_ty) => { - quote! { - let via = <<#return_ty as sys::GodotFuncMarshal>::Via as sys::GodotFfi>::from_sys_init_default(|return_ptr| { - #ptrcall_invocation - }); - <#return_ty as sys::GodotFuncMarshal>::try_from_via(via).unwrap() - } - } - None => { - quote! { - let return_ptr = std::ptr::null_mut(); - #ptrcall_invocation - } - } - } -} - fn make_virtual_methods_trait( class: &Class, class_name: &TyName, @@ -1911,6 +1793,7 @@ fn make_virtual_method(method: &ClassMethod, ctx: &mut Context) -> TokenStream { surrounding_class: None, // no default parameters needed for virtual methods is_private: false, is_virtual: true, + is_vararg: false, qualifier: FnQualifier::for_method(method.is_const, method.is_static), params: FnParam::new_range(&method.arguments, ctx), return_value: FnReturn::new(&method.return_value, ctx), @@ -1918,8 +1801,6 @@ fn make_virtual_method(method: &ClassMethod, ctx: &mut Context) -> TokenStream { &FnCode { receiver: make_receiver(false, method.is_const, TokenStream::new()), // make_return() requests following args, but they are not used for virtual methods. We can provide empty streams. - variant_ffi: None, - init_code: TokenStream::new(), varcall_invocation: TokenStream::new(), ptrcall_invocation: TokenStream::new(), }, diff --git a/godot-codegen/src/codegen_special_cases.rs b/godot-codegen/src/codegen_special_cases.rs index 07203480b..b3fa17095 100644 --- a/godot-codegen/src/codegen_special_cases.rs +++ b/godot-codegen/src/codegen_special_cases.rs @@ -42,7 +42,7 @@ fn is_type_excluded(ty: &str, ctx: &mut Context) -> bool { None => false, Some(class) => is_class_excluded(class.as_str()), }, - RustTy::EngineClass { class, .. } => is_class_excluded(class), + RustTy::EngineClass { class, .. } => is_class_excluded(&class.to_string()), } } is_rust_type_excluded(&util::to_rust_type(ty, None, ctx)) diff --git a/godot-codegen/src/lib.rs b/godot-codegen/src/lib.rs index 5a3c7095b..580a440f5 100644 --- a/godot-codegen/src/lib.rs +++ b/godot-codegen/src/lib.rs @@ -186,9 +186,10 @@ enum RustTy { /// `Gd` EngineClass { + /// Tokens with full `Gd` tokens: TokenStream, - #[allow(dead_code)] // currently not read - class: String, + /// only inner `T` + class: Ident, }, } diff --git a/godot-codegen/src/util.rs b/godot-codegen/src/util.rs index 7570b231e..e0be89e11 100644 --- a/godot-codegen/src/util.rs +++ b/godot-codegen/src/util.rs @@ -144,6 +144,18 @@ pub(crate) fn option_as_slice(option: &Option>) -> &[T] { option.as_ref().map_or(&[], Vec::as_slice) } +pub(crate) fn make_imports() -> TokenStream { + quote! { + use godot_ffi as sys; + use crate::builtin::*; + use crate::builtin::meta::{ClassName, PtrcallReturnUnit, PtrcallReturnT, PtrcallReturnOptionGdT, PtrcallSignatureTuple, VarcallSignatureTuple}; + use crate::engine::native::*; + use crate::engine::Object; + use crate::obj::Gd; + use crate::sys::GodotFfi as _; + } +} + // Use &ClassMethod instead of &str, to make sure it's the original Godot name and no rename. pub(crate) fn make_class_method_ptr_name(class_ty: &TyName, method: &ClassMethod) -> Ident { format_ident!("{}__{}", to_snake_case(&class_ty.godot_ty), method.name) @@ -693,7 +705,7 @@ fn to_rust_type_uncached(full_ty: &GodotTy, ctx: &mut Context) -> RustTy { let ty = rustify_ty(ty); RustTy::EngineClass { tokens: quote! { Gd }, - class: ty.to_string(), + class: ty, } } } diff --git a/godot-codegen/src/utilities_generator.rs b/godot-codegen/src/utilities_generator.rs index 4d8f7c1cb..859051e34 100644 --- a/godot-codegen/src/utilities_generator.rs +++ b/godot-codegen/src/utilities_generator.rs @@ -9,8 +9,8 @@ use std::path::Path; use quote::quote; use crate::class_generator::make_utility_function_definition; -use crate::Context; use crate::{api_parser::*, SubmitFn}; +use crate::{util, Context}; pub(crate) fn generate_utilities_file( api: &ExtensionApi, @@ -24,6 +24,8 @@ pub(crate) fn generate_utilities_file( .iter() .map(|utility_fn| make_utility_function_definition(utility_fn, ctx)); + let imports = util::make_imports(); + let tokens = quote! { //! Global utility functions. //! @@ -32,11 +34,7 @@ pub(crate) fn generate_utilities_file( //! //! See also [Godot docs for `@GlobalScope`](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#methods). - use godot_ffi as sys; - use crate::builtin::*; - use crate::obj::Gd; - use crate::engine::Object; - use sys::GodotFfi as _; + #imports #(#utility_fn_defs)* }; diff --git a/godot-core/src/builtin/meta/mod.rs b/godot-core/src/builtin/meta/mod.rs index cafb237cb..8ae0d11c8 100644 --- a/godot-core/src/builtin/meta/mod.rs +++ b/godot-core/src/builtin/meta/mod.rs @@ -7,9 +7,13 @@ pub mod registration; mod class_name; +mod return_marshal; mod signature; pub use class_name::*; +#[doc(hidden)] +pub use return_marshal::*; +#[doc(hidden)] pub use signature::*; use godot_ffi as sys; diff --git a/godot-core/src/builtin/meta/return_marshal.rs b/godot-core/src/builtin/meta/return_marshal.rs new file mode 100644 index 000000000..ab44f7394 --- /dev/null +++ b/godot-core/src/builtin/meta/return_marshal.rs @@ -0,0 +1,61 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use crate::obj::{Gd, GodotClass}; +use crate::sys; + +/// Specifies how the return type is marshalled in a ptrcall. +#[doc(hidden)] +pub trait PtrcallReturn { + type Ret; + + unsafe fn call(process_return_ptr: impl FnMut(sys::GDExtensionTypePtr)) -> Self::Ret; +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- + +pub struct PtrcallReturnOptionGdT { + _marker: std::marker::PhantomData, +} + +impl PtrcallReturn for PtrcallReturnOptionGdT> { + type Ret = Option>; + + unsafe fn call(process_return_ptr: impl FnMut(sys::GDExtensionTypePtr)) -> Self::Ret { + Gd::::from_sys_init_opt(process_return_ptr) + } +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- + +pub struct PtrcallReturnT { + _marker: std::marker::PhantomData, +} + +impl PtrcallReturn for PtrcallReturnT { + type Ret = T; + + unsafe fn call(mut process_return_ptr: impl FnMut(sys::GDExtensionTypePtr)) -> Self::Ret { + let via = ::from_sys_init_default(|return_ptr| { + process_return_ptr(return_ptr) + }); + + T::try_from_via(via).unwrap() + } +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- + +pub enum PtrcallReturnUnit {} + +impl PtrcallReturn for PtrcallReturnUnit { + type Ret = (); + + unsafe fn call(mut process_return_ptr: impl FnMut(sys::GDExtensionTypePtr)) -> Self::Ret { + let return_ptr = std::ptr::null_mut(); + process_return_ptr(return_ptr); + } +} diff --git a/godot-core/src/builtin/meta/signature.rs b/godot-core/src/builtin/meta/signature.rs index 4d856e41f..bf1129b0d 100644 --- a/godot-core/src/builtin/meta/signature.rs +++ b/godot-core/src/builtin/meta/signature.rs @@ -7,6 +7,8 @@ use godot_ffi as sys; use std::fmt::Debug; +use sys::{BuiltinMethodBind, ClassMethodBind, UtilityFunctionBind}; + #[doc(hidden)] pub trait VarcallSignatureTuple: PtrcallSignatureTuple { const PARAM_COUNT: usize; @@ -18,7 +20,7 @@ pub trait VarcallSignatureTuple: PtrcallSignatureTuple { // TODO(uninit) - can we use this for varcall/ptrcall? // ret: sys::GDExtensionUninitializedVariantPtr // ret: sys::GDExtensionUninitializedTypePtr - unsafe fn varcall( + unsafe fn in_varcall( instance_ptr: sys::GDExtensionClassInstancePtr, args_ptr: *const sys::GDExtensionConstVariantPtr, ret: sys::GDExtensionVariantPtr, @@ -26,6 +28,22 @@ pub trait VarcallSignatureTuple: PtrcallSignatureTuple { func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret, method_name: &str, ); + + unsafe fn out_class_varcall( + method_bind: sys::GDExtensionMethodBindPtr, + method_name: &'static str, + object_ptr: sys::GDExtensionObjectPtr, + args: Self::Params, + varargs: &[Variant], + ) -> Self::Ret; + + unsafe fn out_utility_ptrcall_varargs( + utility_fn: UtilityFunctionBind, + args: Self::Params, + varargs: &[Variant], + ) -> Self::Ret; + + fn format_args(args: &Self::Params) -> String; } #[doc(hidden)] @@ -35,7 +53,7 @@ pub trait PtrcallSignatureTuple { // Note: this method imposes extra bounds on GodotFfi, which may not be implemented for user types. // We could fall back to varcalls in such cases, and not require GodotFfi categorically. - unsafe fn ptrcall( + unsafe fn in_ptrcall( instance_ptr: sys::GDExtensionClassInstancePtr, args_ptr: *const sys::GDExtensionConstTypePtr, ret: sys::GDExtensionTypePtr, @@ -43,6 +61,21 @@ pub trait PtrcallSignatureTuple { method_name: &str, call_type: sys::PtrcallType, ); + + unsafe fn out_class_ptrcall>( + method_bind: sys::GDExtensionMethodBindPtr, + object_ptr: sys::GDExtensionObjectPtr, + args: Self::Params, + ) -> Self::Ret; + + unsafe fn out_builtin_ptrcall>( + builtin_fn: BuiltinMethodBind, + type_ptr: sys::GDExtensionTypePtr, + args: Self::Params, + ) -> Self::Ret; + + unsafe fn out_utility_ptrcall(utility_fn: UtilityFunctionBind, args: Self::Params) + -> Self::Ret; } // impl Sig for [P; N] @@ -68,17 +101,20 @@ use super::registration::method::MethodParamOrReturnInfo; macro_rules! impl_varcall_signature_for_tuple { ( - $PARAM_COUNT:literal, + $PARAM_COUNT:literal; $R:ident - $(, $Pn:ident : $n:literal)* + $(, $Pn:ident : $n:tt)* // $n cannot be literal if substituted as tuple index .0 ) => { + // R: FromVariantIndirect, Pn: ToVariant -> when calling engine APIs + // R: ToVariant, Pn: #[allow(unused_variables)] impl<$R, $($Pn,)*> VarcallSignatureTuple for ($R, $($Pn,)*) - where $R: VariantMetadata + ToVariant + sys::GodotFuncMarshal + Debug, - $( $Pn: VariantMetadata + FromVariant + sys::GodotFuncMarshal + Debug, )* + where $R: VariantMetadata + FromVariantIndirect + ToVariant + sys::GodotFuncMarshal + Debug, + $( $Pn: VariantMetadata + ToVariant + FromVariant + sys::GodotFuncMarshal + Debug, )* { const PARAM_COUNT: usize = $PARAM_COUNT; + #[inline] fn param_info(index: usize, param_name: &str) -> Option { match index { $( @@ -88,10 +124,12 @@ macro_rules! impl_varcall_signature_for_tuple { } } + #[inline] fn return_info() -> Option { $R::return_info() } + #[inline] fn param_property_info(index: usize, param_name: &str) -> PropertyInfo { match index { $( @@ -101,9 +139,8 @@ macro_rules! impl_varcall_signature_for_tuple { } } - #[inline] - unsafe fn varcall( + unsafe fn in_varcall( instance_ptr: sys::GDExtensionClassInstancePtr, args_ptr: *const sys::GDExtensionConstVariantPtr, ret: sys::GDExtensionVariantPtr, @@ -119,6 +156,76 @@ macro_rules! impl_varcall_signature_for_tuple { varcall_return::<$R>(func(instance_ptr, args), ret, err) } + + #[inline] + unsafe fn out_class_varcall( + method_bind: ClassMethodBind, + method_name: &'static str, + object_ptr: sys::GDExtensionObjectPtr, + args: Self::Params, + varargs: &[Variant], + ) -> Self::Ret { + let class_fn = sys::interface_fn!(object_method_bind_call); + + let explicit_args = [ + $( + <$Pn as ToVariant>::to_variant(&args.$n), + )* + ]; + + let mut variant_ptrs = Vec::with_capacity(explicit_args.len() + varargs.len()); + variant_ptrs.extend(explicit_args.iter().map(Variant::var_sys_const)); + variant_ptrs.extend(varargs.iter().map(Variant::var_sys_const)); + + let variant = Variant::from_var_sys_init(|return_ptr| { + let mut err = sys::default_call_error(); + class_fn( + method_bind, + object_ptr, + variant_ptrs.as_ptr(), + variant_ptrs.len() as i64, + return_ptr, + std::ptr::addr_of_mut!(err), + ); + + check_varcall_error(&err, method_name, &explicit_args, varargs); + }); + ::convert(variant) + } + + // Note: this is doing a ptrcall, but uses variant conversions for it + #[inline] + unsafe fn out_utility_ptrcall_varargs( + utility_fn: UtilityFunctionBind, + args: Self::Params, + varargs: &[Variant], + ) -> Self::Ret { + + let explicit_args: [Variant; $PARAM_COUNT] = [ + $( + <$Pn as ToVariant>::to_variant(&args.$n), + )* + ]; + + let mut type_ptrs = Vec::with_capacity(explicit_args.len() + varargs.len()); + type_ptrs.extend(explicit_args.iter().map(sys::GodotFfi::sys_const)); + type_ptrs.extend(varargs.iter().map(sys::GodotFfi::sys_const)); + + // Important: this calls from_sys_init_default(). + PtrcallReturnT::<$R>::call(|return_ptr| { + utility_fn(return_ptr, type_ptrs.as_ptr(), type_ptrs.len() as i32); + }) + } + + #[inline] + fn format_args(args: &Self::Params) -> String { + let mut string = String::new(); + $( + string.push_str(&format!("{:?}, ", args.$n)); + )* + string.remove(string.len() - 2); // remove trailing ", " + string + } } }; } @@ -126,7 +233,7 @@ macro_rules! impl_varcall_signature_for_tuple { macro_rules! impl_ptrcall_signature_for_tuple { ( $R:ident - $(, $Pn:ident : $n:literal)* + $(, $Pn:ident : $n:tt)* // $n cannot be literal if substituted as tuple index .0 ) => { #[allow(unused_variables)] impl<$R, $($Pn,)*> PtrcallSignatureTuple for ($R, $($Pn,)*) @@ -136,7 +243,8 @@ macro_rules! impl_ptrcall_signature_for_tuple { type Params = ($($Pn,)*); type Ret = $R; - unsafe fn ptrcall( + #[inline] + unsafe fn in_ptrcall( instance_ptr: sys::GDExtensionClassInstancePtr, args_ptr: *const sys::GDExtensionConstTypePtr, ret: sys::GDExtensionTypePtr, @@ -155,6 +263,79 @@ macro_rules! impl_ptrcall_signature_for_tuple { // TODO: double-check the above ptrcall_return::<$R>(func(instance_ptr, args), ret, method_name, call_type) } + + #[inline] + unsafe fn out_class_ptrcall>( + method_bind: ClassMethodBind, + object_ptr: sys::GDExtensionObjectPtr, + args: Self::Params, + ) -> Self::Ret { + let class_fn = sys::interface_fn!(object_method_bind_ptrcall); + + #[allow(clippy::let_unit_value)] + let marshalled_args = ( + $( + <$Pn as sys::GodotFuncMarshal>::try_into_via(args.$n).unwrap(), + )* + ); + + let type_ptrs = [ + $( + sys::GodotFfi::as_arg_ptr(&marshalled_args.$n), + )* + ]; + + Rr::call(|return_ptr| { + class_fn(method_bind, object_ptr, type_ptrs.as_ptr(), return_ptr); + }) + } + + #[inline] + unsafe fn out_builtin_ptrcall>( + builtin_fn: BuiltinMethodBind, + type_ptr: sys::GDExtensionTypePtr, + args: Self::Params, + ) -> Self::Ret { + #[allow(clippy::let_unit_value)] + let marshalled_args = ( + $( + <$Pn as sys::GodotFuncMarshal>::try_into_via(args.$n).unwrap(), + )* + ); + + let type_ptrs = [ + $( + sys::GodotFfi::as_arg_ptr(&marshalled_args.$n), + )* + ]; + + Rr::call(|return_ptr| { + builtin_fn(type_ptr, type_ptrs.as_ptr(), return_ptr, type_ptrs.len() as i32); + }) + } + + #[inline] + unsafe fn out_utility_ptrcall( + utility_fn: UtilityFunctionBind, + args: Self::Params, + ) -> Self::Ret { + #[allow(clippy::let_unit_value)] + let marshalled_args = ( + $( + <$Pn as sys::GodotFuncMarshal>::try_into_via(args.$n).unwrap(), + )* + ); + + let arg_ptrs = [ + $( + sys::GodotFfi::as_arg_ptr(&marshalled_args.$n), + )* + ]; + + PtrcallReturnT::<$R>::call(|return_ptr| { + utility_fn(return_ptr, arg_ptrs.as_ptr(), arg_ptrs.len() as i32); + }) + } } }; } @@ -231,25 +412,86 @@ fn return_error(method_name: &str, arg: &impl Debug) -> ! { panic!("{method_name}: return type {return_ty} is unable to store value {arg:?}",); } -impl_varcall_signature_for_tuple!(0, R); +fn check_varcall_error( + err: &sys::GDExtensionCallError, + fn_name: &str, + explicit_args: &[T], + varargs: &[Variant], +) where + T: Debug + ToVariant, +{ + if err.error == sys::GDEXTENSION_CALL_OK { + return; + } + + // TODO(optimize): split into non-generic, expensive parts after error check + + let mut arg_types = Vec::with_capacity(explicit_args.len() + varargs.len()); + arg_types.extend(explicit_args.iter().map(|arg| arg.to_variant().get_type())); + arg_types.extend(varargs.iter().map(Variant::get_type)); + + let explicit_args_str = join_to_string(explicit_args); + let vararg_str = join_to_string(varargs); + + let func_str = format!("{fn_name}({explicit_args_str}; varargs {vararg_str})"); + + sys::panic_call_error(err, &func_str, &arg_types); +} + +fn join_to_string(list: &[T]) -> String { + list.iter() + .map(|v| format!("{v:?}")) + .collect::>() + .join(", ") +} + +/// Helper trait to support `()` which doesn't implement `FromVariant`. +trait FromVariantIndirect { + fn convert(variant: Variant) -> Self; +} + +impl FromVariantIndirect for () { + fn convert(_variant: Variant) -> Self {} +} + +impl FromVariantIndirect for T { + fn convert(variant: Variant) -> Self { + T::from_variant(&variant) + } +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- +// Poor man's variadic templates. +// For example, RenderingServer::environment_set_volumetric_fog() has 14 parameters. We may need to extend this if the API adds more such methods. + +impl_varcall_signature_for_tuple!(0; R); +impl_varcall_signature_for_tuple!(1; R, P0: 0); +impl_varcall_signature_for_tuple!(2; R, P0: 0, P1: 1); +impl_varcall_signature_for_tuple!(3; R, P0: 0, P1: 1, P2: 2); +impl_varcall_signature_for_tuple!(4; R, P0: 0, P1: 1, P2: 2, P3: 3); +impl_varcall_signature_for_tuple!(5; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4); +impl_varcall_signature_for_tuple!(6; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5); +impl_varcall_signature_for_tuple!(7; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6); +impl_varcall_signature_for_tuple!(8; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7); +impl_varcall_signature_for_tuple!(9; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8); +impl_varcall_signature_for_tuple!(10; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9); +impl_varcall_signature_for_tuple!(11; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10); +impl_varcall_signature_for_tuple!(12; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10, P11: 11); +impl_varcall_signature_for_tuple!(13; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10, P11: 11, P12: 12); +impl_varcall_signature_for_tuple!(14; R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10, P11: 11, P12: 12, P13: 13); + impl_ptrcall_signature_for_tuple!(R); -impl_varcall_signature_for_tuple!(1, R, P0: 0); impl_ptrcall_signature_for_tuple!(R, P0: 0); -impl_varcall_signature_for_tuple!(2, R, P0: 0, P1: 1); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1); -impl_varcall_signature_for_tuple!(3, R, P0: 0, P1: 1, P2: 2); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2); -impl_varcall_signature_for_tuple!(4, R, P0: 0, P1: 1, P2: 2, P3: 3); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3); -impl_varcall_signature_for_tuple!(5, R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4); -impl_varcall_signature_for_tuple!(6, R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5); -impl_varcall_signature_for_tuple!(7, R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6); -impl_varcall_signature_for_tuple!(8, R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7); -impl_varcall_signature_for_tuple!(9, R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8); -impl_varcall_signature_for_tuple!(10, R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9); impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9); +impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10); +impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10, P11: 11); +impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10, P11: 11, P12: 12); +impl_ptrcall_signature_for_tuple!(R, P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5, P6: 6, P7: 7, P8: 8, P9: 9, P10: 10, P11: 11, P12: 12, P13: 13); diff --git a/godot-core/src/lib.rs b/godot-core/src/lib.rs index 424187e3f..e9c21c753 100644 --- a/godot-core/src/lib.rs +++ b/godot-core/src/lib.rs @@ -36,6 +36,7 @@ pub mod engine; #[rustfmt::skip] #[allow(unused_imports, dead_code, non_upper_case_globals, non_snake_case)] #[allow(clippy::too_many_arguments, clippy::let_and_return, clippy::new_ret_no_self)] +#[allow(clippy::let_unit_value)] // let args = (); #[allow(clippy::wrong_self_convention)] // to_string() is const #[allow(clippy::upper_case_acronyms)] // TODO remove this line once we transform names #[allow(unreachable_code, clippy::unimplemented)] // TODO remove once #153 is implemented diff --git a/godot-ffi/src/gdextension_plus.rs b/godot-ffi/src/gdextension_plus.rs index ba48fc355..3e54c9ea6 100644 --- a/godot-ffi/src/gdextension_plus.rs +++ b/godot-ffi/src/gdextension_plus.rs @@ -73,8 +73,11 @@ pub fn default_call_error() -> GDExtensionCallError { pub fn panic_call_error( err: &GDExtensionCallError, function_name: &str, - arg_types: &[VariantType], + vararg_types: &[VariantType], ) -> ! { + // This specializes on reflection-style calls, e.g. call(), rpc() etc. + // In these cases, varargs are the _actual_ arguments, with required args being metadata such as method name. + debug_assert_ne!(err.error, GDEXTENSION_CALL_OK); // already checked outside let GDExtensionCallError { @@ -83,11 +86,11 @@ pub fn panic_call_error( expected, } = *err; - let argc = arg_types.len(); + let argc = vararg_types.len(); let reason = match error { GDEXTENSION_CALL_ERROR_INVALID_METHOD => "method not found".to_string(), GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT => { - let from = arg_types[argument as usize]; + let from = vararg_types[argument as usize]; let to = VariantType::from_sys(expected as GDExtensionVariantType); let i = argument + 1; diff --git a/godot-ffi/src/godot_ffi.rs b/godot-ffi/src/godot_ffi.rs index e89071708..6989c9d66 100644 --- a/godot-ffi/src/godot_ffi.rs +++ b/godot-ffi/src/godot_ffi.rs @@ -5,8 +5,9 @@ */ use crate as sys; -use std::{error::Error, fmt::Debug, marker::PhantomData, ptr}; -use sys::ptr_then; +use std::error::Error; +use std::marker::PhantomData; +use std::ptr; /// Adds methods to convert from and to Godot FFI pointers. /// See [crate::ffi_methods] for ergonomic implementation. @@ -147,7 +148,7 @@ where T: GodotNullablePtr, { unsafe fn from_sys(ptr: sys::GDExtensionTypePtr) -> Self { - ptr_then(ptr, |ptr| T::from_sys(ptr)) + crate::ptr_then(ptr, |ptr| T::from_sys(ptr)) } unsafe fn from_sys_init(init_fn: impl FnOnce(sys::GDExtensionUninitializedTypePtr)) -> Self { diff --git a/godot-ffi/src/toolbox.rs b/godot-ffi/src/toolbox.rs index 6c9fa1d57..9f657e7f1 100644 --- a/godot-ffi/src/toolbox.rs +++ b/godot-ffi/src/toolbox.rs @@ -166,7 +166,7 @@ pub(crate) type GetClassMethod = unsafe extern "C" fn( p_hash: sys::GDExtensionInt, ) -> sys::GDExtensionMethodBindPtr; -pub(crate) type ClassMethodBind = sys::GDExtensionMethodBindPtr; +pub type ClassMethodBind = sys::GDExtensionMethodBindPtr; pub(crate) type GetBuiltinMethod = unsafe extern "C" fn( p_type: sys::GDExtensionVariantType, @@ -175,7 +175,7 @@ pub(crate) type GetBuiltinMethod = unsafe extern "C" fn( ) -> sys::GDExtensionPtrBuiltInMethod; // GDExtensionPtrBuiltInMethod -pub(crate) type BuiltinMethodBind = unsafe extern "C" fn( +pub type BuiltinMethodBind = unsafe extern "C" fn( p_base: sys::GDExtensionTypePtr, p_args: *const sys::GDExtensionConstTypePtr, r_return: sys::GDExtensionTypePtr, @@ -187,7 +187,7 @@ pub(crate) type GetUtilityFunction = unsafe extern "C" fn( p_hash: sys::GDExtensionInt, ) -> sys::GDExtensionPtrUtilityFunction; -pub(crate) type UtilityFunctionBind = unsafe extern "C" fn( +pub type UtilityFunctionBind = unsafe extern "C" fn( r_return: sys::GDExtensionTypePtr, p_args: *const sys::GDExtensionConstTypePtr, p_argument_count: std::os::raw::c_int, diff --git a/godot-macros/src/class/data_models/func.rs b/godot-macros/src/class/data_models/func.rs index 2ef43f246..cbc4f8e1a 100644 --- a/godot-macros/src/class/data_models/func.rs +++ b/godot-macros/src/class/data_models/func.rs @@ -322,7 +322,7 @@ fn make_ptrcall_invocation( }; quote! { - <#sig_tuple as ::godot::builtin::meta::PtrcallSignatureTuple>::ptrcall( + <#sig_tuple as ::godot::builtin::meta::PtrcallSignatureTuple>::in_ptrcall( instance_ptr, args_ptr, ret, @@ -342,7 +342,7 @@ fn make_varcall_invocation( let method_name_str = method_name.to_string(); quote! { - <#sig_tuple as ::godot::builtin::meta::VarcallSignatureTuple>::varcall( + <#sig_tuple as ::godot::builtin::meta::VarcallSignatureTuple>::in_varcall( instance_ptr, args_ptr, ret,