mod impls;
use crate::builtin::Variant;
use crate::meta::error::ConvertError;
use crate::meta::shape::GodotShape;
use crate::meta::traits::GodotFfiVariant;
use crate::meta::{ArgPassing, GodotType, ToArg};
#[doc(alias = "via", alias = "transparent")]
#[diagnostic::on_unimplemented(
message = "`GodotConvert` is needed for `#[func]` parameters/returns, as well as `#[var]` and `#[export]` properties",
note = "check following errors for more information"
)]
pub trait GodotConvert {
type Via: GodotType;
fn godot_shape() -> GodotShape;
}
#[diagnostic::on_unimplemented(
message = "passing type `{Self}` to Godot requires `ToGodot` trait, which is usually provided by the library",
note = "ToGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
note = "if you really need a custom representation (for non-class types), implement ToGodot manually or use #[derive(GodotConvert)].",
note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
)]
pub trait ToGodot: Sized + GodotConvert {
type Pass: ArgPassing;
fn to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
fn to_godot_owned(&self) -> Self::Via {
Self::Pass::ref_to_owned_via(self)
}
fn to_variant(&self) -> Variant {
Self::Pass::ref_to_variant(self)
}
}
#[diagnostic::on_unimplemented(
message = "receiving type `{Self}` from Godot requires `FromGodot` trait, which is usually provided by the library",
note = "FromGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
note = "if you really need a custom representation (for non-class types), implement FromGodot manually or use #[derive(GodotConvert)]",
note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
)]
pub trait FromGodot: Sized + GodotConvert {
fn try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
fn from_godot(via: Self::Via) -> Self {
Self::try_from_godot(via)
.unwrap_or_else(|err| panic!("FromGodot::from_godot() failed: {err}"))
}
fn try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
let ffi = <Self::Via as GodotType>::Ffi::ffi_from_variant(variant)?;
let via = Self::Via::try_from_ffi(ffi)?;
Self::try_from_godot(via)
}
fn from_variant(variant: &Variant) -> Self {
Self::try_from_variant(variant).unwrap_or_else(|err| {
panic!("FromGodot::from_variant() failed -- {err}");
})
}
}
#[doc(hidden)]
pub trait EngineToGodot: Sized + GodotConvert {
type Pass: ArgPassing;
fn engine_to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
fn engine_to_godot_owned(&self) -> Self::Via {
Self::Pass::ref_to_owned_via(self)
}
fn engine_to_variant(&self) -> Variant;
}
impl<T: ToGodot> EngineToGodot for T {
type Pass = T::Pass;
fn engine_to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass> {
<T as ToGodot>::to_godot(self)
}
fn engine_to_godot_owned(&self) -> Self::Via {
<T as ToGodot>::to_godot_owned(self)
}
fn engine_to_variant(&self) -> Variant {
<T as ToGodot>::to_variant(self)
}
}
#[doc(hidden)]
pub trait EngineFromGodot: Sized + GodotConvert {
fn engine_try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
fn engine_try_from_variant(variant: &Variant) -> Result<Self, ConvertError>;
}
impl<T: FromGodot> EngineFromGodot for T {
fn engine_try_from_godot(via: Self::Via) -> Result<Self, ConvertError> {
<T as FromGodot>::try_from_godot(via)
}
fn engine_try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
<T as FromGodot>::try_from_variant(variant)
}
}
#[macro_export]
macro_rules! impl_godot_as_self {
($T:ty: $Passing:ident) => {
impl $crate::meta::GodotConvert for $T {
type Via = $T;
fn godot_shape() -> $crate::meta::shape::GodotShape {
$crate::meta::shape::GodotShape::of_builtin::<$T>()
}
}
$crate::impl_godot_as_self!(@to_godot $T: $Passing);
impl $crate::meta::FromGodot for $T {
#[inline]
fn try_from_godot(via: Self::Via) -> Result<Self, $crate::meta::error::ConvertError> {
Ok(via)
}
}
};
(@to_godot $T:ty: ByValue) => {
impl $crate::meta::ToGodot for $T {
type Pass = $crate::meta::ByValue;
#[inline]
fn to_godot(&self) -> Self::Via {
self.clone()
}
}
};
(@to_godot $T:ty: ByRef) => {
impl $crate::meta::ToGodot for $T {
type Pass = $crate::meta::ByRef;
#[inline]
fn to_godot(&self) -> &Self::Via {
self
}
}
};
(@to_godot $T:ty: ByVariant) => {
impl $crate::meta::ToGodot for $T {
type Pass = $crate::meta::ByVariant;
#[inline]
fn to_godot(&self) -> &Self::Via {
self
}
}
};
}