Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement AsArg for Instance + TInstance #830

Merged
merged 3 commits into from Dec 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
182 changes: 182 additions & 0 deletions gdnative-core/src/object/as_arg.rs
@@ -0,0 +1,182 @@
use crate::export::user_data::Map;
use crate::export::NativeClass;
use crate::object::ownership::{Ownership, Shared, Unique};
use crate::object::{GodotObject, Instance, Null, Ref, SubClass, TInstance, TRef};

/// Trait for safe conversion from Godot object references into API method arguments. This is
/// a sealed trait with no public interface.
///
/// In order to enforce thread safety statically, the ability to be passed to the engine is only
/// given to some reference types. Specifically, they are:
///
/// - All *owned* `Ref<T, Unique>` references. The `Unique` access is lost if passed into a
/// method.
/// - Owned and borrowed `Shared` references, including temporary ones (`TRef`).
///
/// It's unsound to pass `ThreadLocal` references to the engine because there is no guarantee
/// that the reference will stay on the same thread.
///
/// To explicitly pass a null reference to the engine, use `Null::null` or `GodotObject::null`.
pub trait AsArg<T>: private::Sealed {
#[doc(hidden)]
fn as_arg_ptr(&self) -> *mut sys::godot_object;

#[doc(hidden)]
#[inline]
unsafe fn to_arg_variant(&self) -> crate::core_types::Variant {
crate::core_types::Variant::from_object_ptr(self.as_arg_ptr())
}
}

/// Trait for safe conversion from Godot object references into Variant. This is
/// a sealed trait with no public interface.
///
/// Used for `Variant` methods and implementations as a trait bound to improve type inference.
pub trait AsVariant: AsArg<<Self as AsVariant>::Target> {
type Target;
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Sealed

mod private {
pub trait Sealed {}
}

// Null
impl<'a, T> private::Sealed for Null<T> {}

// Temporary references (shared ownership)
impl<'a, T: GodotObject> private::Sealed for TRef<'a, T, Shared> {}
impl<'a, T: GodotObject> private::Sealed for &'a Ref<T, Shared> {}
impl<'a, T: NativeClass> private::Sealed for TInstance<'a, T, Shared> {}
impl<'a, T: NativeClass> private::Sealed for &'a Instance<T, Shared> {}

// Persistent references (any ownership)
impl<T: GodotObject, Own: Ownership> private::Sealed for Ref<T, Own> {}
impl<T: NativeClass, Own: Ownership> private::Sealed for Instance<T, Own> {}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Null

impl<'a, T: GodotObject> AsArg<T> for Null<T> {
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
std::ptr::null_mut()
}
}

impl<'a, T: GodotObject> AsVariant for Null<T> {
type Target = T;
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// TRef

impl<'a, T, U> AsArg<U> for TRef<'a, T, Shared>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}

impl<'a, T: GodotObject> AsVariant for TRef<'a, T, Shared> {
type Target = T;
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Ref

impl<T, U> AsArg<U> for Ref<T, Shared>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}

impl<T, U> AsArg<U> for Ref<T, Unique>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}

impl<T: GodotObject> AsVariant for Ref<T, Unique> {
type Target = T;
}

impl<'a, T, U> AsArg<U> for &'a Ref<T, Shared>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}

impl<T: GodotObject> AsVariant for Ref<T, Shared> {
type Target = T;
}

impl<'a, T: GodotObject> AsVariant for &'a Ref<T, Shared> {
type Target = T;
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// TInstance

impl<'a, T, U> AsArg<U> for TInstance<'a, T, Shared>
where
T: NativeClass,
T::Base: GodotObject + SubClass<U>,
T::UserData: Map,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_base_ptr()
}
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Instance

impl<T, U, Own: Ownership> AsArg<U> for Instance<T, Own>
where
T: NativeClass,
T::Base: GodotObject + SubClass<U>,
T::UserData: Map,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_base_ptr()
}
}

impl<'a, T, U> AsArg<U> for &'a Instance<T, Shared>
where
T: NativeClass,
T::Base: GodotObject + SubClass<U>,
T::UserData: Map,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_base_ptr()
}
}
10 changes: 10 additions & 0 deletions gdnative-core/src/object/instance.rs
Expand Up @@ -229,6 +229,11 @@ impl<T: NativeClass, Own: Ownership> Instance<T, Own> {
pub fn script(&self) -> &T::UserData {
&self.script
}

/// Convert to a nullable raw pointer. Used for AsArg.
pub(super) fn as_base_ptr(&self) -> *mut sys::godot_object {
self.owner.as_ptr()
}
}

impl<T: NativeClass, Own: Ownership> Instance<T, Own>
Expand Down Expand Up @@ -464,6 +469,11 @@ impl<'a, T: NativeClass, Own: Ownership> TInstance<'a, T, Own> {
let script = T::UserData::clone_from_user_data_unchecked(user_data);
TInstance { owner, script }
}

/// Convert to a nullable raw pointer. Used for AsArg.
pub(super) fn as_base_ptr(&self) -> *mut sys::godot_object {
self.owner.as_ptr()
}
}

impl<'a, T: NativeClass, Own: NonUniqueOwnership> TInstance<'a, T, Own> {
Expand Down
110 changes: 2 additions & 108 deletions gdnative-core/src/object/mod.rs
Expand Up @@ -25,6 +25,7 @@ use crate::export::NativeClass;
use crate::private::{get_api, ManuallyManagedClassPlaceholder, ReferenceCountedClassPlaceholder};
use crate::sys;

pub use as_arg::*;
pub use instance::*;
pub use new_ref::NewRef;
pub use raw::RawObject;
Expand All @@ -33,6 +34,7 @@ pub mod bounds;
pub mod memory;
pub mod ownership;

mod as_arg;
mod instance;
mod new_ref;
mod raw;
Expand Down Expand Up @@ -305,8 +307,6 @@ unsafe impl<T: GodotObject, Own: Ownership + Send> Send for Ref<T, Own> {}
/// `Ref` is `Sync` if the thread access is `Shared`.
unsafe impl<T: GodotObject, Own: Ownership + Sync> Sync for Ref<T, Own> {}

impl<T: GodotObject, Own: Ownership> private::Sealed for Ref<T, Own> {}

/// `Ref` is `Copy` if the underlying object is manually-managed, and the access is not
/// `Unique`.
impl<T, Own> Copy for Ref<T, Own>
Expand Down Expand Up @@ -994,39 +994,6 @@ impl<'a, T: GodotObject> TRef<'a, T, Shared> {
}
}

/// Trait for safe conversion from Godot object references into API method arguments. This is
/// a sealed trait with no public interface.
///
/// In order to enforce thread safety statically, the ability to be passed to the engine is only
/// given to some reference types. Specifically, they are:
///
/// - All *owned* `Ref<T, Unique>` references. The `Unique` access is lost if passed into a
/// method.
/// - Owned and borrowed `Shared` references, including temporary ones (`TRef`).
///
/// It's unsound to pass `ThreadLocal` references to the engine because there is no guarantee
/// that the reference will stay on the same thread.
///
/// To explicitly pass a null reference to the engine, use `Null::null` or `GodotObject::null`.
pub trait AsArg<T>: private::Sealed {
#[doc(hidden)]
fn as_arg_ptr(&self) -> *mut sys::godot_object;

#[doc(hidden)]
#[inline]
unsafe fn to_arg_variant(&self) -> crate::core_types::Variant {
crate::core_types::Variant::from_object_ptr(self.as_arg_ptr())
}
}

/// Trait for safe conversion from Godot object references into Variant. This is
/// a sealed trait with no public interface.
///
/// Used for `Variant` methods and implementations as a trait bound to improve type inference.
pub trait AsVariant: AsArg<<Self as AsVariant>::Target> {
type Target;
}

/// Represents an explicit null reference in method arguments. This works around type inference
/// issues with `Option`. You may create `Null`s with `Null::null` or `GodotObject::null`.
pub struct Null<T>(PhantomData<T>);
Expand All @@ -1040,76 +1007,3 @@ impl<T: GodotObject> Null<T> {
Null(PhantomData)
}
}

impl<'a, T> private::Sealed for Null<T> {}
impl<'a, T: GodotObject> AsArg<T> for Null<T> {
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
std::ptr::null_mut()
}
}
impl<'a, T: GodotObject> AsVariant for Null<T> {
type Target = T;
}

impl<'a, T: GodotObject> private::Sealed for TRef<'a, T, Shared> {}
impl<'a, T, U> AsArg<U> for TRef<'a, T, Shared>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}
impl<'a, T: GodotObject> AsVariant for TRef<'a, T, Shared> {
type Target = T;
}

impl<T, U> AsArg<U> for Ref<T, Shared>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}
impl<T: GodotObject> AsVariant for Ref<T, Shared> {
type Target = T;
}

impl<T, U> AsArg<U> for Ref<T, Unique>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}
impl<T: GodotObject> AsVariant for Ref<T, Unique> {
type Target = T;
}

impl<'a, T: GodotObject> private::Sealed for &'a Ref<T, Shared> {}
impl<'a, T, U> AsArg<U> for &'a Ref<T, Shared>
where
T: GodotObject + SubClass<U>,
U: GodotObject,
{
#[inline]
fn as_arg_ptr(&self) -> *mut sys::godot_object {
self.as_ptr()
}
}
impl<'a, T: GodotObject> AsVariant for &'a Ref<T, Shared> {
type Target = T;
}

mod private {
pub trait Sealed {}
}
9 changes: 5 additions & 4 deletions test/project/addons/editor_test_runner/plugin.gd
Expand Up @@ -15,7 +15,7 @@ func _enter_tree():
print("Opening editor normally for the test project. To run tests, pass `--run-editor-tests` to the executable.")

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

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

gdn.terminate()
else:
print(" -- Could not load the gdnative library.")
print(" -- Could not load the GDNative library.")

print()
if status:
print(" -- Test run completed successfully.")
print(" All tests PASSED.")
else:
print(" -- Test run completed with errors.")
print(" Tests FAILED.")
OS.exit_code = 1

print(" -- exiting.")
Expand Down