Skip to content

Commit 9a0d8ba

Browse files
committed
Add test + doc for Signal/Callable::object_id() on dead objects
1 parent 7a3ff27 commit 9a0d8ba

File tree

4 files changed

+26
-9
lines changed

4 files changed

+26
-9
lines changed

godot-core/src/builtin/callable.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,8 @@ impl Callable {
205205

206206
/// Returns the object on which this callable is called.
207207
///
208-
/// Returns `None` when this callable doesn't have any target object to call a method on, regardless of
209-
/// if the method exists for that target or not.
208+
/// Returns `None` when this callable doesn't have any target object to call a method on (regardless of whether the method exists for that
209+
/// target or not). Also returns `None` if the object is dead. You can differentiate these two cases using [`object_id()`][Self::object_id].
210210
///
211211
/// _Godot equivalent: `get_object`_
212212
pub fn object(&self) -> Option<Gd<Object>> {
@@ -222,6 +222,8 @@ impl Callable {
222222
///
223223
/// Returns `None` when this callable doesn't have any target to call a method on.
224224
///
225+
/// If the pointed-to object is dead, the ID will still be returned. Use [`object()`][Self::object] to check for liveness.
226+
///
225227
/// _Godot equivalent: `get_object_id`_
226228
pub fn object_id(&self) -> Option<InstanceId> {
227229
let id = self.as_inner().get_object_id();

godot-core/src/builtin/signal.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ impl Signal {
121121

122122
/// Returns the object to which this signal belongs.
123123
///
124-
/// Returns [`None`] when this signal doesn't have any object.
124+
/// Returns [`None`] when this signal doesn't have any object, or the object is dead. You can differentiate these two situations using
125+
/// [`object_id()`][Self::object_id].
125126
///
126127
/// _Godot equivalent: `get_object`_
127128
pub fn object(&self) -> Option<Gd<Object>> {
@@ -135,6 +136,8 @@ impl Signal {
135136
///
136137
/// Returns [`None`] when this signal doesn't have any object.
137138
///
139+
/// If the pointed-to object is dead, the ID will still be returned. Use [`object()`][Self::object] to check for liveness.
140+
///
138141
/// _Godot equivalent: `get_object_id`_
139142
pub fn object_id(&self) -> Option<InstanceId> {
140143
let id = self.as_inner().get_object_id();

itest/rust/src/builtin_tests/containers/callable_test.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,19 @@ fn callable_hash() {
6767

6868
#[itest]
6969
fn callable_object_method() {
70-
let obj = CallableTestObj::new_gd();
71-
let callable = obj.callable("foo");
70+
let object = CallableTestObj::new_gd();
71+
let object_id = object.instance_id();
72+
let callable = object.callable("foo");
7273

73-
assert_eq!(callable.object(), Some(obj.clone().upcast::<Object>()));
74-
assert_eq!(callable.object_id(), Some(obj.instance_id()));
74+
assert_eq!(callable.object(), Some(object.clone().upcast::<Object>()));
75+
assert_eq!(callable.object_id(), Some(object_id));
7576
assert_eq!(callable.method_name(), Some("foo".into()));
7677

78+
// Invalidating the object still returns the old ID, however not the object.
79+
drop(object);
80+
assert_eq!(callable.object_id(), Some(object_id));
81+
assert_eq!(callable.object(), None);
82+
7783
assert_eq!(Callable::invalid().object(), None);
7884
assert_eq!(Callable::invalid().object_id(), None);
7985
assert_eq!(Callable::invalid().method_name(), None);

itest/rust/src/builtin_tests/containers/signal_test.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,21 @@ fn signals() {
9595
#[itest]
9696
fn instantiate_signal() {
9797
let mut object = RefCounted::new_gd();
98+
let object_id = object.instance_id();
9899

99100
object.add_user_signal("test_signal".into());
100101

101102
let signal = Signal::from_object_signal(&object, "test_signal");
102103

103104
assert!(!signal.is_null());
104105
assert_eq!(signal.name(), StringName::from("test_signal"));
105-
assert_eq!(signal.object().unwrap(), object.clone().upcast());
106-
assert_eq!(signal.object_id().unwrap(), object.instance_id());
106+
assert_eq!(signal.object(), Some(object.clone().upcast()));
107+
assert_eq!(signal.object_id(), Some(object_id));
108+
109+
// Invalidating the object still returns the old ID, however not the object.
110+
drop(object);
111+
assert_eq!(signal.object_id(), Some(object_id));
112+
assert_eq!(signal.object(), None);
107113
}
108114

109115
#[itest]

0 commit comments

Comments
 (0)