Skip to content

Commit cc8ff55

Browse files
committed
Rid: get_id() now unsafe; rename is_valid() -> is_occupied(); fix PartialOrd; docs
1 parent 27af81b commit cc8ff55

File tree

1 file changed

+42
-19
lines changed
  • gdnative-core/src/core_types

1 file changed

+42
-19
lines changed

gdnative-core/src/core_types/rid.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
11
use crate::private::get_api;
22
use crate::sys;
33
use std::cmp::Ordering;
4-
use std::cmp::{Eq, PartialEq};
54
use std::mem::transmute;
65

7-
/// The RID type is used to access the unique integer ID of a resource.
8-
/// They are opaque, so they do not grant access to the associated resource by themselves.
6+
// Note: for safety design, consult:
7+
// * https://github.com/godotengine/godot/blob/3.x/core/rid.h
8+
// * https://github.com/godotengine/godot/blob/3.x/modules/gdnative/include/gdnative/rid.h
9+
10+
/// A RID ("resource ID") is an opaque handle that refers to a Godot `Resource`.
11+
///
12+
/// RIDs do not grant access to the resource itself. Instead, they can be used in lower-level resource APIs
13+
/// such as the [servers]. See also [Godot API docs for `RID`][docs].
14+
///
15+
/// Note that RIDs are highly unsafe to work with (especially with a Release build of Godot):
16+
/// * They are untyped, i.e. Godot does not recognize if they represent the correct resource type.
17+
/// * The internal handle is interpreted as a raw pointer by Godot, meaning that passing an invalid or wrongly
18+
/// typed RID is instant undefined behavior.
19+
///
20+
/// For this reason, GDNative methods accepting `Rid` parameters are marked `unsafe`.
21+
///
22+
/// [servers]: https://docs.godotengine.org/en/stable/tutorials/optimization/using_servers.html
23+
/// [docs]: https://docs.godotengine.org/en/stable/classes/class_rid.html
924
#[derive(Copy, Clone, Debug)]
1025
pub struct Rid(pub(crate) sys::godot_rid);
1126

1227
impl Rid {
28+
/// Creates an empty, invalid RID.
1329
#[inline]
1430
pub fn new() -> Self {
1531
Rid::default()
1632
}
1733

34+
/// Returns the ID of the referenced resource.
35+
///
36+
/// # Panics
37+
/// When this instance is empty, i.e. `self.is_occupied()` is false.
38+
///
39+
/// # Safety
40+
/// RIDs are untyped and interpreted as raw pointers by the engine.
41+
/// If this method is called on an invalid resource ID, the behavior is undefined.
42+
/// This can happen when the resource behind the RID is no longer alive.
1843
#[inline]
19-
pub fn get_id(self) -> i32 {
20-
unsafe { (get_api().godot_rid_get_id)(&self.0) }
21-
}
22-
23-
#[inline]
24-
pub fn operator_less(self, b: Rid) -> bool {
25-
unsafe { (get_api().godot_rid_operator_less)(&self.0, &b.0) }
44+
pub unsafe fn get_id(self) -> i32 {
45+
assert!(self.is_occupied());
46+
(get_api().godot_rid_get_id)(&self.0)
2647
}
2748

49+
/// Check if this RID is non-empty. This does **not** mean it's valid or safe to use!
50+
///
51+
/// This simply checks if the handle has not been initialized with the empty default.
52+
/// It does not give any indication about whether it points to a valid resource.
2853
#[inline]
29-
pub fn is_valid(self) -> bool {
54+
pub fn is_occupied(self) -> bool {
3055
self.to_u64() != 0
3156
}
3257

@@ -73,14 +98,12 @@ impl_basic_traits_as_sys! {
7398
impl PartialOrd for Rid {
7499
#[inline]
75100
fn partial_cmp(&self, other: &Rid) -> Option<Ordering> {
76-
unsafe {
77-
let native = (get_api().godot_rid_operator_less)(&self.0, &other.0);
78-
79-
if native {
80-
Some(Ordering::Less)
81-
} else {
82-
Some(Ordering::Greater)
83-
}
101+
if PartialEq::eq(self, other) {
102+
Some(Ordering::Equal)
103+
} else if unsafe { (get_api().godot_rid_operator_less)(self.sys(), other.sys()) } {
104+
Some(Ordering::Less)
105+
} else {
106+
Some(Ordering::Greater)
84107
}
85108
}
86109
}

0 commit comments

Comments
 (0)