Skip to main content

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 {}