6
6
*/
7
7
8
8
use crate :: builtin:: { GString , NodePath , StringName } ;
9
- use crate :: meta:: { sealed, CowArg } ;
9
+ use crate :: meta:: sealed:: Sealed ;
10
+ use crate :: meta:: { CowArg , ToGodot } ;
10
11
use std:: ffi:: CStr ;
11
12
12
13
/// Implicit conversions for arguments passed to Godot APIs.
@@ -15,19 +16,17 @@ use std::ffi::CStr;
15
16
/// this trait is implemented more conservatively.
16
17
///
17
18
/// As a result, `AsArg<T>` is currently only implemented for certain argument types:
18
- /// - `T` for by-value builtins (typically `Copy`): `i32`, `bool`, `Vector3`, `Transform2D`, ...
19
- /// - `&T` for by-ref builtins : `GString`, `Array`, `Dictionary`, `Packed*Array`, `Variant`...
19
+ /// - `T` for by-value built-ins (typically `Copy`): `i32`, `bool`, `Vector3`, `Transform2D`, ...
20
+ /// - `&T` for by-ref built-ins : `GString`, `Array`, `Dictionary`, `Packed*Array`, `Variant`...
20
21
/// - `&str`, `&String` additionally for string types `GString`, `StringName`, `NodePath`.
21
22
///
22
23
/// See also the [`AsObjectArg`][crate::meta::AsObjectArg] trait which is specialized for object arguments. It may be merged with `AsArg`
23
24
/// in the future.
24
25
///
25
26
/// # Pass by value
26
- /// Implicitly converting from `T` for by-ref builtins is explicitly not supported. This emphasizes that there is no need to consume the object,
27
+ /// Implicitly converting from `T` for by-ref built-ins is explicitly not supported. This emphasizes that there is no need to consume the object,
27
28
/// thus discourages unnecessary cloning.
28
29
///
29
- /// If you need to pass owned values in generic code, you can use [`ParamType::owned_to_arg()`].
30
- ///
31
30
/// # Performance for strings
32
31
/// Godot has three string types: [`GString`], [`StringName`] and [`NodePath`]. Conversions between those three, as well as between `String` and
33
32
/// them, is generally expensive because of allocations, re-encoding, validations, hashing, etc. While this doesn't matter for a few strings
@@ -45,24 +44,59 @@ use std::ffi::CStr;
45
44
/// `AsArg` is meant to be used from the function call site, not the declaration site. If you declare a parameter as `impl AsArg<...>` yourself,
46
45
/// you can only forward it as-is to a Godot API -- there are no stable APIs to access the inner object yet.
47
46
///
48
- /// Furthermore, there is currently no benefit in implementing `AsArg` for your own types, as it's only used by Godot APIs which don't accept
49
- /// custom types. Classes are already supported through upcasting and [`AsObjectArg`][crate::meta::AsObjectArg].
47
+ /// If you want to pass your own types to a Godot API i.e. to emit a signal, you should implement the [`ParamType`] trait.
50
48
#[ diagnostic:: on_unimplemented(
51
49
message = "Argument of type `{Self}` cannot be passed to an `impl AsArg<{T}>` parameter" ,
52
50
note = "if you pass by value, consider borrowing instead." ,
53
51
note = "GString/StringName/NodePath aren't implicitly convertible for performance reasons; use their `arg()` method." ,
54
52
note = "see also `AsArg` docs: https://godot-rust.github.io/docs/gdext/master/godot/meta/trait.AsArg.html"
55
53
) ]
56
- pub trait AsArg < T : ParamType >
54
+ pub trait AsArg < T : ToGodot >
57
55
where
58
56
Self : Sized ,
59
57
{
58
+ // The usage of the CowArg return type introduces a small runtime penalty for values that implement Copy. Currently, the usage
59
+ // ergonomics out weigh the runtime cost. Using the CowArg allows us to create a blanket implementation of the trait for all types that
60
+ // implement ToGodot.
60
61
#[ doc( hidden) ]
61
- fn into_arg < ' r > ( self ) -> < T as ParamType > :: Arg < ' r >
62
+ fn into_arg < ' r > ( self ) -> CowArg < ' r , T >
62
63
where
63
64
Self : ' r ;
64
65
}
65
66
67
+ /// Generic abstraction over `T` and `&T` that should be passed as `AsArg<T>`.
68
+ #[ doc( hidden) ]
69
+ pub fn val_into_arg < ' r , T > ( arg : T ) -> impl AsArg < T > + ' r
70
+ where
71
+ T : ToGodot + ' r ,
72
+ {
73
+ CowArg :: Owned ( arg)
74
+ }
75
+
76
+ impl < T > AsArg < T > for & T
77
+ where
78
+ T : ToGodot + ParamType < ArgPassing = ByRef > ,
79
+ {
80
+ fn into_arg < ' r > ( self ) -> CowArg < ' r , T >
81
+ where
82
+ Self : ' r ,
83
+ {
84
+ CowArg :: Borrowed ( self )
85
+ }
86
+ }
87
+
88
+ impl < T > AsArg < T > for T
89
+ where
90
+ T : ToGodot + ParamType < ArgPassing = ByValue > ,
91
+ {
92
+ fn into_arg < ' r > ( self ) -> CowArg < ' r , T >
93
+ where
94
+ Self : ' r ,
95
+ {
96
+ CowArg :: Owned ( self )
97
+ }
98
+ }
99
+
66
100
// ----------------------------------------------------------------------------------------------------------------------------------------------
67
101
// Blanket impls
68
102
@@ -81,7 +115,7 @@ macro_rules! arg_into_ref {
81
115
} ;
82
116
( $arg_variable: ident: $T: ty) => {
83
117
let $arg_variable = $arg_variable. into_arg( ) ;
84
- let $arg_variable: & $T = $crate :: meta :: ParamType :: arg_to_ref ( & $ arg_variable) ;
118
+ let $arg_variable: & $T = $arg_variable. cow_as_ref ( ) ;
85
119
} ;
86
120
}
87
121
@@ -102,71 +136,24 @@ macro_rules! arg_into_owned {
102
136
} ;
103
137
( infer $arg_variable: ident) => {
104
138
let $arg_variable = $arg_variable. into_arg( ) ;
105
- let $arg_variable = $crate :: meta :: ParamType :: arg_into_owned ( $ arg_variable) ;
139
+ let $arg_variable = $arg_variable. cow_into_owned ( ) ;
106
140
} ;
107
141
}
108
142
109
143
#[ macro_export]
110
144
macro_rules! impl_asarg_by_value {
111
145
( $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
-
119
146
impl $crate:: meta:: ParamType for $T {
120
- type Arg <' v> = $T;
121
-
122
- fn owned_to_arg<' v>( self ) -> Self :: Arg <' v> {
123
- self
124
- }
125
-
126
- fn arg_to_ref<' r>( arg: & ' r Self :: Arg <' _>) -> & ' r Self {
127
- arg
128
- }
129
-
130
- fn arg_into_owned( arg: Self :: Arg <' _>) -> Self {
131
- arg
132
- }
147
+ type ArgPassing = $crate:: meta:: ByValue ;
133
148
}
134
149
} ;
135
150
}
136
151
137
152
#[ macro_export]
138
153
macro_rules! impl_asarg_by_ref {
139
154
( $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
-
156
155
impl $crate:: meta:: ParamType for $T {
157
- type Arg <' v> = $crate:: meta:: CowArg <' v, $T>;
158
-
159
- fn owned_to_arg<' v>( self ) -> Self :: Arg <' v> {
160
- $crate:: meta:: CowArg :: Owned ( self )
161
- }
162
-
163
- fn arg_to_ref<' r>( arg: & ' r Self :: Arg <' _>) -> & ' r Self {
164
- arg. cow_as_ref( )
165
- }
166
-
167
- fn arg_into_owned( arg: Self :: Arg <' _>) -> Self {
168
- arg. cow_into_owned( )
169
- }
156
+ type ArgPassing = $crate:: meta:: ByRef ;
170
157
}
171
158
} ;
172
159
}
@@ -182,7 +169,7 @@ macro_rules! declare_arg_method {
182
169
pub fn arg<T >( & self ) -> impl $crate:: meta:: AsArg <T >
183
170
where
184
171
for <' a> T : From <& ' a Self >
185
- + $crate:: meta:: ParamType < Arg < ' a> = $crate :: meta :: CowArg < ' a , T >>
172
+ + $crate:: meta:: ToGodot
186
173
+ ' a,
187
174
{
188
175
$crate:: meta:: CowArg :: Owned ( T :: from( self ) )
@@ -199,7 +186,7 @@ macro_rules! declare_arg_method {
199
186
/// This is necessary for packed array dispatching to different "inner" backend signatures.
200
187
impl < T > AsArg < T > for CowArg < ' _ , T >
201
188
where
202
- for < ' r > T : ParamType < Arg < ' r > = CowArg < ' r , T > > + ' r ,
189
+ for < ' r > T : ToGodot ,
203
190
{
204
191
fn into_arg < ' r > ( self ) -> CowArg < ' r , T >
205
192
where
@@ -271,37 +258,37 @@ impl AsArg<NodePath> for &String {
271
258
// ----------------------------------------------------------------------------------------------------------------------------------------------
272
259
273
260
/// Implemented for all parameter types `T` that are allowed to receive [impl `AsArg<T>`][AsArg].
261
+ ///
262
+ /// **Deprecated**: This trait is considered deprecated and will be removed in 0.4. It is still required to be implemented by types that should
263
+ /// be passed `AsArg` in the current version, though.
264
+ //
274
265
// ParamType used to be a subtrait of GodotType, but this can be too restrictive. For example, DynGd is not a "Godot canonical type"
275
266
// (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
267
+ //
268
+ // TODO(v0.4): merge ParamType::ArgPassing into ToGodot::ToVia, reducing redundancy on user side.
269
+ pub trait ParamType : ToGodot + Sized + ' static
277
270
// GodotType bound not required right now, but conceptually should always be the case.
278
271
{
279
- /// Canonical argument passing type, either `T` or an internally-used CoW type.
280
- ///
281
- /// The general rule is that `Copy` types are passed by value, while the rest is passed by reference.
282
- ///
283
- /// This associated type is closely related to [`ToGodot::ToVia<'v>`][crate::meta::ToGodot::ToVia] and may be reorganized in the future.
284
- #[ doc( hidden) ]
285
- type Arg < ' v > : AsArg < Self >
286
- where
287
- Self : ' v ;
288
-
289
- /// Converts an owned value to the canonical argument type, which can be passed to [`impl AsArg<T>`][AsArg].
290
- ///
291
- /// Useful in generic contexts where only a value is available, and one doesn't want to dispatch between value/reference.
292
- ///
293
- /// You should not rely on the exact return type, as it may change in future versions; treat it like `impl AsArg<Self>`.
294
- fn owned_to_arg < ' v > ( self ) -> Self :: Arg < ' v > ;
295
-
296
- /// Converts an argument to a shared reference.
297
- ///
298
- /// Useful in generic contexts where you need to extract a reference of an argument, independently of how it is passed.
299
- #[ doc( hidden) ] // for now, users are encouraged to use only call-site of impl AsArg; declaration-site may still develop.
300
- fn arg_to_ref < ' r > ( arg : & ' r Self :: Arg < ' _ > ) -> & ' r Self ;
301
-
302
- /// Clones an argument into an owned value.
303
- ///
304
- /// Useful in generic contexts where you need to extract a value of an argument, independently of how it is passed.
305
- #[ doc( hidden) ] // for now, users are encouraged to use only call-site of impl AsArg; declaration-site may still develop.
306
- fn arg_into_owned ( arg : Self :: Arg < ' _ > ) -> Self ;
272
+ type ArgPassing : ArgPassing ;
273
+
274
+ #[ deprecated(
275
+ since = "0.3.2" ,
276
+ note = "This method is no longer needed and will be removed in 0.4"
277
+ ) ]
278
+ fn owned_to_arg ( self ) -> impl AsArg < Self > {
279
+ val_into_arg ( self )
280
+ }
307
281
}
282
+
283
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
284
+ // Argument passing (mutually exclusive by-val or by-ref).
285
+
286
+ pub trait ArgPassing : Sealed { }
287
+
288
+ pub enum ByValue { }
289
+ impl ArgPassing for ByValue { }
290
+ impl Sealed for ByValue { }
291
+
292
+ pub enum ByRef { }
293
+ impl ArgPassing for ByRef { }
294
+ impl Sealed for ByRef { }
0 commit comments