@@ -16,8 +16,9 @@ use sys::{ffi_methods, interface_fn, static_assert_eq_size, GodotFfi, PtrcallTyp
16
16
17
17
use crate :: builtin:: meta:: { ClassName , VariantMetadata } ;
18
18
use crate :: builtin:: {
19
- Callable , FromVariant , StringName , ToVariant , Variant , VariantConversionError ,
19
+ Callable , FromVariant , GodotString , StringName , ToVariant , Variant , VariantConversionError ,
20
20
} ;
21
+ use crate :: engine:: Object ;
21
22
use crate :: obj:: dom:: Domain as _;
22
23
use crate :: obj:: mem:: Memory as _;
23
24
use crate :: obj:: { cap, dom, mem, Export , GodotClass , Inherits , Share } ;
@@ -326,11 +327,31 @@ impl<T: GodotClass> Gd<T> {
326
327
} )
327
328
}
328
329
330
+ // Temporary workaround for bug in Godot that makes casts always succeed.
331
+ // (See https://github.com/godot-rust/gdext/issues/158)
332
+ // TODO(#234) remove this code once the bug is fixed upstream.
333
+ fn is_cast_valid < U > ( & self ) -> bool
334
+ where
335
+ U : GodotClass ,
336
+ {
337
+ let as_obj = unsafe { self . ffi_cast :: < Object > ( ) } . expect ( "Everything inherits object" ) ;
338
+ let cast_is_valid = as_obj. is_class ( GodotString :: from ( U :: CLASS_NAME ) ) ;
339
+ std:: mem:: forget ( as_obj) ;
340
+ cast_is_valid
341
+ }
342
+
329
343
/// Returns `Ok(cast_obj)` on success, `Err(self)` on error
330
344
fn owned_cast < U > ( self ) -> Result < Gd < U > , Self >
331
345
where
332
346
U : GodotClass ,
333
347
{
348
+ // Temporary workaround for bug in Godot that makes casts always
349
+ // succeed. (See https://github.com/godot-rust/gdext/issues/158)
350
+ // TODO(#234) remove this check once the bug is fixed upstream.
351
+ if !self . is_cast_valid :: < U > ( ) {
352
+ return Err ( self ) ;
353
+ }
354
+
334
355
// The unsafe { std::mem::transmute<&T, &Base>(self.inner()) } relies on the C++ static_cast class casts
335
356
// to return the same pointer, however in theory those may yield a different pointer (VTable offset,
336
357
// virtual inheritance etc.). It *seems* to work so far, but this is no indication it's not UB.
@@ -643,7 +664,10 @@ impl<T: GodotClass> Export for Gd<T> {
643
664
impl < T : GodotClass > FromVariant for Gd < T > {
644
665
fn try_from_variant ( variant : & Variant ) -> Result < Self , VariantConversionError > {
645
666
let result_or_none = unsafe {
646
- Self :: from_sys_init_opt ( |self_ptr| {
667
+ // TODO(#234) replace Gd::<Object> with Self when Godot stops allowing
668
+ // illegal conversions (See
669
+ // https://github.com/godot-rust/gdext/issues/158)
670
+ Gd :: < Object > :: from_sys_init_opt ( |self_ptr| {
647
671
let converter = sys:: builtin_fn!( object_from_variant) ;
648
672
converter ( self_ptr, variant. var_sys ( ) ) ;
649
673
} )
@@ -653,6 +677,9 @@ impl<T: GodotClass> FromVariant for Gd<T> {
653
677
// (This behaves differently in the opposite direction `object_to_variant`.)
654
678
result_or_none
655
679
. map ( |obj| obj. with_inc_refcount ( ) )
680
+ // TODO(#234) remove this cast when Godot stops allowing illegal conversions
681
+ // (See https://github.com/godot-rust/gdext/issues/158)
682
+ . and_then ( |obj| obj. owned_cast ( ) . ok ( ) )
656
683
. ok_or ( VariantConversionError )
657
684
}
658
685
}
0 commit comments