Skip to content

Commit 4e0e5a6

Browse files
TitanNanoBromeon
authored andcommitted
remove ParamType from AsArg
1 parent 031730c commit 4e0e5a6

File tree

6 files changed

+91
-63
lines changed

6 files changed

+91
-63
lines changed

godot-core/src/builtin/collections/array.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,15 +1118,6 @@ unsafe impl<T: ArrayElement> GodotFfi for Array<T> {
11181118
// Only implement for untyped arrays; typed arrays cannot be nested in Godot.
11191119
impl ArrayElement for VariantArray {}
11201120

1121-
impl<'r, T: ArrayElement> AsArg<Array<T>> for &'r Array<T> {
1122-
fn into_arg<'cow>(self) -> CowArg<'cow, Array<T>>
1123-
where
1124-
'r: 'cow, // Original reference must be valid for at least as long as the returned cow.
1125-
{
1126-
CowArg::Borrowed(self)
1127-
}
1128-
}
1129-
11301121
impl<T: ArrayElement> ParamType for Array<T> {
11311122
type Arg<'v> = CowArg<'v, Self>;
11321123

godot-core/src/meta/args/as_arg.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
use crate::builtin::{GString, NodePath, StringName};
9-
use crate::meta::{sealed, CowArg};
9+
use crate::meta::{sealed, CowArg, ToGodot};
1010
use std::ffi::CStr;
1111

1212
/// Implicit conversions for arguments passed to Godot APIs.
@@ -53,16 +53,37 @@ use std::ffi::CStr;
5353
note = "GString/StringName/NodePath aren't implicitly convertible for performance reasons; use their `arg()` method.",
5454
note = "see also `AsArg` docs: https://godot-rust.github.io/docs/gdext/master/godot/meta/trait.AsArg.html"
5555
)]
56-
pub trait AsArg<T: ParamType>
56+
pub trait AsArg<T: ToGodot>
5757
where
5858
Self: Sized,
5959
{
60+
// The usage of the CowArg return type introduces a small runtime penalty for values that implement Copy. Currently, the usage
61+
// ergonomics out weigh the runtime cost. Using the CowArg allows us to create a blanket implementation of the trait for all types that
62+
// implement ToGodot.
6063
#[doc(hidden)]
61-
fn into_arg<'r>(self) -> <T as ParamType>::Arg<'r>
64+
fn into_arg<'r>(self) -> CowArg<'r, T>
6265
where
6366
Self: 'r;
6467
}
6568

69+
impl<T: ToGodot> AsArg<T> for &T {
70+
fn into_arg<'r>(self) -> CowArg<'r, T>
71+
where
72+
Self: 'r,
73+
{
74+
CowArg::Borrowed(self)
75+
}
76+
}
77+
78+
impl<T: ToGodot + Copy> AsArg<T> for T {
79+
fn into_arg<'r>(self) -> CowArg<'r, T>
80+
where
81+
Self: 'r,
82+
{
83+
CowArg::Owned(self)
84+
}
85+
}
86+
6687
// ----------------------------------------------------------------------------------------------------------------------------------------------
6788
// Blanket impls
6889

@@ -81,7 +102,7 @@ macro_rules! arg_into_ref {
81102
};
82103
($arg_variable:ident: $T:ty) => {
83104
let $arg_variable = $arg_variable.into_arg();
84-
let $arg_variable: &$T = $crate::meta::ParamType::arg_to_ref(&$arg_variable);
105+
let $arg_variable: &$T = $arg_variable.cow_as_ref();
85106
};
86107
}
87108

@@ -102,20 +123,13 @@ macro_rules! arg_into_owned {
102123
};
103124
(infer $arg_variable:ident) => {
104125
let $arg_variable = $arg_variable.into_arg();
105-
let $arg_variable = $crate::meta::ParamType::arg_into_owned($arg_variable);
126+
let $arg_variable = $arg_variable.cow_into_owned();
106127
};
107128
}
108129

109130
#[macro_export]
110131
macro_rules! impl_asarg_by_value {
111132
($T:ty) => {
112-
impl $crate::meta::AsArg<$T> for $T {
113-
fn into_arg<'r>(self) -> <$T as $crate::meta::ParamType>::Arg<'r> {
114-
// Moves value (but typically a Copy type).
115-
self
116-
}
117-
}
118-
119133
impl $crate::meta::ParamType for $T {
120134
type Arg<'v> = $T;
121135

@@ -137,22 +151,6 @@ macro_rules! impl_asarg_by_value {
137151
#[macro_export]
138152
macro_rules! impl_asarg_by_ref {
139153
($T:ty) => {
140-
impl<'r> $crate::meta::AsArg<$T> for &'r $T {
141-
// 1 rustfmt + 1 rustc problems (bugs?) here:
142-
// - formatting doesn't converge; `where` keeps being further indented on each run.
143-
// - a #[rustfmt::skip] annotation over the macro causes a compile error when mentioning `crate::impl_asarg_by_ref`.
144-
// "macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"
145-
// Thus, keep `where` on same line.
146-
// type ArgType<'v> = &'v $T where Self: 'v;
147-
148-
fn into_arg<'cow>(self) -> <$T as $crate::meta::ParamType>::Arg<'cow>
149-
where
150-
'r: 'cow, // Original reference must be valid for at least as long as the returned cow.
151-
{
152-
$crate::meta::CowArg::Borrowed(self)
153-
}
154-
}
155-
156154
impl $crate::meta::ParamType for $T {
157155
type Arg<'v> = $crate::meta::CowArg<'v, $T>;
158156

@@ -199,7 +197,7 @@ macro_rules! declare_arg_method {
199197
/// This is necessary for packed array dispatching to different "inner" backend signatures.
200198
impl<T> AsArg<T> for CowArg<'_, T>
201199
where
202-
for<'r> T: ParamType<Arg<'r> = CowArg<'r, T>> + 'r,
200+
for<'r> T: ToGodot,
203201
{
204202
fn into_arg<'r>(self) -> CowArg<'r, T>
205203
where
@@ -273,7 +271,7 @@ impl AsArg<NodePath> for &String {
273271
/// Implemented for all parameter types `T` that are allowed to receive [impl `AsArg<T>`][AsArg].
274272
// ParamType used to be a subtrait of GodotType, but this can be too restrictive. For example, DynGd is not a "Godot canonical type"
275273
// (GodotType), however it's still useful to store it in arrays -- which requires AsArg and subsequently ParamType.
276-
pub trait ParamType: sealed::Sealed + Sized + 'static
274+
pub trait ParamType: sealed::Sealed + Sized + 'static + ToGodot
277275
// GodotType bound not required right now, but conceptually should always be the case.
278276
{
279277
/// Canonical argument passing type, either `T` or an internally-used CoW type.

godot-core/src/meta/args/cow_arg.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::meta::{FromGodot, GodotConvert, GodotFfiVariant, RefArg, ToGodot};
1111
use crate::sys;
1212
use godot_ffi::{GodotFfi, GodotNullableFfi, PtrcallType};
1313
use std::fmt;
14+
use std::ops::Deref;
1415

1516
/// Owned or borrowed value, used when passing arguments through `impl AsArg` to Godot APIs.
1617
#[doc(hidden)]
@@ -182,3 +183,14 @@ where
182183
self.cow_as_ref().is_null()
183184
}
184185
}
186+
187+
impl<T> Deref for CowArg<'_, T> {
188+
type Target = T;
189+
190+
fn deref(&self) -> &Self::Target {
191+
match self {
192+
CowArg::Owned(value) => value,
193+
CowArg::Borrowed(value) => value,
194+
}
195+
}
196+
}

godot-core/src/obj/dyn_gd.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -530,19 +530,6 @@ where
530530
}
531531
}
532532

533-
impl<'r, T, D> meta::AsArg<DynGd<T, D>> for &'r DynGd<T, D>
534-
where
535-
T: GodotClass,
536-
D: ?Sized + 'static,
537-
{
538-
fn into_arg<'cow>(self) -> meta::CowArg<'cow, DynGd<T, D>>
539-
where
540-
'r: 'cow, // Original reference must be valid for at least as long as the returned cow.
541-
{
542-
meta::CowArg::Borrowed(self)
543-
}
544-
}
545-
546533
/*
547534
// See `impl AsArg for Gd<T>` for why this isn't yet implemented.
548535
impl<'r, T, TBase, D> meta::AsArg<DynGd<TBase, D>> for &'r DynGd<T, D>

godot-core/src/obj/gd.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -842,16 +842,6 @@ impl<T: GodotClass> ArrayElement for Option<Gd<T>> {
842842
}
843843
}
844844

845-
impl<'r, T: GodotClass> AsArg<Gd<T>> for &'r Gd<T> {
846-
#[doc(hidden)] // Repeated despite already hidden in trait; some IDEs suggest this otherwise.
847-
fn into_arg<'cow>(self) -> CowArg<'cow, Gd<T>>
848-
where
849-
'r: 'cow, // Original reference must be valid for at least as long as the returned cow.
850-
{
851-
CowArg::Borrowed(self)
852-
}
853-
}
854-
855845
/*
856846
// TODO find a way to generalize AsArg to derived->base conversions without breaking type inference in array![].
857847
// Possibly we could use a "canonical type" with unambiguous mapping (&Gd<T> -> &Gd<T>, not &Gd<T> -> &Gd<TBase>).

itest/rust/src/builtin_tests/containers/signal_test.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ use crate::framework::itest;
99
use godot::builtin::{vslice, GString, Signal, StringName};
1010
use godot::classes::object::ConnectFlags;
1111
use godot::classes::{Node, Node3D, Object, RefCounted};
12-
use godot::meta::ToGodot;
12+
use godot::meta::{FromGodot, GodotConvert, ToGodot};
1313
use godot::obj::{Base, Gd, InstanceId, NewAlloc, NewGd};
14+
use godot::prelude::ConvertError;
1415
use godot::register::{godot_api, GodotClass};
1516
use godot::sys;
1617
use godot::sys::Global;
@@ -472,6 +473,55 @@ fn signal_construction_and_id() {
472473
assert_eq!(signal.object(), None);
473474
}
474475

476+
#[cfg(since_api = "4.2")]
477+
#[itest]
478+
fn enums_as_signal_args() {
479+
#[derive(Debug, Clone)]
480+
enum EventType {
481+
Ready,
482+
}
483+
484+
impl GodotConvert for EventType {
485+
type Via = u8;
486+
}
487+
488+
impl ToGodot for EventType {
489+
type ToVia<'v> = Self::Via;
490+
491+
fn to_godot(&self) -> Self::ToVia<'_> {
492+
match self {
493+
EventType::Ready => 0,
494+
}
495+
}
496+
}
497+
498+
impl FromGodot for EventType {
499+
fn try_from_godot(via: Self::Via) -> Result<Self, godot::prelude::ConvertError> {
500+
match via {
501+
0 => Ok(Self::Ready),
502+
_ => Err(ConvertError::new("value out of range")),
503+
}
504+
}
505+
}
506+
507+
#[derive(GodotClass)]
508+
#[class(base = RefCounted, init)]
509+
struct SignalObject {
510+
base: Base<RefCounted>,
511+
}
512+
513+
#[godot_api]
514+
impl SignalObject {
515+
#[signal]
516+
fn game_event(ty: EventType);
517+
}
518+
519+
let object = SignalObject::new_gd();
520+
let event = EventType::Ready;
521+
522+
object.signals().game_event().emit(&event);
523+
}
524+
475525
// ----------------------------------------------------------------------------------------------------------------------------------------------
476526
// Helper types
477527

0 commit comments

Comments
 (0)