Skip to content

Commit 50ea49b

Browse files
toasteaterBromeon
andcommitted
Add wrapper for from_instance_id
Co-authored-by: Jan Haller <[email protected]>
1 parent 9da09b1 commit 50ea49b

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

gdnative-core/src/object.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,36 @@ pub unsafe trait GodotObject: Sized + crate::private::godot_object::Sealed {
151151
{
152152
Ref::from_sys(self.as_raw().sys())
153153
}
154+
155+
/// Recovers a instance ID previously returned by `Object::get_instance_id` if the object is
156+
/// still alive. See also `TRef::try_from_instance_id`.
157+
///
158+
/// # Safety
159+
///
160+
/// During the entirety of `'a`, the thread from which `try_from_instance_id` is called must
161+
/// have exclusive access to the underlying object, if it is still alive.
162+
#[inline]
163+
unsafe fn try_from_instance_id<'a>(id: i64) -> Option<TRef<'a, Self, Shared>> {
164+
TRef::try_from_instance_id(id)
165+
}
166+
167+
/// Recovers a instance ID previously returned by `Object::get_instance_id` if the object is
168+
/// still alive, and panics otherwise. This does **NOT** guarantee that the resulting
169+
/// reference is safe to use.
170+
///
171+
/// # Panics
172+
///
173+
/// Panics if the given id refers to a destroyed object. For a non-panicking version, see
174+
/// `try_from_instance_id`.
175+
///
176+
/// # Safety
177+
///
178+
/// During the entirety of `'a`, the thread from which `try_from_instance_id` is called must
179+
/// have exclusive access to the underlying object, if it is still alive.
180+
#[inline]
181+
unsafe fn from_instance_id<'a>(id: i64) -> TRef<'a, Self, Shared> {
182+
TRef::from_instance_id(id)
183+
}
154184
}
155185

156186
/// Marker trait for API types that are subclasses of another type. This trait is implemented
@@ -892,6 +922,41 @@ where
892922
}
893923
}
894924

925+
impl<'a, T: GodotObject> TRef<'a, T, Shared> {
926+
/// Recovers a instance ID previously returned by `Object::get_instance_id` if the object is
927+
/// still alive.
928+
///
929+
/// # Safety
930+
///
931+
/// During the entirety of `'a`, the thread from which `try_from_instance_id` is called must
932+
/// have exclusive access to the underlying object, if it is still alive.
933+
#[inline]
934+
pub unsafe fn try_from_instance_id(id: i64) -> Option<Self> {
935+
let api = get_api();
936+
let ptr = NonNull::new((api.godot_instance_from_id)(id as sys::godot_int))?;
937+
let raw = RawObject::try_from_sys_ref(ptr)?;
938+
Some(TRef::new(T::cast_ref(raw)))
939+
}
940+
941+
/// Recovers a instance ID previously returned by `Object::get_instance_id` if the object is
942+
/// still alive, and panics otherwise. This does **NOT** guarantee that the resulting
943+
/// reference is safe to use.
944+
///
945+
/// # Panics
946+
///
947+
/// Panics if the given id refers to a destroyed object. For a non-panicking version, see
948+
/// `try_from_instance_id`.
949+
///
950+
/// # Safety
951+
///
952+
/// During the entirety of `'a`, the thread from which `try_from_instance_id` is called must
953+
/// have exclusive access to the underlying object, if it is still alive.
954+
#[inline]
955+
pub unsafe fn from_instance_id(id: i64) -> Self {
956+
Self::try_from_instance_id(id).expect("instance should be alive")
957+
}
958+
}
959+
895960
/// Trait for safe conversion from Godot object references into API method arguments. This is
896961
/// a sealed trait with no public interface.
897962
///

test/src/lib.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub extern "C" fn run_tests(
5757
status &= test_constructor();
5858
status &= test_underscore_method_binding();
5959
status &= test_rust_class_construction();
60+
status &= test_from_instance_id();
6061

6162
status &= test_derive::run_tests();
6263
status &= test_free_ub::run_tests();
@@ -207,6 +208,61 @@ impl OptionalArgs {
207208
}
208209
}
209210

211+
fn test_from_instance_id() -> bool {
212+
println!(" -- test_from_instance_id");
213+
214+
let ok = std::panic::catch_unwind(|| {
215+
assert!(unsafe { Node::try_from_instance_id(22).is_none() });
216+
assert!(unsafe { Node::try_from_instance_id(42).is_none() });
217+
assert!(unsafe { Node::try_from_instance_id(503).is_none() });
218+
219+
let instance_id;
220+
221+
{
222+
let foo = unsafe { Node::new().into_shared().assume_safe() };
223+
foo.set_name("foo");
224+
225+
instance_id = foo.get_instance_id();
226+
227+
assert!(unsafe { Reference::try_from_instance_id(instance_id).is_none() });
228+
229+
let reconstructed = unsafe { Node::from_instance_id(instance_id) };
230+
assert_eq!("foo", reconstructed.name().to_string());
231+
232+
unsafe { foo.assume_unique().free() };
233+
}
234+
235+
assert!(unsafe { Node::try_from_instance_id(instance_id).is_none() });
236+
237+
let instance_id;
238+
239+
{
240+
let foo = Reference::new().into_shared();
241+
let foo = unsafe { foo.assume_safe() };
242+
foo.set_meta("foo", "bar");
243+
244+
instance_id = foo.get_instance_id();
245+
246+
assert!(unsafe { Node::try_from_instance_id(instance_id).is_none() });
247+
248+
let reconstructed = unsafe { Reference::from_instance_id(instance_id) };
249+
assert_eq!(
250+
"bar",
251+
String::from_variant(&reconstructed.get_meta("foo")).unwrap()
252+
);
253+
}
254+
255+
assert!(unsafe { Reference::try_from_instance_id(instance_id).is_none() });
256+
})
257+
.is_ok();
258+
259+
if !ok {
260+
gdnative::godot_error!(" !! Test test_from_instance_id failed");
261+
}
262+
263+
ok
264+
}
265+
210266
fn init(handle: InitHandle) {
211267
handle.add_class::<Foo>();
212268
handle.add_class::<OptionalArgs>();

0 commit comments

Comments
 (0)