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::{GString, NodePath, StringName, Variant};
9use crate::meta::sealed::Sealed;
10use crate::meta::traits::{GodotFfiVariant, GodotNullableFfi};
11use crate::meta::{CowArg, 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, each type provides an `arg()` method, such as
53/// [`GString::arg()`]. You cannot use this method in other contexts.
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 their `arg()` method.",
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
121impl<T> AsArg<T> for T
122where
123    T: ToGodot<Pass = ByValue>,
124{
125    fn into_arg<'arg>(self) -> CowArg<'arg, T>
126    where
127        Self: 'arg,
128    {
129        CowArg::Owned(self)
130    }
131}
132
133// ----------------------------------------------------------------------------------------------------------------------------------------------
134// Object (Gd + DynGd) impls
135
136// Convert `Gd` -> `Gd` (with upcast).
137impl<T, Base> AsArg<Gd<Base>> for &Gd<T>
138where
139    T: Inherits<Base>,
140    Base: GodotClass,
141{
142    //noinspection RsConstantConditionIf - false positive in IDE for `T::IS_SAME_CLASS`.
143    fn into_arg<'arg>(self) -> CowArg<'arg, Gd<Base>>
144    where
145        Self: 'arg,
146    {
147        if T::IS_SAME_CLASS {
148            // SAFETY: T == Base, so &Gd<T> can be treated as &Gd<Base>.
149            let gd_ref = unsafe { std::mem::transmute::<&Gd<T>, &Gd<Base>>(self) };
150            CowArg::Borrowed(gd_ref)
151        } else {
152            // Different types: clone and upcast. May incur ref-count increment for RefCounted objects, but the common path
153            // of FFI passing is already optimized.
154            CowArg::Owned(self.clone().upcast())
155        }
156    }
157
158    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Gd<Base>>
159    where
160        Self: 'arg,
161    {
162        let arg = ObjectArg::from_gd(self);
163        FfiArg::FfiObject(arg)
164    }
165}
166
167/// Convert `DynGd` -> `DynGd` (with upcast).
168impl<T, D, Base> AsArg<DynGd<Base, D>> for &DynGd<T, D>
169where
170    T: Inherits<Base>,
171    D: ?Sized,
172    Base: GodotClass,
173{
174    //noinspection RsConstantConditionIf - false positive in IDE for `T::IS_SAME_CLASS`.
175    fn into_arg<'arg>(self) -> CowArg<'arg, DynGd<Base, D>>
176    where
177        Self: 'arg,
178    {
179        if T::IS_SAME_CLASS {
180            // SAFETY: T == Base, so &DynGd<T, D> can be treated as &DynGd<Base, D>.
181            let gd_ref = unsafe { std::mem::transmute::<&DynGd<T, D>, &DynGd<Base, D>>(self) };
182            CowArg::Borrowed(gd_ref)
183        } else {
184            // Different types: clone and upcast. May incur ref-count increment for RefCounted objects, but the common path
185            // of FFI passing is already optimized.
186            CowArg::Owned(self.clone().upcast())
187        }
188    }
189
190    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, DynGd<Base, D>>
191    where
192        Self: 'arg,
193    {
194        let arg = ObjectArg::from_gd(self);
195        FfiArg::FfiObject(arg)
196    }
197}
198
199/// Convert `DynGd` -> `Gd` (with upcast).
200impl<T, D, Base> AsArg<Gd<Base>> for &DynGd<T, D>
201where
202    T: Inherits<Base>,
203    D: ?Sized,
204    Base: GodotClass,
205{
206    fn into_arg<'arg>(self) -> CowArg<'arg, Gd<Base>>
207    where
208        Self: 'arg,
209    {
210        let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
211        AsArg::into_arg(gd_ref)
212    }
213
214    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Gd<Base>>
215    where
216        Self: 'arg,
217    {
218        let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
219        AsArg::into_ffi_arg(gd_ref)
220    }
221}
222
223// ----------------------------------------------------------------------------------------------------------------------------------------------
224// Null arguments
225
226/// Private struct for passing null arguments to optional object parameters.
227///
228/// This struct implements `AsArg` for both `Option<Gd<T>>` and `Option<DynGd<T, D>>`, allowing [`Gd::null_arg()`] and [`DynGd::null_arg()`]
229/// to share implementation.
230///
231/// Not public, as `impl AsArg<...>` is used by `null_arg()` methods.
232pub(crate) struct NullArg<T>(pub std::marker::PhantomData<*mut T>);
233
234impl<T> AsArg<Option<Gd<T>>> for NullArg<T>
235where
236    T: GodotClass,
237{
238    fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<T>>>
239    where
240        Self: 'arg,
241    {
242        CowArg::Owned(None)
243    }
244}
245
246impl<T, D> AsArg<Option<DynGd<T, D>>> for NullArg<T>
247where
248    T: GodotClass,
249    D: ?Sized + 'static,
250{
251    fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<T, D>>>
252    where
253        Self: 'arg,
254    {
255        CowArg::Owned(None)
256    }
257}
258
259// ----------------------------------------------------------------------------------------------------------------------------------------------
260// Optional object (Gd + DynGd) impls
261
262/// Convert `&Gd` -> `Option<Gd>` (with upcast).
263impl<T, Base> AsArg<Option<Gd<Base>>> for &Gd<T>
264where
265    T: Inherits<Base>,
266    Base: GodotClass,
267{
268    fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
269    where
270        Self: 'arg,
271    {
272        // Upcasting to an owned value Gd<Base> requires cloning. Optimized path in into_ffi_arg().
273        CowArg::Owned(Some(self.clone().upcast::<Base>()))
274    }
275
276    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
277    where
278        Self: 'arg,
279    {
280        let arg = ObjectArg::from_gd(self);
281        FfiArg::FfiObject(arg)
282    }
283}
284
285/// Convert `Option<&Gd>` -> `Option<Gd>` (with upcast).
286impl<T, Base> AsArg<Option<Gd<Base>>> for Option<&Gd<T>>
287where
288    T: Inherits<Base>,
289    Base: GodotClass,
290{
291    fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
292    where
293        Self: 'arg,
294    {
295        // Upcasting to an owned value Gd<Base> requires cloning. Optimized path in into_ffi_arg().
296        match self {
297            Some(gd_ref) => AsArg::into_arg(gd_ref),
298            None => CowArg::Owned(None),
299        }
300    }
301
302    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
303    where
304        Self: 'arg,
305    {
306        let arg = ObjectArg::from_option_gd(self);
307        FfiArg::FfiObject(arg)
308    }
309}
310
311/// Convert `&DynGd` -> `Option<DynGd>` (with upcast).
312impl<T, D, Base> AsArg<Option<DynGd<Base, D>>> for &DynGd<T, D>
313where
314    T: Inherits<Base>,
315    D: ?Sized,
316    Base: GodotClass,
317{
318    fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<Base, D>>>
319    where
320        Self: 'arg,
321    {
322        // Upcasting to an owned value DynGd<Base, D> requires cloning. Optimized path in into_ffi_arg().
323        CowArg::Owned(Some(self.clone().upcast()))
324    }
325
326    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<DynGd<Base, D>>>
327    where
328        Self: 'arg,
329    {
330        let arg = ObjectArg::from_gd(self);
331        FfiArg::FfiObject(arg)
332    }
333}
334
335/// Convert `&DynGd` -> `Option<Gd>` (with upcast).
336impl<T, D, Base> AsArg<Option<Gd<Base>>> for &DynGd<T, D>
337where
338    T: Inherits<Base>,
339    D: ?Sized,
340    Base: GodotClass,
341{
342    fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
343    where
344        Self: 'arg,
345    {
346        let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
347        AsArg::into_arg(gd_ref)
348    }
349
350    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
351    where
352        Self: 'arg,
353    {
354        let gd_ref: &Gd<T> = self; // DynGd -> Gd deref.
355        AsArg::into_ffi_arg(gd_ref)
356    }
357}
358
359/// Convert `Option<&DynGd>` -> `Option<DynGd>` (with upcast).
360impl<T, D, Base> AsArg<Option<DynGd<Base, D>>> for Option<&DynGd<T, D>>
361where
362    T: Inherits<Base>,
363    D: ?Sized,
364    Base: GodotClass,
365{
366    fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<Base, D>>>
367    where
368        Self: 'arg,
369    {
370        // Upcasting to an owned value Gd<Base> requires cloning. Optimized path in into_ffi_arg().
371        match self {
372            Some(gd_ref) => AsArg::into_arg(gd_ref),
373            None => CowArg::Owned(None),
374        }
375    }
376
377    fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<DynGd<Base, D>>>
378    where
379        Self: 'arg,
380    {
381        let option_gd: Option<&Gd<T>> = self.map(|v| &**v); // as_deref() not working.
382        let arg = ObjectArg::from_option_gd(option_gd);
383        FfiArg::FfiObject(arg)
384    }
385}
386
387// ----------------------------------------------------------------------------------------------------------------------------------------------
388// Public helper functions (T|&T -> AsArg)
389
390/// Generic abstraction over `T` owned values that should be passed as `AsArg<T>`.
391///
392/// Useful for generic programming: you have owned values, and want the argument conversion to benefit from moving whenever possible.
393/// You don't care if the value can truly be moved efficiently, since you don't need the value at the call site anymore.
394///
395/// Note that the pattern `owned_into_arg(value.clone())` is inefficient -- instead, use [`ref_to_arg(&value)`][ref_to_arg].
396///
397/// # Example
398/// ```
399/// use godot::prelude::*;
400/// use godot::meta::{ArrayElement, owned_into_arg};
401///
402/// // Creates random values, e.g. for fuzzing, property-based testing, etc.
403/// // Assume global state for simplicity.
404/// trait Generator {
405///    fn next() -> Self;
406/// }
407///
408/// fn fill_randomly<T>(arr: &mut Array<T>, count: usize)
409/// where
410///     T: ArrayElement + ToGodot + Generator,
411/// {
412///     for _ in 0..count {
413///         let value = T::next();
414///         arr.push(owned_into_arg(value));
415///     }
416/// }
417/// ```
418pub fn owned_into_arg<'arg, T>(owned_val: T) -> impl AsArg<T> + 'arg
419where
420    T: ToGodot + 'arg,
421{
422    CowArg::Owned(owned_val)
423}
424
425/// Generic abstraction over `&T` references that should be passed as `AsArg<T>`.
426///
427/// Useful for generic programming: you have references, and want the argument conversion to benefit from borrowing whenever possible.
428///
429/// If you no longer need the value at the call site, consider using [`owned_into_arg(value)`][owned_into_arg] instead.
430///
431/// # Example
432/// ```
433/// use godot::prelude::*;
434/// use godot::meta::{ArrayElement, ref_to_arg};
435///
436/// // Could use `impl AsArg<T>` and forward it, but let's demonstrate `&T` here.
437/// fn log_and_push<T>(arr: &mut Array<T>, value: &T)
438/// where
439///     T: ArrayElement + ToGodot + std::fmt::Debug,
440/// {
441///     println!("Add value: {value:?}");
442///     arr.push(ref_to_arg(value));
443/// }
444/// ```
445pub fn ref_to_arg<'r, T>(ref_val: &'r T) -> impl AsArg<T> + 'r
446where
447    T: ToGodot + 'r,
448{
449    CowArg::Borrowed(ref_val)
450}
451
452// ----------------------------------------------------------------------------------------------------------------------------------------------
453// Internal helper macros (AsArg -> &T|T)
454
455/// Converts `impl AsArg<T>` into a locally valid `&T`.
456///
457/// This cannot be done via function, since an intermediate variable (the Cow) is needed, which would go out of scope
458/// once the reference is returned. Could use more fancy syntax like `arg_into_ref! { let path = ref; }` or `let path = arg_into_ref!(path)`,
459/// 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.
460#[macro_export]
461#[doc(hidden)] // Doesn't work at re-export.
462macro_rules! arg_into_ref {
463    ($arg_variable:ident) => {
464        // Non-generic version allows type inference. Only applicable for CowArg types.
465        let $arg_variable = $arg_variable.into_arg();
466        let $arg_variable = $arg_variable.cow_as_ref();
467    };
468    ($arg_variable:ident: $T:ty) => {
469        let $arg_variable = $arg_variable.into_arg();
470        let $arg_variable: &$T = $arg_variable.cow_as_ref();
471    };
472}
473
474/// Converts `impl AsArg<T>` into a locally valid `T`.
475///
476/// A macro for consistency with [`arg_into_ref`][crate::arg_into_ref].
477#[macro_export]
478#[doc(hidden)] // Doesn't work at re-export.
479macro_rules! arg_into_owned {
480    ($arg_variable:ident) => {
481        // Non-generic version allows type inference. Only applicable for CowArg types.
482        let $arg_variable = $arg_variable.into_arg();
483        let $arg_variable = $arg_variable.cow_into_owned();
484    };
485    (infer $arg_variable:ident) => {
486        let $arg_variable = $arg_variable.into_arg();
487        let $arg_variable = $arg_variable.cow_into_owned();
488    };
489}
490
491#[macro_export]
492macro_rules! declare_arg_method {
493    ($ ($docs:tt)+ ) => {
494        $( $docs )+
495        ///
496        /// # Generic bounds
497        /// The bounds are implementation-defined and may change at any time. Do not use this function in a generic context requiring `T`
498        /// -- use the `From` trait or [`AsArg`][crate::meta::AsArg] in that case.
499        pub fn arg<T>(&self) -> impl $crate::meta::AsArg<T>
500        where
501            for<'a> T: From<&'a Self>
502                + $crate::meta::ToGodot
503                + 'a,
504        {
505            $crate::meta::CowArg::Owned(T::from(self))
506        }
507    };
508}
509
510// ----------------------------------------------------------------------------------------------------------------------------------------------
511// CowArg
512
513/// `CowArg` can itself be passed as an argument (internal only).
514///
515/// Allows forwarding of `impl AsArg<T>` arguments to both another signature of `impl AsArg<T>` and signature of `T` for `Copy` types.
516/// This is necessary for packed array dispatching to different "inner" backend signatures.
517impl<T> AsArg<T> for CowArg<'_, T>
518where
519    for<'r> T: ToGodot,
520{
521    fn into_arg<'arg>(self) -> CowArg<'arg, T>
522    where
523        Self: 'arg,
524    {
525        self
526    }
527}
528
529// ----------------------------------------------------------------------------------------------------------------------------------------------
530// GString
531
532// Note: for all string types S, `impl AsArg<S> for &mut String` is not yet provided, but we can add them if needed.
533
534impl AsArg<GString> for &str {
535    fn into_arg<'arg>(self) -> CowArg<'arg, GString> {
536        CowArg::Owned(GString::from(self))
537    }
538}
539
540impl AsArg<GString> for &String {
541    fn into_arg<'arg>(self) -> CowArg<'arg, GString> {
542        CowArg::Owned(GString::from(self))
543    }
544}
545
546// ----------------------------------------------------------------------------------------------------------------------------------------------
547// StringName
548
549impl AsArg<StringName> for &str {
550    fn into_arg<'arg>(self) -> CowArg<'arg, StringName> {
551        CowArg::Owned(StringName::from(self))
552    }
553}
554
555impl AsArg<StringName> for &String {
556    fn into_arg<'arg>(self) -> CowArg<'arg, StringName> {
557        CowArg::Owned(StringName::from(self))
558    }
559}
560
561// ----------------------------------------------------------------------------------------------------------------------------------------------
562// NodePath
563
564impl AsArg<NodePath> for &str {
565    fn into_arg<'arg>(self) -> CowArg<'arg, NodePath> {
566        CowArg::Owned(NodePath::from(self))
567    }
568}
569
570impl AsArg<NodePath> for &String {
571    fn into_arg<'arg>(self) -> CowArg<'arg, NodePath> {
572        CowArg::Owned(NodePath::from(self))
573    }
574}
575
576// ----------------------------------------------------------------------------------------------------------------------------------------------
577// Argument passing (mutually exclusive by-val or by-ref).
578
579/// Determines whether arguments are passed by value or by reference to Godot.
580///
581/// See [`ToGodot::Pass`].
582pub trait ArgPassing: Sealed {
583    /// Return type: `T` or `&'r T`.
584    type Output<'r, T: 'r>
585    where
586        Self: 'r;
587
588    /// FFI argument type: `T::Ffi` or `T::ToFfi<'f>`.
589    #[doc(hidden)]
590    type FfiOutput<'f, T>: GodotFfiVariant
591    where
592        T: GodotType + 'f;
593
594    /// Convert to owned `T::Via` (cloning if necessary).
595    #[doc(hidden)]
596    fn ref_to_owned_via<T>(value: &T) -> T::Via
597    where
598        T: ToGodot<Pass = Self>,
599        T::Via: Clone;
600
601    /// Convert to FFI repr in the most efficient way (move or borrow).
602    #[doc(hidden)]
603    fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
604    where
605        T: ToGodot<Pass = Self>,
606        T::Via: GodotType;
607
608    /// Convert to `Variant` in the most efficient way (move or borrow).
609    #[doc(hidden)]
610    fn ref_to_variant<T>(value: &T) -> Variant
611    where
612        T: ToGodot<Pass = Self>,
613    {
614        let ffi_result = Self::ref_to_ffi(value);
615        GodotFfiVariant::ffi_to_variant(&ffi_result)
616    }
617}
618
619/// Pass arguments to Godot by value.
620///
621/// See [`ToGodot::Pass`].
622pub enum ByValue {}
623impl Sealed for ByValue {}
624impl ArgPassing for ByValue {
625    type Output<'r, T: 'r> = T;
626
627    type FfiOutput<'a, T>
628        = T::Ffi
629    where
630        T: GodotType + 'a;
631
632    fn ref_to_owned_via<T>(value: &T) -> T::Via
633    where
634        T: ToGodot<Pass = Self>,
635        T::Via: Clone,
636    {
637        value.to_godot()
638    }
639
640    fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
641    where
642        T: ToGodot<Pass = Self>,
643        T::Via: GodotType,
644    {
645        // For ByValue: to_godot() returns owned T::Via, move directly to FFI.
646        GodotType::into_ffi(value.to_godot())
647    }
648}
649
650/// Pass arguments to Godot by reference.
651///
652/// See [`ToGodot::Pass`].
653pub enum ByRef {}
654impl Sealed for ByRef {}
655impl ArgPassing for ByRef {
656    type Output<'r, T: 'r> = &'r T;
657
658    type FfiOutput<'f, T>
659        = T::ToFfi<'f>
660    where
661        T: GodotType + 'f;
662
663    fn ref_to_owned_via<T>(value: &T) -> T::Via
664    where
665        T: ToGodot<Pass = Self>,
666        T::Via: Clone,
667    {
668        // For ByRef types, clone the reference to get owned value.
669        value.to_godot().clone()
670    }
671
672    fn ref_to_ffi<T>(value: &T) -> <T::Via as GodotType>::ToFfi<'_>
673    where
674        T: ToGodot<Pass = Self>,
675        T::Via: GodotType,
676    {
677        // Use by-ref conversion if possible, avoiding unnecessary clones when passing to FFI.
678        GodotType::to_ffi(value.to_godot())
679    }
680}
681
682/// Pass arguments to Godot by object pointer (for objects only).
683///
684/// Currently distinct from [`ByRef`] to not interfere with the blanket impl for `&T` for all `ByRef` types. Semantics are largely the same.
685///
686/// See [`ToGodot::Pass`].
687pub enum ByObject {}
688impl Sealed for ByObject {}
689impl ArgPassing for ByObject {
690    type Output<'r, T: 'r> = &'r T;
691
692    type FfiOutput<'f, T>
693        = ObjectArg<'f>
694    where
695        T: GodotType + 'f;
696
697    fn ref_to_owned_via<T>(value: &T) -> T::Via
698    where
699        T: ToGodot<Pass = Self>,
700        T::Via: Clone,
701    {
702        // For ByObject types, do like ByRef: clone the reference to get owned value.
703        value.to_godot().clone()
704    }
705
706    fn ref_to_ffi<T>(value: &T) -> ObjectArg<'_>
707    where
708        T: ToGodot<Pass = Self>,
709        T::Via: GodotType,
710    {
711        let obj_ref: &T::Via = value.to_godot(); // implements GodotType.
712        obj_ref.as_object_arg()
713    }
714}
715
716/// Pass optional arguments by returning `Option<&T::Via>`, allowing delegation to underlying type's strategy.
717///
718/// This enables `Option<T>` to benefit from the underlying type's efficient passing without cloning. [`ByRef`] doesn't support this because it
719/// would transform `Option<T>` to `&Option<T>`; however, we need `Option<&T>` instead.
720///
721/// See [`ToGodot::Pass`].
722pub enum ByOption<Via> {
723    // Uses `Via` generic type to work around the near-impossibility of Output<'r, T> pointing to a metafunction that transforms Option<T> to
724    // Option<&'r T>. Such a metafunction cannot be implemented via trait (overlapping impls cause coherence issues), and we would need to
725    // pollute also the other `By*` types by anything. Using a generic parameter on the trait rather than the associated type avoids that.
726    _Phantom(std::marker::PhantomData<Via>),
727}
728impl<Via> Sealed for ByOption<Via> {}
729impl<Via> ArgPassing for ByOption<Via>
730where
731    Via: GodotType,
732    for<'f> Via::ToFfi<'f>: GodotNullableFfi,
733{
734    type Output<'r, T: 'r>
735        = Option<&'r Via>
736    where
737        Self: 'r;
738
739    type FfiOutput<'f, T>
740        = <Via as GodotType>::ToFfi<'f>
741    where
742        T: GodotType + 'f;
743
744    // value:  &Option<U>
745    // return: T::Via = Option<U::Via>
746    fn ref_to_owned_via<T>(value: &T) -> T::Via
747    where
748        T: ToGodot<Pass = Self>,
749        T::Via: Clone,
750    {
751        value.to_godot_owned()
752    }
753
754    fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
755    where
756        T: ToGodot<Pass = Self>,
757        T::Via: GodotType,
758    {
759        // Reuse pattern from impl GodotType for Option<T>:
760        // Convert Option<&Via> to Option<Via::ToFfi> and then flatten to Via::ToFfi with null handling.
761        GodotNullableFfi::flatten_option(value.to_godot().map(|via_ref| via_ref.to_ffi()))
762    }
763}
764
765#[doc(hidden)] // Easier for internal use.
766pub type ToArg<'r, Via, Pass> = <Pass as ArgPassing>::Output<'r, Via>;
767
768/// This type exists only as a place to add doctests for `AsArg`, which do not need to be in the public documentation.
769///
770/// `AsArg<Option<Gd<UserClass>>` can be used with signals correctly:
771///
772/// ```no_run
773/// # use godot::prelude::*;
774/// #[derive(GodotClass)]
775/// #[class(init, base = Node)]
776/// struct MyClass {
777///     base: Base<Node>
778/// }
779///
780/// #[godot_api]
781/// impl MyClass {
782///     #[signal]
783///     fn signal_optional_user_obj(arg1: Option<Gd<MyClass>>);
784///
785///     fn foo(&mut self) {
786///         let arg = self.to_gd();
787///         // Directly:
788///         self.signals().signal_optional_user_obj().emit(&arg);
789///         // Via Some:
790///         self.signals().signal_optional_user_obj().emit(Some(&arg));
791///         // With None (Note: Gd::null_arg() is restricted to engine classes):
792///         self.signals().signal_optional_user_obj().emit(None::<Gd<MyClass>>.as_ref());
793///     }
794/// }
795/// ```
796///
797#[allow(dead_code)]
798struct PhantomAsArgDoctests;