diff --git a/gdnative-core/src/export/macros.rs b/gdnative-core/src/export/macros.rs index 92b3bea..5fc1708 100644 --- a/gdnative-core/src/export/macros.rs +++ b/gdnative-core/src/export/macros.rs @@ -11,11 +11,23 @@ macro_rules! godot_wrap_method_parameter_count { } } +#[doc(hidden)] +#[macro_export] +macro_rules! godot_wrap_method_if_deref { + (true, $ret:expr) => { + std::ops::Deref::deref(&$ret) + }; + (false, $ret:expr) => { + $ret + }; +} + #[doc(hidden)] #[macro_export] macro_rules! godot_wrap_method_inner { ( $type_name:ty, + $is_deref_return:ident, $map_method:ident, fn $method_name:ident( $self:ident, @@ -56,7 +68,9 @@ macro_rules! godot_wrap_method_inner { $($pname,)* $($opt_pname,)* ); - gdnative::core_types::OwnedToVariant::owned_to_variant(ret) + gdnative::core_types::OwnedToVariant::owned_to_variant( + $crate::godot_wrap_method_if_deref!($is_deref_return, ret) + ) } }) .unwrap_or_else(|err| { @@ -83,6 +97,7 @@ macro_rules! godot_wrap_method { // mutable ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( &mut $self:ident, $owner:ident : $owner_ty:ty @@ -93,6 +108,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method_inner!( $type_name, + $is_deref_return, map_mut, fn $method_name( $self, @@ -105,6 +121,7 @@ macro_rules! godot_wrap_method { // immutable ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( & $self:ident, $owner:ident : $owner_ty:ty @@ -115,6 +132,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method_inner!( $type_name, + $is_deref_return, map, fn $method_name( $self, @@ -127,6 +145,7 @@ macro_rules! godot_wrap_method { // owned ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( mut $self:ident, $owner:ident : $owner_ty:ty @@ -137,6 +156,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method_inner!( $type_name, + $is_deref_return, map_owned, fn $method_name( $self, @@ -149,6 +169,7 @@ macro_rules! godot_wrap_method { // owned ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( $self:ident, $owner:ident : $owner_ty:ty @@ -159,6 +180,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method_inner!( $type_name, + $is_deref_return, map_owned, fn $method_name( $self, @@ -171,6 +193,7 @@ macro_rules! godot_wrap_method { // mutable without return type ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( &mut $self:ident, $owner:ident : $owner_ty:ty @@ -181,6 +204,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method!( $type_name, + $is_deref_return, fn $method_name( &mut $self, $owner: $owner_ty @@ -192,6 +216,7 @@ macro_rules! godot_wrap_method { // immutable without return type ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( & $self:ident, $owner:ident : $owner_ty:ty @@ -202,6 +227,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method!( $type_name, + $is_deref_return, fn $method_name( & $self, $owner: $owner_ty @@ -213,6 +239,7 @@ macro_rules! godot_wrap_method { // owned without return type ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( mut $self:ident, $owner:ident : $owner_ty:ty @@ -223,6 +250,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method!( $type_name, + $is_deref_return, fn $method_name( $self, $owner: $owner_ty @@ -234,6 +262,7 @@ macro_rules! godot_wrap_method { // owned without return type ( $type_name:ty, + $is_deref_return:ident, fn $method_name:ident( $self:ident, $owner:ident : $owner_ty:ty @@ -244,6 +273,7 @@ macro_rules! godot_wrap_method { ) => { $crate::godot_wrap_method!( $type_name, + $is_deref_return, fn $method_name( $self, $owner: $owner_ty diff --git a/gdnative-derive/src/methods.rs b/gdnative-derive/src/methods.rs index bcc4a10..c4d264c 100644 --- a/gdnative-derive/src/methods.rs +++ b/gdnative-derive/src/methods.rs @@ -66,6 +66,7 @@ pub(crate) struct ExportArgs { pub(crate) optional_args: Option, pub(crate) rpc_mode: RpcMode, pub(crate) name_override: Option, + pub(crate) is_deref_return: bool, } pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 { @@ -116,6 +117,7 @@ pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 { }; let rpc = args.rpc_mode; + let is_deref_return = args.is_deref_return; let args = sig.inputs.iter().enumerate().map(|(n, arg)| { let span = arg.span(); @@ -130,6 +132,7 @@ pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 { { let method = ::gdnative::export::godot_wrap_method!( #class_name, + #is_deref_return, fn #name ( #( #args )* ) -> #ret_ty ); @@ -183,6 +186,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) { let mut export_args = None; let mut rpc = None; let mut name_override = None; + let mut is_deref_return = false; let mut errors = vec![]; @@ -292,6 +296,20 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) { )); } } + } else if path.is_ident("deref_return") { + // deref return value + if lit.is_some() { + errors.push(syn::Error::new( + nested_meta.span(), + "value for deref_return parameter is not valid", + )); + } else if is_deref_return { + errors.push(syn::Error::new( + nested_meta.span(), + "deref_return was apply more than once", + )); + } else { + is_deref_return = true; } } else { let msg = format!( @@ -350,6 +368,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) { export_args.optional_args = optional_args; export_args.rpc_mode = rpc.unwrap_or(RpcMode::Disabled); export_args.name_override = name_override; + export_args.is_deref_return = is_deref_return; methods_to_export.push(ExportMethod { sig: method.sig.clone(),