|
1 | 1 | use crate::private::get_api;
|
2 | 2 | use crate::sys;
|
3 | 3 | use std::cmp::Ordering;
|
4 |
| -use std::cmp::{Eq, PartialEq}; |
5 | 4 | use std::mem::transmute;
|
6 | 5 |
|
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 |
9 | 24 | #[derive(Copy, Clone, Debug)]
|
10 | 25 | pub struct Rid(pub(crate) sys::godot_rid);
|
11 | 26 |
|
12 | 27 | impl Rid {
|
| 28 | + /// Creates an empty, invalid RID. |
13 | 29 | #[inline]
|
14 | 30 | pub fn new() -> Self {
|
15 | 31 | Rid::default()
|
16 | 32 | }
|
17 | 33 |
|
| 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. |
18 | 43 | #[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) |
26 | 47 | }
|
27 | 48 |
|
| 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. |
28 | 53 | #[inline]
|
29 |
| - pub fn is_valid(self) -> bool { |
| 54 | + pub fn is_occupied(self) -> bool { |
30 | 55 | self.to_u64() != 0
|
31 | 56 | }
|
32 | 57 |
|
@@ -73,14 +98,12 @@ impl_basic_traits_as_sys! {
|
73 | 98 | impl PartialOrd for Rid {
|
74 | 99 | #[inline]
|
75 | 100 | 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) |
84 | 107 | }
|
85 | 108 | }
|
86 | 109 | }
|
0 commit comments