@@ -11,6 +11,7 @@ use crate::builtin::{GString, NodePath, StringName, Variant};
11
11
use crate :: meta:: sealed:: Sealed ;
12
12
use crate :: meta:: traits:: GodotFfiVariant ;
13
13
use crate :: meta:: { CowArg , GodotType , ToGodot } ;
14
+ use crate :: obj:: { bounds, Bounds , DynGd , Gd , GodotClass , Inherits } ;
14
15
15
16
/// Implicit conversions for arguments passed to Godot APIs.
16
17
///
@@ -22,10 +23,8 @@ use crate::meta::{CowArg, GodotType, ToGodot};
22
23
/// - These all implement `ToGodot<Pass = ByValue>` and typically also `Copy`.
23
24
/// - `&T` for **by-ref** built-ins: `GString`, `Array`, `Dictionary`, `PackedArray`, `Variant`...
24
25
/// - These all implement `ToGodot<Pass = ByRef>`.
25
- /// - `&str`, `&String` additionally for string types `GString`, `StringName`, `NodePath`.
26
- ///
27
- /// See also the [`AsObjectArg`][crate::meta::AsObjectArg] trait which is specialized for object arguments. It may be merged with `AsArg`
28
- /// in the future.
26
+ /// - `&str`, `&String` additionally for string types `GString`, `StringName`, `NodePath`, see [String arguments](#string-arguments).
27
+ /// - `&Gd`, `Option<&Gd>` for objects, see [Object arguments](#object-arguments).
29
28
///
30
29
/// # Owned values vs. references
31
30
/// Implicitly converting from `T` for **by-ref** built-ins is explicitly not supported, i.e. you need to pass `&variant` instead of `variant`.
@@ -35,7 +34,14 @@ use crate::meta::{CowArg, GodotType, ToGodot};
35
34
/// Sometimes, you need exactly that for generic programming though: consistently pass `T` or `&T`. For this purpose, the global functions
36
35
/// [`owned_into_arg()`] and [`ref_to_arg()`] are provided.
37
36
///
38
- /// # Performance for strings
37
+ /// # Using the trait
38
+ /// `AsArg` is meant to be used from the function call site, not the declaration site. If you declare a parameter as `impl AsArg<...>` yourself,
39
+ /// you can only forward it as-is to a Godot API -- there are no stable APIs to access the inner object yet.
40
+ ///
41
+ /// The blanket implementations of `AsArg` for `T` (in case of `Pass = ByValue`) and `&T` (`Pass = ByRef`) should readily enable most use
42
+ /// cases, as long as your type already supports `ToGodot`. In the majority of cases, you'll simply use by-value passing, e.g. for enums.
43
+ ///
44
+ /// # String arguments
39
45
/// Godot has three string types: [`GString`], [`StringName`] and [`NodePath`]. Conversions between those three, as well as between `String` and
40
46
/// them, is generally expensive because of allocations, re-encoding, validations, hashing, etc. While this doesn't matter for a few strings
41
47
/// passed to engine APIs, it can become a problematic when passing long strings in a hot loop.
@@ -48,12 +54,29 @@ use crate::meta::{CowArg, GodotType, ToGodot};
48
54
/// If you want to convert between Godot's string types for the sake of argument passing, each type provides an `arg()` method, such as
49
55
/// [`GString::arg()`]. You cannot use this method in other contexts.
50
56
///
51
- /// # Using the trait
52
- /// `AsArg` is meant to be used from the function call site, not the declaration site. If you declare a parameter as `impl AsArg<...>` yourself,
53
- /// you can only forward it as-is to a Godot API -- there are no stable APIs to access the inner object yet.
57
+ /// # Object arguments
58
+ /// This section treats `AsArg<Gd<*>>`. The trait is implemented for **shared references** in multiple ways:
59
+ /// - [`&Gd<T>`][crate::obj::Gd] to pass objects. Subclasses of `T` are explicitly supported.
60
+ /// - [`Option<&Gd<T>>`][Option], to pass optional objects. `None` is mapped to a null argument.
61
+ /// - [`Gd::null_arg()`], to pass `null` arguments without using `Option`.
54
62
///
55
- /// The blanket implementations of `AsArg` for `T` (in case of `Pass = ByValue`) and `&T` (`Pass = ByRef`) should readily enable most use
56
- /// cases, as long as your type already supports `ToGodot`. In the majority of cases, you'll simply use by-value passing, e.g. for enums.
63
+ /// The following table lists the possible argument types and how you can pass them. `Gd` is short for `Gd<T>`.
64
+ ///
65
+ /// | Type | Closest accepted type | How to transform |
66
+ /// |-------------------|-----------------------|------------------|
67
+ /// | `Gd` | `&Gd` | `&arg` |
68
+ /// | `&Gd` | `&Gd` | `arg` |
69
+ /// | `&mut Gd` | `&Gd` | `&*arg` |
70
+ /// | `Option<Gd>` | `Option<&Gd>` | `arg.as_ref()` |
71
+ /// | `Option<&Gd>` | `Option<&Gd>` | `arg` |
72
+ /// | `Option<&mut Gd>` | `Option<&Gd>` | `arg.as_deref()` |
73
+ /// | (null literal) | | `Gd::null_arg()` |
74
+ ///
75
+ /// ## Nullability
76
+ /// <div class="warning">
77
+ /// The GDExtension API does not inform about nullability of its function parameters. It is up to you to verify that the arguments you pass
78
+ /// are only null when this is allowed. Doing this wrong should be safe, but can lead to the function call failing.
79
+ /// </div>
57
80
#[ diagnostic:: on_unimplemented(
58
81
message = "Argument of type `{Self}` cannot be passed to an `impl AsArg<{T}>` parameter" ,
59
82
note = "if you pass by value, consider borrowing instead." ,
@@ -97,6 +120,106 @@ where
97
120
}
98
121
}
99
122
123
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
124
+ // Object (Gd + DynGd) impls
125
+
126
+ // TODO(v0.4): all objects + optional objects should be pass-by-ref.
127
+
128
+ impl < T , Base > AsArg < Gd < Base > > for & Gd < T >
129
+ where
130
+ T : Inherits < Base > ,
131
+ Base : GodotClass ,
132
+ {
133
+ fn into_arg < ' r > ( self ) -> CowArg < ' r , Gd < Base > >
134
+ where
135
+ Self : ' r ,
136
+ {
137
+ CowArg :: Owned ( self . clone ( ) . upcast :: < Base > ( ) )
138
+ }
139
+ }
140
+
141
+ impl < T , U , D > AsArg < DynGd < T , D > > for & DynGd < U , D >
142
+ where
143
+ T : GodotClass ,
144
+ U : Inherits < T > ,
145
+ D : ?Sized ,
146
+ {
147
+ fn into_arg < ' r > ( self ) -> CowArg < ' r , DynGd < T , D > >
148
+ where
149
+ Self : ' r ,
150
+ {
151
+ CowArg :: Owned ( self . clone ( ) . upcast :: < T > ( ) )
152
+ }
153
+ }
154
+
155
+ // Convert DynGd -> Gd (with upcast).
156
+ impl < ' r , T , U , D > AsArg < Gd < T > > for & ' r DynGd < U , D >
157
+ where
158
+ T : GodotClass ,
159
+ U : Inherits < T > ,
160
+ D : ?Sized ,
161
+ {
162
+ fn into_arg < ' cow > ( self ) -> CowArg < ' cow , Gd < T > >
163
+ where
164
+ ' r : ' cow ,
165
+ {
166
+ CowArg :: Owned ( self . clone ( ) . upcast :: < T > ( ) . into_gd ( ) )
167
+ }
168
+ }
169
+
170
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
171
+ // Optional object (Gd + DynGd) impls
172
+
173
+ impl < T , U > AsArg < Option < Gd < T > > > for & Option < Gd < U > >
174
+ where
175
+ T : GodotClass + Bounds < Declarer = bounds:: DeclEngine > ,
176
+ U : Inherits < T > ,
177
+ {
178
+ fn into_arg < ' r > ( self ) -> CowArg < ' r , Option < Gd < T > > > {
179
+ match self {
180
+ Some ( gd) => CowArg :: Owned ( Some ( gd. clone ( ) . upcast :: < T > ( ) ) ) ,
181
+ None => CowArg :: Owned ( None ) ,
182
+ }
183
+ }
184
+ }
185
+
186
+ impl < T , U > AsArg < Option < Gd < T > > > for Option < & Gd < U > >
187
+ where
188
+ T : GodotClass + Bounds < Declarer = bounds:: DeclEngine > ,
189
+ U : Inherits < T > ,
190
+ {
191
+ fn into_arg < ' cow > ( self ) -> CowArg < ' cow , Option < Gd < T > > > {
192
+ // This needs to construct a new Option<Gd<T>>, so cloning is unavoidable
193
+ // since we go from Option<&Gd<U>> to Option<Gd<T>>
194
+ match self {
195
+ Some ( gd) => CowArg :: Owned ( Some ( gd. clone ( ) . upcast :: < T > ( ) ) ) ,
196
+ None => CowArg :: Owned ( None ) ,
197
+ }
198
+ }
199
+ }
200
+
201
+ impl < T , U > AsArg < Option < Gd < T > > > for & Gd < U >
202
+ where
203
+ T : GodotClass + Bounds < Declarer = bounds:: DeclEngine > ,
204
+ U : Inherits < T > ,
205
+ {
206
+ fn into_arg < ' cow > ( self ) -> CowArg < ' cow , Option < Gd < T > > > {
207
+ CowArg :: Owned ( Some ( self . clone ( ) . upcast :: < T > ( ) ) )
208
+ }
209
+ }
210
+
211
+ impl < T , U , D > AsArg < Option < Gd < T > > > for & DynGd < U , D >
212
+ where
213
+ T : GodotClass + Bounds < Declarer = bounds:: DeclEngine > ,
214
+ U : Inherits < T > ,
215
+ D : ?Sized ,
216
+ {
217
+ fn into_arg < ' cow > ( self ) -> CowArg < ' cow , Option < Gd < T > > > {
218
+ let gd: & Gd < U > = self ; // Deref
219
+ CowArg :: Owned ( Some ( gd. clone ( ) . upcast :: < T > ( ) ) )
220
+ }
221
+ }
222
+
100
223
// ----------------------------------------------------------------------------------------------------------------------------------------------
101
224
// Public helper functions (T|&T -> AsArg)
102
225
0 commit comments