Skip to content

Commit 84505ba

Browse files
committed
Use Gd::null_arg(), consistent with Variant::nil()
1 parent df48750 commit 84505ba

File tree

6 files changed

+68
-55
lines changed

6 files changed

+68
-55
lines changed

godot-core/src/builtin/variant/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub struct Variant {
2929

3030
impl Variant {
3131
/// Create an empty variant (`null` value in GDScript).
32+
///
33+
/// If a Godot engine API accepts object (not variant) parameters and you'd like to pass `null`, use
34+
/// [`Gd::null_arg()`][crate::obj::Gd::null_arg] instead.
3235
pub fn nil() -> Self {
3336
Self::default()
3437
}

godot-core/src/obj/gd.rs

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ use crate::{classes, out};
3131
/// This smart pointer can only hold _objects_ in the Godot sense: instances of Godot classes (`Node`, `RefCounted`, etc.)
3232
/// or user-declared structs (declared with `#[derive(GodotClass)]`). It does **not** hold built-in types (`Vector3`, `Color`, `i32`).
3333
///
34-
/// `Gd<T>` never holds null objects. If you need nullability, use `Option<Gd<T>>`. To pass null objects to engine APIs, use
35-
/// [`NullArg`][crate::obj::NullArg].
34+
/// `Gd<T>` never holds null objects. If you need nullability, use `Option<Gd<T>>`. To pass null objects to engine APIs, you can
35+
/// additionally use [`Gd::null_arg()`] as a shorthand.
3636
///
3737
/// # Memory management
3838
///
@@ -466,26 +466,7 @@ impl<T: GodotClass> Gd<T> {
466466
{
467467
self.raw.script_sys()
468468
}
469-
}
470-
471-
impl<T: GodotClass> Deref for Gd<T> {
472-
// Target is always an engine class:
473-
// * if T is an engine class => T
474-
// * if T is a user class => T::Base
475-
type Target = GdDerefTarget<T>;
476469

477-
fn deref(&self) -> &Self::Target {
478-
self.raw.as_target()
479-
}
480-
}
481-
482-
impl<T: GodotClass> DerefMut for Gd<T> {
483-
fn deref_mut(&mut self) -> &mut Self::Target {
484-
self.raw.as_target_mut()
485-
}
486-
}
487-
488-
impl<T: GodotClass> Gd<T> {
489470
/// Runs `init_fn` on the address of a pointer (initialized to null). If that pointer is still null after the `init_fn` call,
490471
/// then `None` will be returned; otherwise `Gd::from_obj_sys(ptr)`.
491472
///
@@ -635,9 +616,56 @@ where
635616
}
636617
}
637618

619+
impl<T> Gd<T>
620+
where
621+
T: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
622+
{
623+
/// Represents `null` when passing an object argument to Godot.
624+
///
625+
/// This expression is only intended for function argument lists. It can be used whenever a Godot signature accepts
626+
/// [`AsObjectArg<T>`][crate::obj::AsObjectArg]. `Gd::null_arg()` as an argument is equivalent to `Option::<Gd<T>>::None`, but less wordy.
627+
///
628+
/// To work with objects that can be null, use `Option<Gd<T>>` instead. For APIs that accept `Variant`, you can pass [`Variant::nil()`].
629+
///
630+
/// # Nullability
631+
/// <div class="warning">
632+
/// The GDExtension API does not inform about nullability of its function parameters. It is up to you to verify that the arguments you pass
633+
/// are only null when this is allowed. Doing this wrong should be safe, but can lead to the function call failing.
634+
/// </div>
635+
///
636+
/// # Example
637+
/// ```no_run
638+
/// # fn some_shape() -> Gd<GltfPhysicsShape> { unimplemented!() }
639+
/// use godot::prelude::*;
640+
/// use godot::classes::GltfPhysicsShape;
641+
///
642+
/// let mut shape: Gd<GltfPhysicsShape> = some_shape();
643+
/// shape.set_importer_mesh(Gd::null_arg());
644+
pub fn null_arg() -> crate::obj::ObjectNullArg<T> {
645+
crate::obj::ObjectNullArg(std::marker::PhantomData)
646+
}
647+
}
648+
638649
// ----------------------------------------------------------------------------------------------------------------------------------------------
639650
// Trait impls
640651

652+
impl<T: GodotClass> Deref for Gd<T> {
653+
// Target is always an engine class:
654+
// * if T is an engine class => T
655+
// * if T is a user class => T::Base
656+
type Target = GdDerefTarget<T>;
657+
658+
fn deref(&self) -> &Self::Target {
659+
self.raw.as_target()
660+
}
661+
}
662+
663+
impl<T: GodotClass> DerefMut for Gd<T> {
664+
fn deref_mut(&mut self) -> &mut Self::Target {
665+
self.raw.as_target_mut()
666+
}
667+
}
668+
641669
impl<T: GodotClass> GodotConvert for Gd<T> {
642670
type Via = Gd<T>;
643671
}

godot-core/src/obj/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@
1111
//! * [`GodotClass`], which is implemented for every class that Godot can work with (either engine- or user-provided).
1212
//! * [`Gd`], a smart pointer that manages instances of Godot classes.
1313
14-
mod as_object_arg;
1514
mod base;
1615
mod gd;
1716
mod guards;
1817
mod instance_id;
18+
mod object_arg;
1919
mod onready;
2020
mod raw_gd;
2121
mod traits;
2222

2323
pub(crate) mod rtti;
2424

25-
pub use as_object_arg::*;
2625
pub use base::*;
2726
pub use gd::*;
2827
pub use guards::{BaseMut, BaseRef, GdMut, GdRef};
2928
pub use instance_id::*;
29+
pub use object_arg::*;
3030
pub use onready::*;
3131
pub use raw_gd::*;
3232
pub use traits::*;

godot-core/src/obj/as_object_arg.rs renamed to godot-core/src/obj/object_arg.rs

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::ptr;
1818
/// This trait is implemented for the following types:
1919
/// - [`Gd<T>`] and `&Gd<T>`, to pass objects. Subclasses of `T` are explicitly supported.
2020
/// - [`Option<Gd<T>>`] and `Option<&Gd<T>>`, to pass optional objects. `None` is mapped to a null argument.
21-
/// - [`NullArg`], to pass `null` arguments without using `Option`.
21+
/// - [`Gd::null_arg()`], to pass `null` arguments without using `Option`.
2222
///
2323
/// # Nullability
2424
/// <div class="warning">
@@ -49,7 +49,9 @@ where
4949
U: Inherits<T>,
5050
{
5151
fn as_object_arg(&self) -> ObjectArg<T> {
52-
ObjectArg::from_raw_gd(&self.raw)
52+
// SAFETY: In the context where as_object_arg() is called (a Godot engine call), the original Gd is guaranteed to remain valid.
53+
// This function is not part of the public API.
54+
unsafe { ObjectArg::from_raw_gd(&self.raw) }
5355
}
5456
}
5557

@@ -64,7 +66,7 @@ where
6466
}
6567
}
6668

67-
impl<T> AsObjectArg<T> for NullArg
69+
impl<T> AsObjectArg<T> for ObjectNullArg<T>
6870
where
6971
T: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
7072
{
@@ -75,30 +77,8 @@ where
7577

7678
// ----------------------------------------------------------------------------------------------------------------------------------------------
7779

78-
/// Represents `null` when passing an object argument to Godot.
79-
///
80-
/// This can be used whenever a Godot signature accepts [`AsObjectArg<T>`].
81-
/// Using `NullArg` is equivalent to passing `Option::<Gd<T>>::None`, but less wordy.
82-
///
83-
/// This expression is only intended for function argument lists. To work with objects that can be null, use `Option<Gd<T>>` instead.
84-
///
85-
/// For APIs that accept `Variant`, you can pass [`Variant::nil()`] instead.
86-
///
87-
/// # Nullability
88-
/// <div class="warning">
89-
/// The GDExtension API does not inform about nullability of its function parameters. It is up to you to verify that the arguments you pass
90-
/// are only null when this is allowed. Doing this wrong should be safe, but can lead to the function call failing.
91-
/// </div>
92-
///
93-
/// # Example
94-
/// ```no_run
95-
/// # fn some_shape() -> Gd<GltfPhysicsShape> { unimplemented!() }
96-
/// use godot::prelude::*;
97-
/// use godot_core::classes::GltfPhysicsShape;
98-
///
99-
/// let mut shape: Gd<GltfPhysicsShape> = some_shape();
100-
/// shape.set_importer_mesh(NullArg);
101-
pub struct NullArg;
80+
#[doc(hidden)]
81+
pub struct ObjectNullArg<T>(pub(crate) std::marker::PhantomData<*mut T>);
10282

10383
// ----------------------------------------------------------------------------------------------------------------------------------------------
10484

@@ -118,7 +98,9 @@ impl<T> ObjectArg<T>
11898
where
11999
T: GodotClass,
120100
{
121-
pub fn from_raw_gd<Derived>(obj: &RawGd<Derived>) -> Self
101+
/// # Safety
102+
/// The referenced `RawGd` must remain valid for the lifetime of this `ObjectArg`.
103+
pub unsafe fn from_raw_gd<Derived>(obj: &RawGd<Derived>) -> Self
122104
where
123105
Derived: Inherits<T>,
124106
{

godot/src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub use super::global::{
2626
pub use super::tools::{load, save, try_load, try_save, GFile};
2727

2828
pub use super::init::{gdextension, ExtensionLibrary, InitLevel};
29-
pub use super::obj::{Base, Gd, GdMut, GdRef, GodotClass, Inherits, InstanceId, NullArg, OnReady};
29+
pub use super::obj::{Base, Gd, GdMut, GdRef, GodotClass, Inherits, InstanceId, OnReady};
3030

3131
// Make trait methods available.
3232
pub use super::obj::EngineBitfield as _;

itest/rust/src/object_tests/object_arg_test.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use godot::builtin::Variant;
99
use godot::classes::{ClassDb, Node};
1010
use godot::global;
11-
use godot::obj::{Gd, NewAlloc, NullArg};
11+
use godot::obj::{Gd, NewAlloc};
1212

1313
use crate::framework::itest;
1414
use crate::object_tests::object_test::{user_refc_instance, RefcPayload};
@@ -71,10 +71,10 @@ fn object_arg_option_none() {
7171
fn object_arg_null_arg() {
7272
// Will emit errors but should not crash.
7373
let db = ClassDb::singleton();
74-
let error = db.class_set_property(NullArg, "name".into(), Variant::from("hello"));
74+
let error = db.class_set_property(Gd::null_arg(), "name".into(), Variant::from("hello"));
7575
assert_eq!(error, global::Error::ERR_UNAVAILABLE);
7676

77-
let error = db.class_set_property(NullArg, "value".into(), Variant::from(-123));
77+
let error = db.class_set_property(Gd::null_arg(), "value".into(), Variant::from(-123));
7878
assert_eq!(error, global::Error::ERR_UNAVAILABLE);
7979
}
8080

0 commit comments

Comments
 (0)