Skip to content

Commit f1d2817

Browse files
committed
Re-enable Variant conversions for ObjectArg; extract code shared with RawGd
1 parent 84505ba commit f1d2817

File tree

2 files changed

+57
-49
lines changed

2 files changed

+57
-49
lines changed

godot-core/src/obj/object_arg.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use crate::builtin::Variant;
99
use crate::meta::error::ConvertError;
1010
use crate::meta::{ClassName, FromGodot, GodotConvert, GodotFfiVariant, GodotType, ToGodot};
11-
use crate::obj::{bounds, Bounds, Gd, GodotClass, Inherits, RawGd};
11+
use crate::obj::{bounds, raw_gd, Bounds, Gd, GodotClass, Inherits, RawGd};
1212
use crate::sys;
1313
use godot_ffi::{GodotFfi, GodotNullableFfi, PtrcallType};
1414
use std::ptr;
@@ -172,16 +172,7 @@ where
172172
// https://github.com/godotengine/godot-cpp/issues/954
173173

174174
fn as_arg_ptr(&self) -> sys::GDExtensionConstTypePtr {
175-
// See RawGd::as_arg_ptr().
176-
#[cfg(before_api = "4.1")]
177-
{
178-
self.sys()
179-
}
180-
181-
#[cfg(since_api = "4.1")]
182-
{
183-
ptr::addr_of!(self.object_ptr) as sys::GDExtensionConstTypePtr
184-
}
175+
raw_gd::object_as_arg_ptr(self, &self.object_ptr)
185176
}
186177

187178
unsafe fn from_arg_ptr(_ptr: sys::GDExtensionTypePtr, _call_type: PtrcallType) -> Self {
@@ -240,7 +231,8 @@ impl<T: GodotClass> GodotType for ObjectArg<T> {
240231

241232
impl<T: GodotClass> GodotFfiVariant for ObjectArg<T> {
242233
fn ffi_to_variant(&self) -> Variant {
243-
unreachable!("ObjectArg::ffi_to_variant() is not expected to be called.")
234+
// Note: currently likely not invoked since there are no known varcall APIs taking Object parameters; however this might change.
235+
raw_gd::object_ffi_to_variant(self)
244236
}
245237

246238
fn ffi_from_variant(_variant: &Variant) -> Result<Self, ConvertError> {

godot-core/src/obj/raw_gd.rs

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -480,27 +480,9 @@ where
480480
// https://github.com/godotengine/godot-cpp/issues/954
481481

482482
fn as_arg_ptr(&self) -> sys::GDExtensionConstTypePtr {
483-
// Do not extract this code. Address of field pointer matters, copying it into a local variable will create use-after-free.
483+
// Even though ObjectArg exists, this function is still relevant, e.g. in Callable.
484484

485-
// No need to call self.check_rtti("as_arg_ptr") here, since this is already done in ToGodot impl.
486-
487-
// We pass an object to a Godot API. If the reference count needs to be incremented, then the callee (Godot C++ function) will do so.
488-
// We do not need to prematurely do so. In Rust terms, if `T` is ref-counted, then we are effectively passing a `&Arc<T>`, and the
489-
// callee would need to invoke `.clone()` if desired.
490-
491-
// In 4.0, argument pointers are passed to godot as `T*`, except for in virtual method calls. We can't perform virtual method calls
492-
// currently, so they are always `T*`.
493-
//
494-
// In 4.1, argument pointers were standardized to always be `T**`.
495-
#[cfg(before_api = "4.1")]
496-
{
497-
self.sys()
498-
}
499-
500-
#[cfg(since_api = "4.1")]
501-
{
502-
ptr::addr_of!(self.obj) as sys::GDExtensionConstTypePtr
503-
}
485+
object_as_arg_ptr(self, &self.obj)
504486
}
505487

506488
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, call_type: PtrcallType) -> Self {
@@ -581,23 +563,7 @@ impl<T: GodotClass> GodotType for RawGd<T> {
581563

582564
impl<T: GodotClass> GodotFfiVariant for RawGd<T> {
583565
fn ffi_to_variant(&self) -> Variant {
584-
// The conversion method `object_to_variant` DOES increment the reference-count of the object; so nothing to do here.
585-
// (This behaves differently in the opposite direction `variant_to_object`.)
586-
587-
unsafe {
588-
Variant::new_with_var_uninit(|variant_ptr| {
589-
let converter = sys::builtin_fn!(object_to_variant);
590-
591-
// Note: this is a special case because of an inconsistency in Godot, where sometimes the equivalency is
592-
// GDExtensionTypePtr == Object** and sometimes GDExtensionTypePtr == Object*. Here, it is the former, thus extra pointer.
593-
// Reported at https://github.com/godotengine/godot/issues/61967
594-
let type_ptr = self.sys();
595-
converter(
596-
variant_ptr,
597-
ptr::addr_of!(type_ptr) as sys::GDExtensionTypePtr,
598-
);
599-
})
600-
}
566+
object_ffi_to_variant(self)
601567
}
602568

603569
fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
@@ -681,6 +647,9 @@ impl<T: GodotClass> fmt::Debug for RawGd<T> {
681647
}
682648
}
683649

650+
// ----------------------------------------------------------------------------------------------------------------------------------------------
651+
// Reusable functions, also shared with Gd, Variant, ObjectArg.
652+
684653
/// Runs `init_fn` on the address of a pointer (initialized to null), then returns that pointer, possibly still null.
685654
///
686655
/// # Safety
@@ -699,3 +668,50 @@ pub unsafe fn raw_object_init(
699668
// We don't need to know if Object** is null, but if Object* is null; return_ptr has the address of a local (never null).
700669
object_ptr
701670
}
671+
672+
pub(super) fn object_ffi_to_variant<T: GodotFfi>(self_: &T) -> Variant {
673+
// The conversion method `object_to_variant` DOES increment the reference-count of the object; so nothing to do here.
674+
// (This behaves differently in the opposite direction `variant_to_object`.)
675+
676+
unsafe {
677+
Variant::new_with_var_uninit(|variant_ptr| {
678+
let converter = sys::builtin_fn!(object_to_variant);
679+
680+
// Note: this is a special case because of an inconsistency in Godot, where sometimes the equivalency is
681+
// GDExtensionTypePtr == Object** and sometimes GDExtensionTypePtr == Object*. Here, it is the former, thus extra pointer.
682+
// Reported at https://github.com/godotengine/godot/issues/61967
683+
let type_ptr = self_.sys();
684+
converter(
685+
variant_ptr,
686+
ptr::addr_of!(type_ptr) as sys::GDExtensionTypePtr,
687+
);
688+
})
689+
}
690+
}
691+
692+
pub(super) fn object_as_arg_ptr<T: GodotFfi, F>(
693+
_self: &T,
694+
_object_ptr_field: &*mut F,
695+
) -> sys::GDExtensionConstTypePtr {
696+
// Be careful when refactoring this code. Address of field pointer matters, copying it into a local variable will create use-after-free.
697+
698+
// No need to call self.check_rtti("as_arg_ptr") here, since this is already done in ToGodot impl.
699+
700+
// We pass an object to a Godot API. If the reference count needs to be incremented, then the callee (Godot C++ function) will do so.
701+
// We do not need to prematurely do so. In Rust terms, if `T` is ref-counted, then we are effectively passing a `&Arc<T>`, and the
702+
// callee would need to invoke `.clone()` if desired.
703+
704+
// In 4.0, argument pointers are passed to godot as `T*`, except for in virtual method calls. We can't perform virtual method calls
705+
// currently, so they are always `T*`.
706+
//
707+
// In 4.1, argument pointers were standardized to always be `T**`.
708+
#[cfg(before_api = "4.1")]
709+
{
710+
_self.sys()
711+
}
712+
713+
#[cfg(since_api = "4.1")]
714+
{
715+
ptr::addr_of!(*_object_ptr_field) as sys::GDExtensionConstTypePtr
716+
}
717+
}

0 commit comments

Comments
 (0)