diff --git a/godot-codegen/src/util.rs b/godot-codegen/src/util.rs index c27007360..26bfb79b9 100644 --- a/godot-codegen/src/util.rs +++ b/godot-codegen/src/util.rs @@ -335,18 +335,18 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream { #index_enum_impl impl crate::builtin::meta::GodotCompatible for #enum_name { - type Via = i64; + type Via = i32; } impl crate::builtin::meta::ToGodot for #enum_name { fn to_godot(&self) -> Self::Via { - ::ord(*self) as i64 + ::ord(*self) } } impl crate::builtin::meta::FromGodot for #enum_name { fn try_from_godot(via: Self::Via) -> Option { - ::try_from_ord(i32::try_from(via).ok()?) + ::try_from_ord(via) } } diff --git a/godot-core/src/builtin/meta/godot_compat/impls.rs b/godot-core/src/builtin/meta/godot_compat/impls.rs deleted file mode 100644 index 21152e105..000000000 --- a/godot-core/src/builtin/meta/godot_compat/impls.rs +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -use crate::builtin::meta::GodotType; - -use super::*; - -impl GodotCompatible for Option -where - Option: GodotType, -{ - type Via = Option; -} - -impl ToGodot for Option -where - Option: GodotType, -{ - fn to_godot(&self) -> Self::Via { - self.as_ref().map(ToGodot::to_godot) - } - - fn into_godot(self) -> Self::Via { - self.map(ToGodot::into_godot) - } -} - -impl FromGodot for Option -where - Option: GodotType, -{ - fn try_from_godot(via: Self::Via) -> Option { - match via { - Some(via) => T::try_from_godot(via).map(Some), - None => Some(None), - } - } - - fn from_godot(via: Self::Via) -> Self { - via.map(T::from_godot) - } -} - -impl GodotCompatible for sys::VariantType { - type Via = i32; -} - -impl ToGodot for sys::VariantType { - fn to_godot(&self) -> Self::Via { - *self as i32 - } - - fn into_godot(self) -> Self::Via { - self as i32 - } -} - -impl FromGodot for sys::VariantType { - fn try_from_godot(via: Self::Via) -> Option { - Some(Self::from_sys(via as sys::GDExtensionVariantType)) - } -} - -impl GodotCompatible for sys::VariantOperator { - type Via = i32; -} - -impl ToGodot for sys::VariantOperator { - fn to_godot(&self) -> Self::Via { - *self as i32 - } - - fn into_godot(self) -> Self::Via { - self as i32 - } -} - -impl FromGodot for sys::VariantOperator { - fn try_from_godot(via: Self::Via) -> Option { - Some(Self::from_sys(via as sys::GDExtensionVariantOperator)) - } -} - -impl GodotCompatible for *mut T { - type Via = i64; -} - -impl ToGodot for *mut T { - fn to_godot(&self) -> Self::Via { - *self as i64 - } -} - -impl FromGodot for *mut T { - fn try_from_godot(via: Self::Via) -> Option { - Some(via as Self) - } -} - -impl GodotCompatible for *const T { - type Via = i64; -} - -impl ToGodot for *const T { - fn to_godot(&self) -> Self::Via { - *self as i64 - } -} - -impl FromGodot for *const T { - fn try_from_godot(via: Self::Via) -> Option { - Some(via as Self) - } -} - -mod scalars { - use super::{impl_godot_as_self, FromGodot, GodotCompatible, ToGodot}; - use crate::builtin::meta::GodotType; - use godot_ffi as sys; - - macro_rules! impl_godot { - ($T:ty as $Via:ty $(, $param_metadata:expr)?) => { - impl GodotType for $T { - type Ffi = $Via; - - fn to_ffi(&self) -> Self::Ffi { - (*self).into() - } - - fn into_ffi(self) -> Self::Ffi { - self.into() - } - - fn try_from_ffi(ffi: Self::Ffi) -> Option { - Self::try_from(ffi).ok() - } - - $( - fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata { - $param_metadata - } - )? - } - - impl GodotCompatible for $T { - type Via = $T; - } - - impl ToGodot for $T { - fn to_godot(&self) -> Self::Via { - *self - } - } - - impl FromGodot for $T { - fn try_from_godot(via: Self::Via) -> Option { - Some(via) - } - } - }; - ($T:ty as $Via:ty $(, $param_metadata:expr)?; lossy) => { - impl GodotType for $T { - type Ffi = $Via; - - fn to_ffi(&self) -> Self::Ffi { - *self as $Via - } - - fn into_ffi(self) -> Self::Ffi { - self as $Via - } - - fn try_from_ffi(ffi: Self::Ffi) -> Option { - Some(ffi as $T) - } - - $( - fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata { - $param_metadata - } - )? - } - - impl GodotCompatible for $T { - type Via = $T; - } - - impl ToGodot for $T { - fn to_godot(&self) -> Self::Via { - *self - } - } - - impl FromGodot for $T { - fn try_from_godot(via: Self::Via) -> Option { - Some(via) - } - } - }; - } - - impl_godot_as_self!(bool); - impl_godot_as_self!(i64, sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64); - impl_godot_as_self!( - f64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE - ); - impl_godot_as_self!(()); - - impl_godot!( - i32 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32 - ); - impl_godot!( - i16 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16 - ); - impl_godot!( - i8 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8 - ); - impl_godot!( - u32 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32 - ); - impl_godot!( - u16 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16 - ); - impl_godot!( - u8 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8 - ); - - impl_godot!( - u64 as i64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64; - lossy - ); - impl_godot!( - f32 as f64, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT; - lossy - ); -} diff --git a/godot-core/src/builtin/meta/godot_compatible/impls.rs b/godot-core/src/builtin/meta/godot_compatible/impls.rs new file mode 100644 index 000000000..ef8a59ab9 --- /dev/null +++ b/godot-core/src/builtin/meta/godot_compatible/impls.rs @@ -0,0 +1,252 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use crate::builtin::meta::{impl_godot_as_self, FromGodot, GodotCompatible, GodotType, ToGodot}; +use godot_ffi as sys; + +// ---------------------------------------------------------------------------------------------------------------------------------------------- +// Option + +impl GodotCompatible for Option +where + Option: GodotType, +{ + type Via = Option; +} + +impl ToGodot for Option +where + Option: GodotType, +{ + fn to_godot(&self) -> Self::Via { + self.as_ref().map(ToGodot::to_godot) + } + + fn into_godot(self) -> Self::Via { + self.map(ToGodot::into_godot) + } +} + +impl FromGodot for Option +where + Option: GodotType, +{ + fn try_from_godot(via: Self::Via) -> Option { + match via { + Some(via) => T::try_from_godot(via).map(Some), + None => Some(None), + } + } + + fn from_godot(via: Self::Via) -> Self { + via.map(T::from_godot) + } +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- +// Builtin Godot types + +impl GodotCompatible for sys::VariantType { + type Via = i32; +} + +impl ToGodot for sys::VariantType { + fn to_godot(&self) -> Self::Via { + *self as i32 + } + + fn into_godot(self) -> Self::Via { + self as i32 + } +} + +impl FromGodot for sys::VariantType { + fn try_from_godot(via: Self::Via) -> Option { + Some(Self::from_sys(via as sys::GDExtensionVariantType)) + } +} + +impl GodotCompatible for sys::VariantOperator { + type Via = i32; +} + +impl ToGodot for sys::VariantOperator { + fn to_godot(&self) -> Self::Via { + *self as i32 + } + + fn into_godot(self) -> Self::Via { + self as i32 + } +} + +impl FromGodot for sys::VariantOperator { + fn try_from_godot(via: Self::Via) -> Option { + Some(Self::from_sys(via as sys::GDExtensionVariantOperator)) + } +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- +// Pointers + +impl GodotCompatible for *mut T { + type Via = i64; +} + +impl ToGodot for *mut T { + fn to_godot(&self) -> Self::Via { + *self as i64 + } +} + +impl FromGodot for *mut T { + fn try_from_godot(via: Self::Via) -> Option { + Some(via as Self) + } +} + +impl GodotCompatible for *const T { + type Via = i64; +} + +impl ToGodot for *const T { + fn to_godot(&self) -> Self::Via { + *self as i64 + } +} + +impl FromGodot for *const T { + fn try_from_godot(via: Self::Via) -> Option { + Some(via as Self) + } +} + +// ---------------------------------------------------------------------------------------------------------------------------------------------- +// Scalars + +macro_rules! impl_godot_scalar { + ($T:ty as $Via:ty $(, $param_metadata:expr)?) => { + impl GodotType for $T { + type Ffi = $Via; + + fn to_ffi(&self) -> Self::Ffi { + (*self).into() + } + + fn into_ffi(self) -> Self::Ffi { + self.into() + } + + fn try_from_ffi(ffi: Self::Ffi) -> Option { + Self::try_from(ffi).ok() + } + + $( + fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata { + $param_metadata + } + )? + } + + impl GodotCompatible for $T { + type Via = $T; + } + + impl ToGodot for $T { + fn to_godot(&self) -> Self::Via { + *self + } + } + + impl FromGodot for $T { + fn try_from_godot(via: Self::Via) -> Option { + Some(via) + } + } + }; + + ($T:ty as $Via:ty $(, $param_metadata:expr)?; lossy) => { + impl GodotType for $T { + type Ffi = $Via; + + fn to_ffi(&self) -> Self::Ffi { + *self as $Via + } + + fn into_ffi(self) -> Self::Ffi { + self as $Via + } + + fn try_from_ffi(ffi: Self::Ffi) -> Option { + Some(ffi as $T) + } + + $( + fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata { + $param_metadata + } + )? + } + + impl GodotCompatible for $T { + type Via = $T; + } + + impl ToGodot for $T { + fn to_godot(&self) -> Self::Via { + *self + } + } + + impl FromGodot for $T { + fn try_from_godot(via: Self::Via) -> Option { + Some(via) + } + } + }; +} + +// `GodotType` for these three is implemented in `godot-core/src/builtin/variant/impls.rs`. +impl_godot_as_self!(bool); +impl_godot_as_self!(i64); +impl_godot_as_self!(f64); +impl_godot_as_self!(()); + +impl_godot_scalar!( + i32 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32 +); +impl_godot_scalar!( + i16 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16 +); +impl_godot_scalar!( + i8 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8 +); +impl_godot_scalar!( + u32 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32 +); +impl_godot_scalar!( + u16 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16 +); +impl_godot_scalar!( + u8 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8 +); + +impl_godot_scalar!( + u64 as i64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64; + lossy +); +impl_godot_scalar!( + f32 as f64, + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT; + lossy +); diff --git a/godot-core/src/builtin/meta/godot_compat/mod.rs b/godot-core/src/builtin/meta/godot_compatible/mod.rs similarity index 95% rename from godot-core/src/builtin/meta/godot_compat/mod.rs rename to godot-core/src/builtin/meta/godot_compatible/mod.rs index f1c03a276..69b95fffa 100644 --- a/godot-core/src/builtin/meta/godot_compat/mod.rs +++ b/godot-core/src/builtin/meta/godot_compatible/mod.rs @@ -6,8 +6,6 @@ mod impls; -use godot_ffi as sys; - use crate::builtin::{Variant, VariantConversionError}; use super::{GodotFfiVariant, GodotType}; @@ -34,6 +32,9 @@ pub trait ToGodot: Sized + GodotCompatible { fn to_godot(&self) -> Self::Via; /// Converts this type to the Godot type. + /// + /// This can in some cases enable some optimizations, such as avoiding reference counting for + /// reference-counted values. fn into_godot(self) -> Self::Via { self.to_godot() } @@ -54,6 +55,7 @@ pub trait ToGodot: Sized + GodotCompatible { pub trait FromGodot: Sized + GodotCompatible { // TODO: better error /// Performs the conversion. + #[must_use] fn try_from_godot(via: Self::Via) -> Option; /// ⚠️ Performs the conversion. @@ -91,7 +93,7 @@ pub(crate) fn try_from_ffi(ffi: ::Ffi) -> Opt } macro_rules! impl_godot_as_self { - ($T:ty$(, $param_metadata:expr)?) => { + ($T:ty) => { impl $crate::builtin::meta::GodotCompatible for $T { type Via = $T; } diff --git a/godot-core/src/builtin/meta/mod.rs b/godot-core/src/builtin/meta/mod.rs index 78f2f06b5..5bc2e89de 100644 --- a/godot-core/src/builtin/meta/mod.rs +++ b/godot-core/src/builtin/meta/mod.rs @@ -7,12 +7,12 @@ pub mod registration; mod class_name; -mod godot_compat; +mod godot_compatible; mod return_marshal; mod signature; pub use class_name::*; -pub use godot_compat::*; +pub use godot_compatible::*; #[doc(hidden)] pub use return_marshal::*; #[doc(hidden)] @@ -101,7 +101,10 @@ mod sealed { /// Types that can represent some Godot type. /// /// This trait cannot be implemented for custom user types, for that you should see [`GodotCompatible`] -/// instead. +/// instead. A type implements `GodotType` when it can directly represent some primitive type exposed by +/// Godot. For instance, [`i64`] implements `GodotType`, since it can be directly represented by Godot's +/// `int` type. But [`VariantType`] does not implement `GodotType`. Since while it is an enum Godot uses, we +/// have no native way to indicate to Godot that a value should be one of the variants of `VariantType`. /// /// Unlike [`GodotFfi`], types implementing this trait don't need to fully represent its corresponding Godot /// type. For instance [`i32`] does not implement [`GodotFfi`] because it cannot represent all values of diff --git a/godot-core/src/builtin/variant/impls.rs b/godot-core/src/builtin/variant/impls.rs index 539697340..94c40f4c3 100644 --- a/godot-core/src/builtin/variant/impls.rs +++ b/godot-core/src/builtin/variant/impls.rs @@ -188,4 +188,8 @@ impl GodotType for Variant { usage: global::PropertyUsageFlags::PROPERTY_USAGE_NIL_IS_VARIANT, } } + + fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata { + sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8 + } } diff --git a/godot-core/src/builtin/variant/mod.rs b/godot-core/src/builtin/variant/mod.rs index 04d96cf4d..43b902307 100644 --- a/godot-core/src/builtin/variant/mod.rs +++ b/godot-core/src/builtin/variant/mod.rs @@ -274,10 +274,7 @@ unsafe impl GodotFfi for Variant { } } -impl_godot_as_self!( - Variant, - sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8 -); +impl_godot_as_self!(Variant); impl Clone for Variant { fn clone(&self) -> Self { diff --git a/godot-ffi/src/godot_ffi.rs b/godot-ffi/src/godot_ffi.rs index b829939a9..a68ea76ba 100644 --- a/godot-ffi/src/godot_ffi.rs +++ b/godot-ffi/src/godot_ffi.rs @@ -137,6 +137,9 @@ pub unsafe fn from_sys_init_or_init_default( /// Types that can represent null-values. /// /// Used to blanket implement various conversions over `Option`. +/// +/// This is currently only implemented for `RawGd`. +// TODO: Consider implementing for `Variant`. pub trait GodotNullableFfi: Sized + GodotFfi { fn flatten_option(opt: Option) -> Self; fn is_null(&self) -> bool;