Skip to content

Commit 86e9583

Browse files
bors[bot]Bromeon
andauthored
Merge #830
830: Implement AsArg for Instance + TInstance r=Bromeon a=Bromeon Closes #749. Also adds integration tests for existing `AsArg` implementations (`Ref` + `TRef`). Co-authored-by: Jan Haller <[email protected]>
2 parents e1ecbc3 + 37b7679 commit 86e9583

File tree

7 files changed

+342
-120
lines changed

7 files changed

+342
-120
lines changed

gdnative-core/src/object/as_arg.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
use crate::export::user_data::Map;
2+
use crate::export::NativeClass;
3+
use crate::object::ownership::{Ownership, Shared, Unique};
4+
use crate::object::{GodotObject, Instance, Null, Ref, SubClass, TInstance, TRef};
5+
6+
/// Trait for safe conversion from Godot object references into API method arguments. This is
7+
/// a sealed trait with no public interface.
8+
///
9+
/// In order to enforce thread safety statically, the ability to be passed to the engine is only
10+
/// given to some reference types. Specifically, they are:
11+
///
12+
/// - All *owned* `Ref<T, Unique>` references. The `Unique` access is lost if passed into a
13+
/// method.
14+
/// - Owned and borrowed `Shared` references, including temporary ones (`TRef`).
15+
///
16+
/// It's unsound to pass `ThreadLocal` references to the engine because there is no guarantee
17+
/// that the reference will stay on the same thread.
18+
///
19+
/// To explicitly pass a null reference to the engine, use `Null::null` or `GodotObject::null`.
20+
pub trait AsArg<T>: private::Sealed {
21+
#[doc(hidden)]
22+
fn as_arg_ptr(&self) -> *mut sys::godot_object;
23+
24+
#[doc(hidden)]
25+
#[inline]
26+
unsafe fn to_arg_variant(&self) -> crate::core_types::Variant {
27+
crate::core_types::Variant::from_object_ptr(self.as_arg_ptr())
28+
}
29+
}
30+
31+
/// Trait for safe conversion from Godot object references into Variant. This is
32+
/// a sealed trait with no public interface.
33+
///
34+
/// Used for `Variant` methods and implementations as a trait bound to improve type inference.
35+
pub trait AsVariant: AsArg<<Self as AsVariant>::Target> {
36+
type Target;
37+
}
38+
39+
// ----------------------------------------------------------------------------------------------------------------------------------------------
40+
// Sealed
41+
42+
mod private {
43+
pub trait Sealed {}
44+
}
45+
46+
// Null
47+
impl<'a, T> private::Sealed for Null<T> {}
48+
49+
// Temporary references (shared ownership)
50+
impl<'a, T: GodotObject> private::Sealed for TRef<'a, T, Shared> {}
51+
impl<'a, T: GodotObject> private::Sealed for &'a Ref<T, Shared> {}
52+
impl<'a, T: NativeClass> private::Sealed for TInstance<'a, T, Shared> {}
53+
impl<'a, T: NativeClass> private::Sealed for &'a Instance<T, Shared> {}
54+
55+
// Persistent references (any ownership)
56+
impl<T: GodotObject, Own: Ownership> private::Sealed for Ref<T, Own> {}
57+
impl<T: NativeClass, Own: Ownership> private::Sealed for Instance<T, Own> {}
58+
59+
// ----------------------------------------------------------------------------------------------------------------------------------------------
60+
// Null
61+
62+
impl<'a, T: GodotObject> AsArg<T> for Null<T> {
63+
#[inline]
64+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
65+
std::ptr::null_mut()
66+
}
67+
}
68+
69+
impl<'a, T: GodotObject> AsVariant for Null<T> {
70+
type Target = T;
71+
}
72+
73+
// ----------------------------------------------------------------------------------------------------------------------------------------------
74+
// TRef
75+
76+
impl<'a, T, U> AsArg<U> for TRef<'a, T, Shared>
77+
where
78+
T: GodotObject + SubClass<U>,
79+
U: GodotObject,
80+
{
81+
#[inline]
82+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
83+
self.as_ptr()
84+
}
85+
}
86+
87+
impl<'a, T: GodotObject> AsVariant for TRef<'a, T, Shared> {
88+
type Target = T;
89+
}
90+
91+
// ----------------------------------------------------------------------------------------------------------------------------------------------
92+
// Ref
93+
94+
impl<T, U> AsArg<U> for Ref<T, Shared>
95+
where
96+
T: GodotObject + SubClass<U>,
97+
U: GodotObject,
98+
{
99+
#[inline]
100+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
101+
self.as_ptr()
102+
}
103+
}
104+
105+
impl<T, U> AsArg<U> for Ref<T, Unique>
106+
where
107+
T: GodotObject + SubClass<U>,
108+
U: GodotObject,
109+
{
110+
#[inline]
111+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
112+
self.as_ptr()
113+
}
114+
}
115+
116+
impl<T: GodotObject> AsVariant for Ref<T, Unique> {
117+
type Target = T;
118+
}
119+
120+
impl<'a, T, U> AsArg<U> for &'a Ref<T, Shared>
121+
where
122+
T: GodotObject + SubClass<U>,
123+
U: GodotObject,
124+
{
125+
#[inline]
126+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
127+
self.as_ptr()
128+
}
129+
}
130+
131+
impl<T: GodotObject> AsVariant for Ref<T, Shared> {
132+
type Target = T;
133+
}
134+
135+
impl<'a, T: GodotObject> AsVariant for &'a Ref<T, Shared> {
136+
type Target = T;
137+
}
138+
139+
// ----------------------------------------------------------------------------------------------------------------------------------------------
140+
// TInstance
141+
142+
impl<'a, T, U> AsArg<U> for TInstance<'a, T, Shared>
143+
where
144+
T: NativeClass,
145+
T::Base: GodotObject + SubClass<U>,
146+
T::UserData: Map,
147+
U: GodotObject,
148+
{
149+
#[inline]
150+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
151+
self.as_base_ptr()
152+
}
153+
}
154+
155+
// ----------------------------------------------------------------------------------------------------------------------------------------------
156+
// Instance
157+
158+
impl<T, U, Own: Ownership> AsArg<U> for Instance<T, Own>
159+
where
160+
T: NativeClass,
161+
T::Base: GodotObject + SubClass<U>,
162+
T::UserData: Map,
163+
U: GodotObject,
164+
{
165+
#[inline]
166+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
167+
self.as_base_ptr()
168+
}
169+
}
170+
171+
impl<'a, T, U> AsArg<U> for &'a Instance<T, Shared>
172+
where
173+
T: NativeClass,
174+
T::Base: GodotObject + SubClass<U>,
175+
T::UserData: Map,
176+
U: GodotObject,
177+
{
178+
#[inline]
179+
fn as_arg_ptr(&self) -> *mut sys::godot_object {
180+
self.as_base_ptr()
181+
}
182+
}

gdnative-core/src/object/instance.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ impl<T: NativeClass, Own: Ownership> Instance<T, Own> {
229229
pub fn script(&self) -> &T::UserData {
230230
&self.script
231231
}
232+
233+
/// Convert to a nullable raw pointer. Used for AsArg.
234+
pub(super) fn as_base_ptr(&self) -> *mut sys::godot_object {
235+
self.owner.as_ptr()
236+
}
232237
}
233238

234239
impl<T: NativeClass, Own: Ownership> Instance<T, Own>
@@ -464,6 +469,11 @@ impl<'a, T: NativeClass, Own: Ownership> TInstance<'a, T, Own> {
464469
let script = T::UserData::clone_from_user_data_unchecked(user_data);
465470
TInstance { owner, script }
466471
}
472+
473+
/// Convert to a nullable raw pointer. Used for AsArg.
474+
pub(super) fn as_base_ptr(&self) -> *mut sys::godot_object {
475+
self.owner.as_ptr()
476+
}
467477
}
468478

469479
impl<'a, T: NativeClass, Own: NonUniqueOwnership> TInstance<'a, T, Own> {

gdnative-core/src/object/mod.rs

Lines changed: 2 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::export::NativeClass;
2525
use crate::private::{get_api, ManuallyManagedClassPlaceholder, ReferenceCountedClassPlaceholder};
2626
use crate::sys;
2727

28+
pub use as_arg::*;
2829
pub use instance::*;
2930
pub use new_ref::NewRef;
3031
pub use raw::RawObject;
@@ -33,6 +34,7 @@ pub mod bounds;
3334
pub mod memory;
3435
pub mod ownership;
3536

37+
mod as_arg;
3638
mod instance;
3739
mod new_ref;
3840
mod raw;
@@ -305,8 +307,6 @@ unsafe impl<T: GodotObject, Own: Ownership + Send> Send for Ref<T, Own> {}
305307
/// `Ref` is `Sync` if the thread access is `Shared`.
306308
unsafe impl<T: GodotObject, Own: Ownership + Sync> Sync for Ref<T, Own> {}
307309

308-
impl<T: GodotObject, Own: Ownership> private::Sealed for Ref<T, Own> {}
309-
310310
/// `Ref` is `Copy` if the underlying object is manually-managed, and the access is not
311311
/// `Unique`.
312312
impl<T, Own> Copy for Ref<T, Own>
@@ -994,39 +994,6 @@ impl<'a, T: GodotObject> TRef<'a, T, Shared> {
994994
}
995995
}
996996

997-
/// Trait for safe conversion from Godot object references into API method arguments. This is
998-
/// a sealed trait with no public interface.
999-
///
1000-
/// In order to enforce thread safety statically, the ability to be passed to the engine is only
1001-
/// given to some reference types. Specifically, they are:
1002-
///
1003-
/// - All *owned* `Ref<T, Unique>` references. The `Unique` access is lost if passed into a
1004-
/// method.
1005-
/// - Owned and borrowed `Shared` references, including temporary ones (`TRef`).
1006-
///
1007-
/// It's unsound to pass `ThreadLocal` references to the engine because there is no guarantee
1008-
/// that the reference will stay on the same thread.
1009-
///
1010-
/// To explicitly pass a null reference to the engine, use `Null::null` or `GodotObject::null`.
1011-
pub trait AsArg<T>: private::Sealed {
1012-
#[doc(hidden)]
1013-
fn as_arg_ptr(&self) -> *mut sys::godot_object;
1014-
1015-
#[doc(hidden)]
1016-
#[inline]
1017-
unsafe fn to_arg_variant(&self) -> crate::core_types::Variant {
1018-
crate::core_types::Variant::from_object_ptr(self.as_arg_ptr())
1019-
}
1020-
}
1021-
1022-
/// Trait for safe conversion from Godot object references into Variant. This is
1023-
/// a sealed trait with no public interface.
1024-
///
1025-
/// Used for `Variant` methods and implementations as a trait bound to improve type inference.
1026-
pub trait AsVariant: AsArg<<Self as AsVariant>::Target> {
1027-
type Target;
1028-
}
1029-
1030997
/// Represents an explicit null reference in method arguments. This works around type inference
1031998
/// issues with `Option`. You may create `Null`s with `Null::null` or `GodotObject::null`.
1032999
pub struct Null<T>(PhantomData<T>);
@@ -1040,76 +1007,3 @@ impl<T: GodotObject> Null<T> {
10401007
Null(PhantomData)
10411008
}
10421009
}
1043-
1044-
impl<'a, T> private::Sealed for Null<T> {}
1045-
impl<'a, T: GodotObject> AsArg<T> for Null<T> {
1046-
#[inline]
1047-
fn as_arg_ptr(&self) -> *mut sys::godot_object {
1048-
std::ptr::null_mut()
1049-
}
1050-
}
1051-
impl<'a, T: GodotObject> AsVariant for Null<T> {
1052-
type Target = T;
1053-
}
1054-
1055-
impl<'a, T: GodotObject> private::Sealed for TRef<'a, T, Shared> {}
1056-
impl<'a, T, U> AsArg<U> for TRef<'a, T, Shared>
1057-
where
1058-
T: GodotObject + SubClass<U>,
1059-
U: GodotObject,
1060-
{
1061-
#[inline]
1062-
fn as_arg_ptr(&self) -> *mut sys::godot_object {
1063-
self.as_ptr()
1064-
}
1065-
}
1066-
impl<'a, T: GodotObject> AsVariant for TRef<'a, T, Shared> {
1067-
type Target = T;
1068-
}
1069-
1070-
impl<T, U> AsArg<U> for Ref<T, Shared>
1071-
where
1072-
T: GodotObject + SubClass<U>,
1073-
U: GodotObject,
1074-
{
1075-
#[inline]
1076-
fn as_arg_ptr(&self) -> *mut sys::godot_object {
1077-
self.as_ptr()
1078-
}
1079-
}
1080-
impl<T: GodotObject> AsVariant for Ref<T, Shared> {
1081-
type Target = T;
1082-
}
1083-
1084-
impl<T, U> AsArg<U> for Ref<T, Unique>
1085-
where
1086-
T: GodotObject + SubClass<U>,
1087-
U: GodotObject,
1088-
{
1089-
#[inline]
1090-
fn as_arg_ptr(&self) -> *mut sys::godot_object {
1091-
self.as_ptr()
1092-
}
1093-
}
1094-
impl<T: GodotObject> AsVariant for Ref<T, Unique> {
1095-
type Target = T;
1096-
}
1097-
1098-
impl<'a, T: GodotObject> private::Sealed for &'a Ref<T, Shared> {}
1099-
impl<'a, T, U> AsArg<U> for &'a Ref<T, Shared>
1100-
where
1101-
T: GodotObject + SubClass<U>,
1102-
U: GodotObject,
1103-
{
1104-
#[inline]
1105-
fn as_arg_ptr(&self) -> *mut sys::godot_object {
1106-
self.as_ptr()
1107-
}
1108-
}
1109-
impl<'a, T: GodotObject> AsVariant for &'a Ref<T, Shared> {
1110-
type Target = T;
1111-
}
1112-
1113-
mod private {
1114-
pub trait Sealed {}
1115-
}

test/project/addons/editor_test_runner/plugin.gd

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func _enter_tree():
1515
print("Opening editor normally for the test project. To run tests, pass `--run-editor-tests` to the executable.")
1616

1717
func _run_tests():
18-
print(" -- Rust gdnative test suite:")
18+
print(" -- Rust GDNative test suite (called from editor):")
1919
gdn = GDNative.new()
2020
var status = false;
2121

@@ -26,12 +26,13 @@ func _run_tests():
2626

2727
gdn.terminate()
2828
else:
29-
print(" -- Could not load the gdnative library.")
29+
print(" -- Could not load the GDNative library.")
3030

31+
print()
3132
if status:
32-
print(" -- Test run completed successfully.")
33+
print(" All tests PASSED.")
3334
else:
34-
print(" -- Test run completed with errors.")
35+
print(" Tests FAILED.")
3536
OS.exit_code = 1
3637

3738
print(" -- exiting.")

0 commit comments

Comments
 (0)