Skip to content

Commit 641664b

Browse files
committed
Impl Debug for RawGd<T> doesn't instantiate a new Gd<T>
Avoids side effects on Gd creation + needless delegation to RawGd.
1 parent 8268cff commit 641664b

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

godot-core/src/classes/class_runtime.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::classes::{ClassDb, Object};
1313
use crate::meta::CallContext;
1414
#[cfg(debug_assertions)]
1515
use crate::meta::ClassName;
16-
use crate::obj::{bounds, Bounds, Gd, GodotClass, InstanceId};
16+
use crate::obj::{bounds, Bounds, Gd, GodotClass, InstanceId, RawGd};
1717
use crate::sys;
1818

1919
pub(crate) fn debug_string<T: GodotClass>(
@@ -23,12 +23,32 @@ pub(crate) fn debug_string<T: GodotClass>(
2323
) -> std::fmt::Result {
2424
if let Some(id) = obj.instance_id_or_none() {
2525
let class: StringName = obj.dynamic_class_string();
26-
write!(f, "{ty} {{ id: {id}, class: {class} }}")
26+
f.debug_struct(ty)
27+
.field("id", &id)
28+
.field("class", &class)
29+
.finish()
2730
} else {
2831
write!(f, "{ty} {{ freed obj }}")
2932
}
3033
}
3134

35+
pub(crate) fn debug_string_nullable<T: GodotClass>(
36+
obj: &RawGd<T>,
37+
f: &mut std::fmt::Formatter<'_>,
38+
ty: &str,
39+
) -> std::fmt::Result {
40+
if obj.is_null() {
41+
write!(f, "{ty} {{ null }}")
42+
} else {
43+
// Unsafety introduced here to avoid creating a new Gd<T> (which can have all sorts of side effects, logs, refcounts etc.)
44+
// *and* pushing down all high-level Gd<T> functions to RawGd<T> as pure delegates.
45+
46+
// SAFETY: layout of Gd<T> is currently equivalent to RawGd<T>.
47+
let obj: &Gd<T> = unsafe { std::mem::transmute::<&RawGd<T>, &Gd<T>>(obj) };
48+
debug_string(obj, f, ty)
49+
}
50+
}
51+
3252
pub(crate) fn debug_string_with_trait<T: GodotClass>(
3353
obj: &Gd<T>,
3454
f: &mut std::fmt::Formatter<'_>,
@@ -37,7 +57,11 @@ pub(crate) fn debug_string_with_trait<T: GodotClass>(
3757
) -> std::fmt::Result {
3858
if let Some(id) = obj.instance_id_or_none() {
3959
let class: StringName = obj.dynamic_class_string();
40-
write!(f, "{ty} {{ id: {id}, class: {class}, trait: {trt} }}")
60+
f.debug_struct(ty)
61+
.field("id", &id)
62+
.field("class", &class)
63+
.field("trait", &trt)
64+
.finish()
4165
} else {
4266
write!(f, "{ty} {{ freed obj }}")
4367
}
@@ -83,7 +107,7 @@ pub(crate) fn ensure_object_alive(
83107
// namely in PR https://github.com/godotengine/godot/pull/36189. Double-check to make sure.
84108
assert_eq!(
85109
new_object_ptr, old_object_ptr,
86-
"{call_ctx}: instance ID {instance_id} points to a stale, reused object. Please report this to gdext maintainers."
110+
"{call_ctx}: instance ID {instance_id} points to a stale, reused object. Please report this to godot-rust maintainers."
87111
);
88112
}
89113

godot-core/src/obj/raw_gd.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ impl<T: GodotClass> RawGd<T> {
9595

9696
/// Returns `true` if the object is null.
9797
///
98-
/// This does not check if the object is dead, for that use
99-
/// [`instance_id_or_none()`](Self::instance_id_or_none).
98+
/// This does not check if the object is dead. For that, use [`is_instance_valid()`](Self::is_instance_valid).
10099
pub(crate) fn is_null(&self) -> bool {
101100
self.obj.is_null() || self.cached_rtti.is_none()
102101
}
@@ -689,12 +688,7 @@ impl<T: GodotClass> Clone for RawGd<T> {
689688

690689
impl<T: GodotClass> fmt::Debug for RawGd<T> {
691690
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692-
if self.is_null() {
693-
return write!(f, "{} {{ null obj }}", std::any::type_name::<T>());
694-
}
695-
696-
let gd = super::Gd::from_ffi(self.clone());
697-
write!(f, "{gd:?}")
691+
classes::debug_string_nullable(self, f, "RawGd")
698692
}
699693
}
700694

0 commit comments

Comments
 (0)