godot_core/meta/args/as_arg.rs
1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use crate::builtin::{Callable, GString, NodePath, Signal, StringName, Variant};
9use crate::meta::sealed::Sealed;
10use crate::meta::traits::{Element, GodotFfiVariant, GodotNullableFfi, PackedElement};
11use crate::meta::{CowArg, EngineToGodot, FfiArg, GodotType, ObjectArg, ToGodot};
12use crate::obj::{DynGd, Gd, GodotClass, Inherits};
13
14/// Implicit conversions for arguments passed to Godot APIs.
15///
16/// An `impl AsArg<T>` parameter allows values to be passed which can be represented in the target type `T`. Note that unlike `From<T>`,
17/// this trait is implemented more conservatively.
18///
19/// As a result, `AsArg<T>` is currently only implemented for certain argument types:
20/// - `T` for **by-value** built-ins: `i32`, `bool`, `Vector3`, `Transform2D`...
21/// - These all implement `ToGodot<Pass = ByValue>` and typically also `Copy`.
22/// - `&T` for **by-ref** built-ins: `GString`, `Array`, `Dictionary`, `PackedArray`, `Variant`...
23/// - These all implement `ToGodot<Pass = ByRef>`.
24/// - `&str`, `&String` additionally for string types `GString`, `StringName`, `NodePath`, see [String arguments](#string-arguments).
25/// - `&Gd`, `Option<&Gd>` for objects, see [Object arguments](#object-arguments).
26///
27/// # Owned values vs. references
28/// Implicitly converting from `T` for **by-ref** built-ins is explicitly not supported, i.e. you need to pass `&variant` instead of `variant`.
29/// This emphasizes that there is no need to consume the object, thus discourages unnecessary cloning. Similarly, you cannot pass by-value
30/// types like `i32` by reference.
31///
32/// Sometimes, you need exactly that for generic programming though: consistently pass `T` or `&T`. For this purpose, the global functions
33/// [`owned_into_arg()`] and [`ref_to_arg()`] are provided.
34///
35/// # Using the trait
36/// `AsArg` is meant to be used from the function call site, not the declaration site. If you declare a parameter as `impl AsArg<...>` yourself,
37/// you can only forward it as-is to a Godot API -- there are no stable APIs to access the inner object yet.
38///
39/// The blanket implementations of `AsArg` for `T` (in case of `Pass = ByValue`) and `&T` (`Pass = ByRef`) should readily enable most use
40/// 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.
41///
42/// # String arguments
43/// Godot has three string types: [`GString`], [`StringName`] and [`NodePath`]. Conversions between those three, as well as between `String` and
44/// them, is generally expensive because of allocations, re-encoding, validations, hashing, etc. While this doesn't matter for a few strings
45/// passed to engine APIs, it can become a problematic when passing long strings in a hot loop.
46///
47/// In the case of strings, we allow implicit conversion from Rust types `&str`, `&String` and `&'static CStr` (`StringName` only).
48/// While these conversions are not free, those are either explicit because a string literal is used, or they are unsurprising, because Godot
49/// cannot deal with raw Rust types. On the other hand, `GString` and `StringName` are sometimes used almost interchangeably (example:
50/// [`Node::set_name`](crate::classes::Node::set_name) takes `GString` but [`Node::get_name`](crate::classes::Node::get_name) returns `StringName`).
51///
52/// If you want to convert between Godot's string types for the sake of argument passing, use the `From` conversions, e.g.
53/// `GString::from(&string_name)`.
54///
55/// # Object arguments
56/// This section treats `AsArg<Gd<*>>`. The trait is implemented for **shared references** in multiple ways:
57/// - [`&Gd<T>`][crate::obj::Gd] to pass objects. Subclasses of `T` are explicitly supported.
58/// - [`Option<&Gd<T>>`][Option], to pass optional objects. `None` is mapped to a null argument.
59/// - [`Gd::null_arg()`], to pass `null` arguments without using `Option`.
60///
61/// The following table lists the possible argument types and how you can pass them. `Gd` is short for `Gd<T>`.
62///
63/// | Type | Closest accepted type | How to transform |
64/// |-------------------|-----------------------|------------------|
65/// | `Gd` | `&Gd` | `&arg` |
66/// | `&Gd` | `&Gd` | `arg` |
67/// | `&mut Gd` | `&Gd` | `&*arg` |
68/// | `Option<Gd>` | `Option<&Gd>` | `arg.as_ref()` |
69/// | `Option<&Gd>` | `Option<&Gd>` | `arg` |
70/// | `Option<&mut Gd>` | `Option<&Gd>` | `arg.as_deref()` |
71/// | (null literal) | | `Gd::null_arg()` |
72///
73/// ## Nullability
74/// <div class="warning">
75/// The GDExtension API does not inform about nullability of its function parameters. It is up to you to verify that the arguments you pass
76/// are only null when this is allowed. Doing this wrong should be safe, but can lead to the function call failing.
77/// </div>
78#[diagnostic::on_unimplemented(
79 message = "Argument of type `{Self}` cannot be passed to an `impl AsArg<{T}>` parameter",
80 note = "if you pass by value, consider borrowing instead.",
81 note = "GString/StringName/NodePath aren't implicitly convertible for performance reasons; use `From` conversions.",
82 note = "see also `AsArg` docs: https://godot-rust.github.io/docs/gdext/master/godot/meta/trait.AsArg.html"
83)]
84pub trait AsArg<T: ToGodot>
85where
86 Self: Sized,
87{
88 // The usage of the CowArg return type introduces a small runtime penalty for values that implement Copy. Currently, the usage
89 // ergonomics out weigh the runtime cost. Using the CowArg allows us to create a blanket implementation of the trait for all types that
90 // implement ToGodot.
91 #[doc(hidden)]
92 fn into_arg<'arg>(self) -> CowArg<'arg, T>
93 where
94 Self: 'arg;
95
96 /// FFI-optimized argument conversion that may use `FfiObject` when beneficial.
97 ///
98 /// Defaults to calling `into_arg()` and wrapping in `FfiArg::Cow()`, which always works, but might be an `Owned` for a conservative
99 /// approach (e.g. object upcast).
100 #[doc(hidden)]
101 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, T>
102 where
103 Self: 'arg,
104 {
105 FfiArg::Cow(self.into_arg())
106 }
107}
108
109impl<T> AsArg<T> for &T
110where
111 T: ToGodot<Pass = ByRef>,
112{
113 fn into_arg<'arg>(self) -> CowArg<'arg, T>
114 where
115 Self: 'arg,
116 {
117 CowArg::Borrowed(self)
118 }
119}
120
121// Variant has `Pass = ByVariant` (not ByRef), so it's not covered by the ByRef blanket above.
122impl AsArg<Variant> for &Variant {
123 fn into_arg<'arg>(self) -> CowArg<'arg, Variant>
124 where
125 Self: 'arg,
126 {
127 CowArg::Borrowed(self)
128 }
129}
130
131impl<T> AsArg<T> for T
132where
133 T: ToGodot<Pass = ByValue> + Sized, // Sized may rule out some coherence issues.
134{
135 fn into_arg<'arg>(self) -> CowArg<'arg, T>
136 where
137 Self: 'arg,
138 {
139 CowArg::Owned(self)
140 }
141}
142
143// ----------------------------------------------------------------------------------------------------------------------------------------------
144// Object (Gd + DynGd) impls
145
146// Convert `Gd` -> `Gd` (with upcast).
147impl<T, Base> AsArg<Gd<Base>> for &Gd<T>
148where
149 T: Inherits<Base>,
150 Base: GodotClass,
151{
152 //noinspection RsConstantConditionIf - false positive in IDE for `T::IS_SAME_CLASS`.
153 fn into_arg<'arg>(self) -> CowArg<'arg, Gd<Base>>
154 where
155 Self: 'arg,
156 {
157 if T::IS_SAME_CLASS {
158 // SAFETY: T == Base, so &Gd<T> can be treated as &Gd<Base>.
159 let gd_ref = unsafe { std::mem::transmute::<&Gd<T>, &Gd<Base>>(self) };
160 CowArg::Borrowed(gd_ref)
161 } else {
162 // Different types: clone and upcast. May incur ref-count increment for RefCounted objects, but the common path
163 // of FFI passing is already optimized.
164 CowArg::Owned(self.clone().upcast())
165 }
166 }
167
168 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Gd<Base>>
169 where
170 Self: 'arg,
171 {
172 let arg = ObjectArg::from_gd(self);
173 FfiArg::FfiObject(arg)
174 }
175}
176
177/// Convert `DynGd` -> `DynGd` (with upcast).
178impl<T, D, Base> AsArg<DynGd<Base, D>> for &DynGd<T, D>
179where
180 T: Inherits<Base>,
181 D: ?Sized,
182 Base: GodotClass,
183{
184 //noinspection RsConstantConditionIf - false positive in IDE for `T::IS_SAME_CLASS`.
185 fn into_arg<'arg>(self) -> CowArg<'arg, DynGd<Base, D>>
186 where
187 Self: 'arg,
188 {
189 if T::IS_SAME_CLASS {
190 // SAFETY: T == Base, so &DynGd<T, D> can be treated as &DynGd<Base, D>.
191 let gd_ref = unsafe { std::mem::transmute::<&DynGd<T, D>, &DynGd<Base, D>>(self) };
192 CowArg::Borrowed(gd_ref)
193 } else {
194 // Different types: clone and upcast. May incur ref-count increment for RefCounted objects, but the common path
195 // of FFI passing is already optimized.
196 CowArg::Owned(self.clone().upcast())
197 }
198 }
199
200 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, DynGd<Base, D>>
201 where
202 Self: 'arg,
203 {
204 let arg = ObjectArg::from_gd(self);
205 FfiArg::FfiObject(arg)
206 }
207}
208
209/// Convert `DynGd` -> `Gd` (with upcast).
210impl<T, D, Base> AsArg<Gd<Base>> for &DynGd<T, D>
211where
212 T: Inherits<Base>,
213 D: ?Sized,
214 Base: GodotClass,
215{
216 fn into_arg<'arg>(self) -> CowArg<'arg, Gd<Base>>
217 where
218 Self: 'arg,
219 {
220 let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
221 AsArg::into_arg(gd_ref)
222 }
223
224 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Gd<Base>>
225 where
226 Self: 'arg,
227 {
228 let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
229 AsArg::into_ffi_arg(gd_ref)
230 }
231}
232
233// ----------------------------------------------------------------------------------------------------------------------------------------------
234// Null arguments
235
236/// Private struct for passing null arguments to optional object parameters.
237///
238/// This struct implements `AsArg` for both `Option<Gd<T>>` and `Option<DynGd<T, D>>`, allowing [`Gd::null_arg()`] and [`DynGd::null_arg()`]
239/// to share implementation.
240///
241/// Not public, as `impl AsArg<...>` is used by `null_arg()` methods.
242pub(crate) struct NullArg<T>(pub std::marker::PhantomData<*mut T>);
243
244impl<T> AsArg<Option<Gd<T>>> for NullArg<T>
245where
246 T: GodotClass,
247{
248 fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<T>>>
249 where
250 Self: 'arg,
251 {
252 CowArg::Owned(None)
253 }
254}
255
256impl<T, D> AsArg<Option<DynGd<T, D>>> for NullArg<T>
257where
258 T: GodotClass,
259 D: ?Sized + 'static,
260{
261 fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<T, D>>>
262 where
263 Self: 'arg,
264 {
265 CowArg::Owned(None)
266 }
267}
268
269// ----------------------------------------------------------------------------------------------------------------------------------------------
270// Optional object (Gd + DynGd) impls
271
272/// Convert `&Gd` -> `Option<Gd>` (with upcast).
273impl<T, Base> AsArg<Option<Gd<Base>>> for &Gd<T>
274where
275 T: Inherits<Base>,
276 Base: GodotClass,
277{
278 fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
279 where
280 Self: 'arg,
281 {
282 // Upcasting to an owned value Gd<Base> requires cloning. Optimized path in into_ffi_arg().
283 CowArg::Owned(Some(self.clone().upcast::<Base>()))
284 }
285
286 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
287 where
288 Self: 'arg,
289 {
290 let arg = ObjectArg::from_gd(self);
291 FfiArg::FfiObject(arg)
292 }
293}
294
295/// Convert `Option<&Gd>` -> `Option<Gd>` (with upcast).
296impl<T, Base> AsArg<Option<Gd<Base>>> for Option<&Gd<T>>
297where
298 T: Inherits<Base>,
299 Base: GodotClass,
300{
301 fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
302 where
303 Self: 'arg,
304 {
305 // Upcasting to an owned value Gd<Base> requires cloning. Optimized path in into_ffi_arg().
306 match self {
307 Some(gd_ref) => AsArg::into_arg(gd_ref),
308 None => CowArg::Owned(None),
309 }
310 }
311
312 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
313 where
314 Self: 'arg,
315 {
316 let arg = ObjectArg::from_option_gd(self);
317 FfiArg::FfiObject(arg)
318 }
319}
320
321/// Convert `&DynGd` -> `Option<DynGd>` (with upcast).
322impl<T, D, Base> AsArg<Option<DynGd<Base, D>>> for &DynGd<T, D>
323where
324 T: Inherits<Base>,
325 D: ?Sized,
326 Base: GodotClass,
327{
328 fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<Base, D>>>
329 where
330 Self: 'arg,
331 {
332 // Upcasting to an owned value DynGd<Base, D> requires cloning. Optimized path in into_ffi_arg().
333 CowArg::Owned(Some(self.clone().upcast()))
334 }
335
336 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<DynGd<Base, D>>>
337 where
338 Self: 'arg,
339 {
340 let arg = ObjectArg::from_gd(self);
341 FfiArg::FfiObject(arg)
342 }
343}
344
345/// Convert `&DynGd` -> `Option<Gd>` (with upcast).
346impl<T, D, Base> AsArg<Option<Gd<Base>>> for &DynGd<T, D>
347where
348 T: Inherits<Base>,
349 D: ?Sized,
350 Base: GodotClass,
351{
352 fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
353 where
354 Self: 'arg,
355 {
356 let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
357 AsArg::into_arg(gd_ref)
358 }
359
360 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
361 where
362 Self: 'arg,
363 {
364 let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
365 AsArg::into_ffi_arg(gd_ref)
366 }
367}
368
369/// Convert `Option<&DynGd>` -> `Option<DynGd>` (with upcast).
370impl<T, D, Base> AsArg<Option<DynGd<Base, D>>> for Option<&DynGd<T, D>>
371where
372 T: Inherits<Base>,
373 D: ?Sized,
374 Base: GodotClass,
375{
376 fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<Base, D>>>
377 where
378 Self: 'arg,
379 {
380 // Upcasting to an owned value Gd<Base> requires cloning. Optimized path in into_ffi_arg().
381 match self {
382 Some(gd_ref) => AsArg::into_arg(gd_ref),
383 None => CowArg::Owned(None),
384 }
385 }
386
387 fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<DynGd<Base, D>>>
388 where
389 Self: 'arg,
390 {
391 let option_gd: Option<&Gd<T>> = self.map(|v| &**v); // as_deref() not working.
392 let arg = ObjectArg::from_option_gd(option_gd);
393 FfiArg::FfiObject(arg)
394 }
395}
396
397// ----------------------------------------------------------------------------------------------------------------------------------------------
398// Public helper functions (T|&T -> AsArg)
399
400/// Generic abstraction over `T` owned values that should be passed as `AsArg<T>`.
401///
402/// Useful for generic programming: you have owned values, and want the argument conversion to benefit from moving whenever possible.
403/// You don't care if the value can truly be moved efficiently, since you don't need the value at the call site anymore.
404///
405/// Note that the pattern `owned_into_arg(value.clone())` is inefficient -- instead, use [`ref_to_arg(&value)`][ref_to_arg].
406///
407/// # Example
408/// ```
409/// use godot::prelude::*;
410/// use godot::meta::{Element, owned_into_arg};
411///
412/// // Creates random values, e.g. for fuzzing, property-based testing, etc.
413/// // Assume global state for simplicity.
414/// trait Generator {
415/// fn next() -> Self;
416/// }
417///
418/// fn fill_randomly<T>(arr: &mut Array<T>, count: usize)
419/// where
420/// T: Element + ToGodot + Generator,
421/// {
422/// for _ in 0..count {
423/// let value = T::next();
424/// arr.push(owned_into_arg(value));
425/// }
426/// }
427/// ```
428pub fn owned_into_arg<'arg, T>(owned_val: T) -> impl AsArg<T> + 'arg
429where
430 T: ToGodot + 'arg,
431{
432 CowArg::Owned(owned_val)
433}
434
435/// Generic abstraction over `&T` references that should be passed as `AsArg<T>`.
436///
437/// Useful for generic programming: you have references, and want the argument conversion to benefit from borrowing whenever possible.
438///
439/// If you no longer need the value at the call site, consider using [`owned_into_arg(value)`][owned_into_arg] instead.
440///
441/// # Example
442/// ```
443/// use godot::prelude::*;
444/// use godot::meta::{Element, ref_to_arg};
445///
446/// // Could use `impl AsArg<T>` and forward it, but let's demonstrate `&T` here.
447/// fn log_and_push<T>(arr: &mut Array<T>, value: &T)
448/// where
449/// T: Element + ToGodot + std::fmt::Debug,
450/// {
451/// println!("Add value: {value:?}");
452/// arr.push(ref_to_arg(value));
453/// }
454/// ```
455pub fn ref_to_arg<'r, T>(ref_val: &'r T) -> impl AsArg<T> + 'r
456where
457 T: ToGodot + 'r,
458{
459 CowArg::Borrowed(ref_val)
460}
461
462// ----------------------------------------------------------------------------------------------------------------------------------------------
463// Internal helper macros (AsArg -> &T|T)
464
465/// Converts `impl AsArg<T>` into a locally valid `&T`.
466///
467/// This cannot be done via function, since an intermediate variable (the Cow) is needed, which would go out of scope
468/// once the reference is returned. Could use more fancy syntax like `arg_into_ref! { let path = ref; }` or `let path = arg_into_ref!(path)`,
469/// but still isn't obvious enough to avoid doc lookup and might give a wrong idea about the scope. So being more exotic is a feature.
470#[macro_export]
471#[doc(hidden)] // Doesn't work at re-export.
472macro_rules! arg_into_ref {
473 ($arg_variable:ident) => {
474 // Non-generic version allows type inference. Only applicable for CowArg types.
475 let $arg_variable = $arg_variable.into_arg();
476 let $arg_variable = $arg_variable.cow_as_ref();
477 };
478 ($arg_variable:ident: $T:ty) => {
479 let $arg_variable = $arg_variable.into_arg();
480 let $arg_variable: &$T = $arg_variable.cow_as_ref();
481 };
482}
483
484/// Converts `impl AsArg<T>` into a locally valid `T`.
485///
486/// A macro for consistency with [`arg_into_ref`][crate::arg_into_ref].
487#[macro_export]
488#[doc(hidden)] // Doesn't work at re-export.
489macro_rules! arg_into_owned {
490 ($arg_variable:ident) => {
491 // Non-generic version allows type inference. Only applicable for CowArg types.
492 let $arg_variable = $arg_variable.into_arg();
493 let $arg_variable = $arg_variable.cow_into_owned();
494 };
495 (infer $arg_variable:ident) => {
496 let $arg_variable = $arg_variable.into_arg();
497 let $arg_variable = $arg_variable.cow_into_owned();
498 };
499}
500
501// ----------------------------------------------------------------------------------------------------------------------------------------------
502// CowArg
503
504/// `CowArg` can itself be passed as an argument (internal only).
505///
506/// Allows forwarding of `impl AsArg<T>` arguments to both another signature of `impl AsArg<T>` and signature of `T` for `Copy` types.
507/// This is necessary for packed array dispatching to different "inner" backend signatures.
508impl<T> AsArg<T> for CowArg<'_, T>
509where
510 for<'r> T: ToGodot,
511{
512 fn into_arg<'arg>(self) -> CowArg<'arg, T>
513 where
514 Self: 'arg,
515 {
516 self
517 }
518}
519
520// ----------------------------------------------------------------------------------------------------------------------------------------------
521// GString
522
523macro_rules! impl_asarg_string {
524 ($Target:ty) => {
525 impl AsArg<$Target> for &str {
526 fn into_arg<'arg>(self) -> CowArg<'arg, $Target> {
527 CowArg::Owned(<$Target>::from(self))
528 }
529 }
530 impl AsArg<$Target> for &String {
531 fn into_arg<'arg>(self) -> CowArg<'arg, $Target> {
532 CowArg::Owned(<$Target>::from(self.as_str()))
533 }
534 }
535 };
536}
537
538impl_asarg_string!(GString);
539impl_asarg_string!(StringName);
540impl_asarg_string!(NodePath);
541
542// ----------------------------------------------------------------------------------------------------------------------------------------------
543// Argument passing (mutually exclusive by-val or by-ref).
544
545/// Determines whether arguments are passed by value or by reference to Godot.
546///
547/// See [`ToGodot::Pass`].
548pub trait ArgPassing: Sealed {
549 /// Return type: `T` or `&'r T`.
550 type Output<'r, T: 'r>
551 where
552 Self: 'r;
553
554 /// FFI argument type: `T::Ffi` or `T::ToFfi<'f>`.
555 #[doc(hidden)]
556 type FfiOutput<'f, T>: GodotFfiVariant
557 where
558 T: GodotType + 'f;
559
560 /// Convert to owned `T::Via` (cloning if necessary).
561 #[doc(hidden)]
562 fn ref_to_owned_via<T>(value: &T) -> T::Via
563 where
564 T: EngineToGodot<Pass = Self>,
565 T::Via: Clone;
566
567 /// Convert to FFI repr in the most efficient way (move or borrow).
568 #[doc(hidden)]
569 fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
570 where
571 T: EngineToGodot<Pass = Self>,
572 T::Via: GodotType;
573
574 /// Convert to `Variant` in the most efficient way (move or borrow).
575 #[doc(hidden)]
576 fn ref_to_variant<T>(value: &T) -> Variant
577 where
578 T: EngineToGodot<Pass = Self>,
579 {
580 let ffi_result = Self::ref_to_ffi(value);
581 GodotFfiVariant::ffi_to_variant(&ffi_result)
582 }
583}
584
585/// Pass arguments to Godot by value.
586///
587/// See [`ToGodot::Pass`].
588pub enum ByValue {}
589impl Sealed for ByValue {}
590impl ArgPassing for ByValue {
591 type Output<'r, T: 'r> = T;
592
593 type FfiOutput<'a, T>
594 = T::Ffi
595 where
596 T: GodotType + 'a;
597
598 fn ref_to_owned_via<T>(value: &T) -> T::Via
599 where
600 T: EngineToGodot<Pass = Self>,
601 T::Via: Clone,
602 {
603 value.engine_to_godot()
604 }
605
606 fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
607 where
608 T: EngineToGodot<Pass = Self>,
609 T::Via: GodotType,
610 {
611 // For ByValue: engine_to_godot() returns owned T::Via, move directly to FFI.
612 GodotType::into_ffi(value.engine_to_godot())
613 }
614}
615
616/// Pass arguments to Godot by reference.
617///
618/// See [`ToGodot::Pass`].
619pub enum ByRef {}
620impl Sealed for ByRef {}
621impl ArgPassing for ByRef {
622 type Output<'r, T: 'r> = &'r T;
623
624 type FfiOutput<'f, T>
625 = T::ToFfi<'f>
626 where
627 T: GodotType + 'f;
628
629 fn ref_to_owned_via<T>(value: &T) -> T::Via
630 where
631 T: EngineToGodot<Pass = Self>,
632 T::Via: Clone,
633 {
634 // For ByRef types, clone the reference to get owned value.
635 value.engine_to_godot().clone()
636 }
637
638 fn ref_to_ffi<T>(value: &T) -> <T::Via as GodotType>::ToFfi<'_>
639 where
640 T: EngineToGodot<Pass = Self>,
641 T::Via: GodotType,
642 {
643 // Use by-ref conversion if possible, avoiding unnecessary clones when passing to FFI.
644 GodotType::to_ffi(value.engine_to_godot())
645 }
646}
647
648/// Pass `Variant` arguments to Godot by reference.
649///
650/// This is semantically identical to [`ByRef`], but exists as a separate type so that `Variant` has its own `Pass` type.
651/// This decoupling enables blanket `AsArg<Variant>` impls for all `ByRef` types without coherence conflicts at `T = Variant`.
652///
653/// See [`ToGodot::Pass`].
654pub enum ByVariant {}
655impl Sealed for ByVariant {}
656impl ArgPassing for ByVariant {
657 type Output<'r, T: 'r> = &'r T;
658
659 type FfiOutput<'f, T>
660 = T::ToFfi<'f>
661 where
662 T: GodotType + 'f;
663
664 fn ref_to_owned_via<T>(value: &T) -> T::Via
665 where
666 T: EngineToGodot<Pass = Self>,
667 T::Via: Clone,
668 {
669 value.engine_to_godot().clone()
670 }
671
672 fn ref_to_ffi<T>(value: &T) -> <T::Via as GodotType>::ToFfi<'_>
673 where
674 T: EngineToGodot<Pass = Self>,
675 T::Via: GodotType,
676 {
677 GodotType::to_ffi(value.engine_to_godot())
678 }
679}
680
681/// Pass arguments to Godot by object pointer (for objects only).
682///
683/// Currently distinct from [`ByRef`] to not interfere with the blanket impl for `&T` for all `ByRef` types. Semantics are largely the same.
684///
685/// See [`ToGodot::Pass`].
686pub enum ByObject {}
687impl Sealed for ByObject {}
688impl ArgPassing for ByObject {
689 type Output<'r, T: 'r> = &'r T;
690
691 type FfiOutput<'f, T>
692 = ObjectArg<'f>
693 where
694 T: GodotType + 'f;
695
696 fn ref_to_owned_via<T>(value: &T) -> T::Via
697 where
698 T: EngineToGodot<Pass = Self>,
699 T::Via: Clone,
700 {
701 // For ByObject types, do like ByRef: clone the reference to get owned value.
702 value.engine_to_godot().clone()
703 }
704
705 fn ref_to_ffi<T>(value: &T) -> ObjectArg<'_>
706 where
707 T: EngineToGodot<Pass = Self>,
708 T::Via: GodotType,
709 {
710 let obj_ref: &T::Via = value.engine_to_godot(); // implements GodotType.
711 obj_ref.as_object_arg()
712 }
713}
714
715/// Pass optional arguments by returning `Option<&T::Via>`, allowing delegation to underlying type's strategy.
716///
717/// This enables `Option<T>` to benefit from the underlying type's efficient passing without cloning. [`ByRef`] doesn't support this because it
718/// would transform `Option<T>` to `&Option<T>`; however, we need `Option<&T>` instead.
719///
720/// See [`ToGodot::Pass`].
721pub enum ByOption<Via> {
722 // Uses `Via` generic type to work around the near-impossibility of Output<'r, T> pointing to a metafunction that transforms Option<T> to
723 // Option<&'r T>. Such a metafunction cannot be implemented via trait (overlapping impls cause coherence issues), and we would need to
724 // pollute also the other `By*` types by anything. Using a generic parameter on the trait rather than the associated type avoids that.
725 _Phantom(std::marker::PhantomData<Via>),
726}
727impl<Via> Sealed for ByOption<Via> {}
728impl<Via> ArgPassing for ByOption<Via>
729where
730 Via: GodotType,
731 for<'f> Via::ToFfi<'f>: GodotNullableFfi,
732{
733 type Output<'r, T: 'r>
734 = Option<&'r Via>
735 where
736 Self: 'r;
737
738 type FfiOutput<'f, T>
739 = <Via as GodotType>::ToFfi<'f>
740 where
741 T: GodotType + 'f;
742
743 // value: &Option<U>
744 // return: T::Via = Option<U::Via>
745 fn ref_to_owned_via<T>(value: &T) -> T::Via
746 where
747 T: EngineToGodot<Pass = Self>,
748 T::Via: Clone,
749 {
750 value.engine_to_godot_owned()
751 }
752
753 fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
754 where
755 T: EngineToGodot<Pass = Self>,
756 T::Via: GodotType,
757 {
758 // Reuse pattern from impl GodotType for Option<T>:
759 // Convert Option<&Via> to Option<Via::ToFfi> and then flatten to Via::ToFfi with null handling.
760 GodotNullableFfi::flatten_option(value.engine_to_godot().map(|via_ref| via_ref.to_ffi()))
761 }
762}
763
764#[doc(hidden)] // Easier for internal use.
765pub type ToArg<'r, Via, Pass> = <Pass as ArgPassing>::Output<'r, Via>;
766
767/// This type exists only as a place to add doctests for `AsArg`, which do not need to be in the public documentation.
768///
769/// `AsArg<Option<Gd<UserClass>>` can be used with signals correctly:
770///
771/// ```no_run
772/// # use godot::prelude::*;
773/// #[derive(GodotClass)]
774/// #[class(init, base = Node)]
775/// struct MyClass {
776/// base: Base<Node>
777/// }
778///
779/// #[godot_api]
780/// impl MyClass {
781/// #[signal]
782/// fn signal_optional_user_obj(arg1: Option<Gd<MyClass>>);
783///
784/// fn foo(&mut self) {
785/// let arg = self.to_gd();
786/// // Directly:
787/// self.signals().signal_optional_user_obj().emit(&arg);
788/// // Via Some:
789/// self.signals().signal_optional_user_obj().emit(Some(&arg));
790/// // With None (Note: Gd::null_arg() is restricted to engine classes):
791/// self.signals().signal_optional_user_obj().emit(None::<Gd<MyClass>>.as_ref());
792/// }
793/// }
794/// ```
795///
796#[allow(dead_code)]
797struct PhantomAsArgDoctests;
798
799// ----------------------------------------------------------------------------------------------------------------------------------------------
800// AsArg<Variant> impls — replaces former AsVArg/DisjointVArg machinery
801
802// Blanket: ByValue types -> Variant (i32, f64, bool, Vector2, Color, &str, String, user enums, etc.).
803impl<T> AsArg<Variant> for T
804where
805 T: ToGodot<Pass = ByValue>,
806{
807 fn into_arg<'arg>(self) -> CowArg<'arg, Variant>
808 where
809 Self: 'arg,
810 {
811 CowArg::Owned(self.to_variant())
812 }
813}
814
815// Macro for ByRef types -> Variant. Generic params go in `[]`, empty for non-generic types.
816macro_rules! impl_asarg_variant_for_ref {
817 ([$($gen:tt)*] $T:ty) => {
818 impl<$($gen)*> AsArg<Variant> for &$T {
819 fn into_arg<'arg>(self) -> CowArg<'arg, Variant>
820 where
821 Self: 'arg,
822 {
823 CowArg::Owned(self.to_variant())
824 }
825 }
826 };
827}
828
829impl_asarg_variant_for_ref!([] GString);
830impl_asarg_variant_for_ref!([] StringName);
831impl_asarg_variant_for_ref!([] NodePath);
832impl_asarg_variant_for_ref!([] Callable);
833impl_asarg_variant_for_ref!([] Signal);
834impl_asarg_variant_for_ref!([T: Element] crate::builtin::Array<T>);
835impl_asarg_variant_for_ref!([K: Element, V: Element] crate::builtin::Dictionary<K, V>);
836impl_asarg_variant_for_ref!([T: PackedElement] crate::builtin::PackedArray<T>);
837impl_asarg_variant_for_ref!([T: GodotClass] Gd<T>);
838
839// ----------------------------------------------------------------------------------------------------------------------------------------------
840// AsDirectElement trait for array![] macro
841
842/// Marker trait for types directly usable in the [`array!`][crate::array] and [`dict!`][crate::dict] macros.
843///
844/// More restrictive than [`AsArg<T>`] — avoids ambiguity once `AsArg<Variant>` impls are added.
845/// Implemented for:
846/// - `T` when `T: Element + ToGodot<Pass = ByValue>` (e.g. `i32`, `bool`, `Color`).
847/// - `&T` when `T: Element + ToGodot<Pass = ByRef>` (e.g. `&GString`, `&Array<T>`).
848/// - `&str`, `&String` for `GString` (only; not `StringName`/`NodePath` to avoid ambiguity).
849pub trait AsDirectElement<T: Element>: AsArg<T> {}
850
851// ByValue: T directly passes as element (i32, bool, Vector2, ...).
852//
853// Explicitly supports other integer types than i64.
854impl<T> AsDirectElement<T> for T where T: Element + ToGodot<Pass = ByValue> {}
855
856// ByRef: &T passes as element (GString, Array, Dictionary, ...).
857impl<T> AsDirectElement<T> for &T where T: Element + ToGodot<Pass = ByRef> {}
858
859// Potentially allow this? However, it encourages manual case differentiation when working with objects,
860// which goes against the idea of implicit upcasts/option-casts/dyn-casts.
861// impl<T: GodotClass> AsDirectElement<Gd<T>> for &Gd<T> {}
862
863// String coercions: &str / &String -> GString only.
864//
865// Unlike impl_asarg_string!, we do NOT add impls for StringName/NodePath, to avoid ambiguity.
866// iarray!["hello"] would otherwise be ambiguous between Array<GString>, Array<StringName>, Array<NodePath>.
867// Users who need Array<StringName> from literals can use iarray![StringName::from("hi")] or
868// provide a type annotation: let arr: Array<StringName> = array!["hi"].
869impl AsDirectElement<GString> for &str {}
870impl AsDirectElement<GString> for &String {}