use crate::builtin::{Callable, GString, NodePath, Signal, StringName, Variant};
use crate::meta::sealed::Sealed;
use crate::meta::traits::{Element, GodotFfiVariant, GodotNullableType, PackedElement};
use crate::meta::{CowArg, EngineToGodot, FfiArg, GodotType, ObjectArg, ToGodot};
use crate::obj::{DynGd, Gd, GodotClass, Inherits};
#[diagnostic::on_unimplemented(
message = "Argument of type `{Self}` cannot be passed to an `impl AsArg<{T}>` parameter",
note = "if you pass by value, consider borrowing instead.",
note = "GString/StringName/NodePath aren't implicitly convertible for performance reasons; use `From` conversions.",
note = "see also `AsArg` docs: https://godot-rust.github.io/docs/gdext/master/godot/meta/trait.AsArg.html"
)]
pub trait AsArg<T: ToGodot>
where
Self: Sized,
{
#[doc(hidden)]
fn into_arg<'arg>(self) -> CowArg<'arg, T>
where
Self: 'arg;
#[doc(hidden)]
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, T>
where
Self: 'arg,
{
FfiArg::Cow(self.into_arg())
}
}
impl<T> AsArg<T> for &T
where
T: ToGodot<Pass = ByRef>,
{
fn into_arg<'arg>(self) -> CowArg<'arg, T>
where
Self: 'arg,
{
CowArg::Borrowed(self)
}
}
impl AsArg<Variant> for &Variant {
fn into_arg<'arg>(self) -> CowArg<'arg, Variant>
where
Self: 'arg,
{
CowArg::Borrowed(self)
}
}
impl<T> AsArg<T> for T
where
T: ToGodot<Pass = ByValue> + Sized, {
fn into_arg<'arg>(self) -> CowArg<'arg, T>
where
Self: 'arg,
{
CowArg::Owned(self)
}
}
impl<T, Base> AsArg<Gd<Base>> for &Gd<T>
where
T: Inherits<Base>,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Gd<Base>>
where
Self: 'arg,
{
if T::IS_SAME_CLASS {
let gd_ref = unsafe { std::mem::transmute::<&Gd<T>, &Gd<Base>>(self) };
CowArg::Borrowed(gd_ref)
} else {
CowArg::Owned(self.clone().upcast())
}
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Gd<Base>>
where
Self: 'arg,
{
let arg = ObjectArg::from_gd(self);
FfiArg::FfiObject(arg)
}
}
impl<T, D, Base> AsArg<DynGd<Base, D>> for &DynGd<T, D>
where
T: Inherits<Base>,
D: ?Sized,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, DynGd<Base, D>>
where
Self: 'arg,
{
if T::IS_SAME_CLASS {
let gd_ref = unsafe { std::mem::transmute::<&DynGd<T, D>, &DynGd<Base, D>>(self) };
CowArg::Borrowed(gd_ref)
} else {
CowArg::Owned(self.clone().upcast())
}
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, DynGd<Base, D>>
where
Self: 'arg,
{
let arg = ObjectArg::from_gd(self);
FfiArg::FfiObject(arg)
}
}
impl<T, D, Base> AsArg<Gd<Base>> for &DynGd<T, D>
where
T: Inherits<Base>,
D: ?Sized,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Gd<Base>>
where
Self: 'arg,
{
let gd_ref: &Gd<T> = self; AsArg::into_arg(gd_ref)
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Gd<Base>>
where
Self: 'arg,
{
let gd_ref: &Gd<T> = self; AsArg::into_ffi_arg(gd_ref)
}
}
pub(crate) struct NullArg<T>(pub std::marker::PhantomData<*mut T>);
impl<T> AsArg<Option<Gd<T>>> for NullArg<T>
where
T: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<T>>>
where
Self: 'arg,
{
CowArg::Owned(None)
}
}
impl<T, D> AsArg<Option<DynGd<T, D>>> for NullArg<T>
where
T: GodotClass,
D: ?Sized + 'static,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<T, D>>>
where
Self: 'arg,
{
CowArg::Owned(None)
}
}
impl<T, Base> AsArg<Option<Gd<Base>>> for &Gd<T>
where
T: Inherits<Base>,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
where
Self: 'arg,
{
CowArg::Owned(Some(self.clone().upcast::<Base>()))
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
where
Self: 'arg,
{
let arg = ObjectArg::from_gd(self);
FfiArg::FfiObject(arg)
}
}
impl<T, Base> AsArg<Option<Gd<Base>>> for Option<&Gd<T>>
where
T: Inherits<Base>,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
where
Self: 'arg,
{
match self {
Some(gd_ref) => AsArg::into_arg(gd_ref),
None => CowArg::Owned(None),
}
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
where
Self: 'arg,
{
let arg = ObjectArg::from_option_gd(self);
FfiArg::FfiObject(arg)
}
}
impl<T, D, Base> AsArg<Option<DynGd<Base, D>>> for &DynGd<T, D>
where
T: Inherits<Base>,
D: ?Sized,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<Base, D>>>
where
Self: 'arg,
{
CowArg::Owned(Some(self.clone().upcast()))
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<DynGd<Base, D>>>
where
Self: 'arg,
{
let arg = ObjectArg::from_gd(self);
FfiArg::FfiObject(arg)
}
}
impl<T, D, Base> AsArg<Option<Gd<Base>>> for &DynGd<T, D>
where
T: Inherits<Base>,
D: ?Sized,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<Gd<Base>>>
where
Self: 'arg,
{
let gd_ref: &Gd<T> = self; AsArg::into_arg(gd_ref)
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<Gd<Base>>>
where
Self: 'arg,
{
let gd_ref: &Gd<T> = self; AsArg::into_ffi_arg(gd_ref)
}
}
impl<T, D, Base> AsArg<Option<DynGd<Base, D>>> for Option<&DynGd<T, D>>
where
T: Inherits<Base>,
D: ?Sized,
Base: GodotClass,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Option<DynGd<Base, D>>>
where
Self: 'arg,
{
match self {
Some(gd_ref) => AsArg::into_arg(gd_ref),
None => CowArg::Owned(None),
}
}
fn into_ffi_arg<'arg>(self) -> FfiArg<'arg, Option<DynGd<Base, D>>>
where
Self: 'arg,
{
let option_gd: Option<&Gd<T>> = self.map(|v| &**v); let arg = ObjectArg::from_option_gd(option_gd);
FfiArg::FfiObject(arg)
}
}
pub fn owned_into_arg<'arg, T>(owned_val: T) -> impl AsArg<T> + 'arg
where
T: ToGodot + 'arg,
{
CowArg::Owned(owned_val)
}
pub fn ref_to_arg<'r, T>(ref_val: &'r T) -> impl AsArg<T> + 'r
where
T: ToGodot + 'r,
{
CowArg::Borrowed(ref_val)
}
#[macro_export]
#[doc(hidden)] macro_rules! arg_into_ref {
($arg_variable:ident) => {
let $arg_variable = $arg_variable.into_arg();
let $arg_variable = $arg_variable.cow_as_ref();
};
($arg_variable:ident: $T:ty) => {
let $arg_variable = $arg_variable.into_arg();
let $arg_variable: &$T = $arg_variable.cow_as_ref();
};
}
#[macro_export]
#[doc(hidden)] macro_rules! arg_into_owned {
($arg_variable:ident) => {
let $arg_variable = $arg_variable.into_arg();
let $arg_variable = $arg_variable.cow_into_owned();
};
(infer $arg_variable:ident) => {
let $arg_variable = $arg_variable.into_arg();
let $arg_variable = $arg_variable.cow_into_owned();
};
}
impl<T> AsArg<T> for CowArg<'_, T>
where
for<'r> T: ToGodot,
{
fn into_arg<'arg>(self) -> CowArg<'arg, T>
where
Self: 'arg,
{
self
}
}
macro_rules! impl_asarg_string {
($Target:ty) => {
impl AsArg<$Target> for &str {
fn into_arg<'arg>(self) -> CowArg<'arg, $Target> {
CowArg::Owned(<$Target>::from(self))
}
}
impl AsArg<$Target> for &String {
fn into_arg<'arg>(self) -> CowArg<'arg, $Target> {
CowArg::Owned(<$Target>::from(self.as_str()))
}
}
};
}
impl_asarg_string!(GString);
impl_asarg_string!(StringName);
impl_asarg_string!(NodePath);
pub trait ArgPassing: Sealed {
type Output<'r, T: 'r>
where
Self: 'r;
#[doc(hidden)]
type FfiOutput<'f, T>: GodotFfiVariant
where
T: GodotType + 'f;
#[doc(hidden)]
fn ref_to_owned_via<T>(value: &T) -> T::Via
where
T: EngineToGodot<Pass = Self>;
#[doc(hidden)]
fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
where
T: EngineToGodot<Pass = Self>;
#[doc(hidden)]
fn ref_to_variant<T>(value: &T) -> Variant
where
T: EngineToGodot<Pass = Self>,
{
let ffi_result = Self::ref_to_ffi(value);
GodotFfiVariant::ffi_to_variant(&ffi_result)
}
}
pub enum ByValue {}
impl Sealed for ByValue {}
impl ArgPassing for ByValue {
type Output<'r, T: 'r> = T;
type FfiOutput<'a, T>
= T::Ffi
where
T: GodotType + 'a;
fn ref_to_owned_via<T>(value: &T) -> T::Via
where
T: EngineToGodot<Pass = Self>,
{
value.engine_to_godot()
}
fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
where
T: EngineToGodot<Pass = Self>,
{
GodotType::into_ffi(value.engine_to_godot())
}
}
pub enum ByRef {}
impl Sealed for ByRef {}
impl ArgPassing for ByRef {
type Output<'r, T: 'r> = &'r T;
type FfiOutput<'f, T>
= T::ToFfi<'f>
where
T: GodotType + 'f;
fn ref_to_owned_via<T>(value: &T) -> T::Via
where
T: EngineToGodot<Pass = Self>,
{
value.engine_to_godot().clone()
}
fn ref_to_ffi<T>(value: &T) -> <T::Via as GodotType>::ToFfi<'_>
where
T: EngineToGodot<Pass = Self>,
{
GodotType::to_ffi(value.engine_to_godot())
}
}
pub enum ByVariant {}
impl Sealed for ByVariant {}
impl ArgPassing for ByVariant {
type Output<'r, T: 'r> = &'r T;
type FfiOutput<'f, T>
= T::ToFfi<'f>
where
T: GodotType + 'f;
fn ref_to_owned_via<T>(value: &T) -> T::Via
where
T: EngineToGodot<Pass = Self>,
{
value.engine_to_godot().clone()
}
fn ref_to_ffi<T>(value: &T) -> <T::Via as GodotType>::ToFfi<'_>
where
T: EngineToGodot<Pass = Self>,
{
GodotType::to_ffi(value.engine_to_godot())
}
}
pub enum ByObject {}
impl Sealed for ByObject {}
impl ArgPassing for ByObject {
type Output<'r, T: 'r> = &'r T;
type FfiOutput<'f, T>
= ObjectArg<'f>
where
T: GodotType + 'f;
fn ref_to_owned_via<T>(value: &T) -> T::Via
where
T: EngineToGodot<Pass = Self>,
{
value.engine_to_godot().clone()
}
fn ref_to_ffi<T>(value: &T) -> ObjectArg<'_>
where
T: EngineToGodot<Pass = Self>,
{
let obj_ref: &T::Via = value.engine_to_godot(); obj_ref.as_object_arg()
}
}
pub enum ByOption<Via> {
_Phantom(std::marker::PhantomData<Via>),
}
impl<Via> Sealed for ByOption<Via> {}
impl<Via> ArgPassing for ByOption<Via>
where
Via: GodotNullableType,
{
type Output<'r, T: 'r>
= Option<&'r Via>
where
Self: 'r;
type FfiOutput<'f, T>
= <Via as GodotType>::ToFfi<'f>
where
T: GodotType + 'f;
fn ref_to_owned_via<T>(value: &T) -> T::Via
where
T: EngineToGodot<Pass = Self>,
{
value.engine_to_godot_owned()
}
fn ref_to_ffi<T>(value: &T) -> Self::FfiOutput<'_, T::Via>
where
T: EngineToGodot<Pass = Self>,
{
value
.engine_to_godot()
.map(|via_ref| via_ref.to_ffi())
.unwrap_or_else(Via::ffi_null_ref)
}
}
#[doc(hidden)] pub type ToArg<'r, Via, Pass> = <Pass as ArgPassing>::Output<'r, Via>;
#[allow(dead_code)]
struct PhantomAsArgDoctests;
impl<T> AsArg<Variant> for T
where
T: ToGodot<Pass = ByValue>,
{
fn into_arg<'arg>(self) -> CowArg<'arg, Variant>
where
Self: 'arg,
{
CowArg::Owned(self.to_variant())
}
}
macro_rules! impl_asarg_variant_for_ref {
([$($gen:tt)*] $T:ty) => {
impl<$($gen)*> AsArg<Variant> for &$T {
fn into_arg<'arg>(self) -> CowArg<'arg, Variant>
where
Self: 'arg,
{
CowArg::Owned(self.to_variant())
}
}
};
}
impl_asarg_variant_for_ref!([] GString);
impl_asarg_variant_for_ref!([] StringName);
impl_asarg_variant_for_ref!([] NodePath);
impl_asarg_variant_for_ref!([] Callable);
impl_asarg_variant_for_ref!([] Signal);
impl_asarg_variant_for_ref!([T: Element] crate::builtin::Array<T>);
impl_asarg_variant_for_ref!([K: Element, V: Element] crate::builtin::Dictionary<K, V>);
impl_asarg_variant_for_ref!([T: PackedElement] crate::builtin::PackedArray<T>);
impl_asarg_variant_for_ref!([T: GodotClass] Gd<T>);
pub trait AsDirectElement<T: Element>: AsArg<T> {}
impl<T> AsDirectElement<T> for T where T: Element + ToGodot<Pass = ByValue> {}
impl<T> AsDirectElement<T> for &T where T: Element + ToGodot<Pass = ByRef> {}
impl AsDirectElement<GString> for &str {}
impl AsDirectElement<GString> for &String {}