use godot_ffi as sys;
use sys::GodotFfi;
use crate::builtin::*;
use crate::meta::error::{ConvertError, FromVariantError};
use crate::meta::sealed::Sealed;
use crate::meta::{Element, GodotFfiVariant, GodotType, RefArg};
use crate::registry::info::ParamMetadata;
use crate::task::{DynamicSend, IntoDynamicSend, ThreadConfined, impl_dynamic_send};
macro_rules! impl_ffi_variant {
(ref $T:ty, $from_fn:ident, $to_fn:ident; $metadata:expr) => {
impl_ffi_variant!(@impls by_ref, $metadata; $T, $from_fn, $to_fn);
};
($T:ty, $from_fn:ident, $to_fn:ident; $metadata:expr) => {
impl_ffi_variant!(@impls by_val, $metadata; $T, $from_fn, $to_fn);
};
(ref $T:ty, $from_fn:ident, $to_fn:ident) => {
impl_ffi_variant!(@impls by_ref, ParamMetadata::NONE; $T, $from_fn, $to_fn);
};
($T:ty, $from_fn:ident, $to_fn:ident) => {
impl_ffi_variant!(@impls by_val, ParamMetadata::NONE; $T, $from_fn, $to_fn);
};
(@impls $by_ref_or_val:ident, $metadata:expr; $T:ty, $from_fn:ident, $to_fn:ident) => {
impl GodotFfiVariant for $T {
fn ffi_to_variant(&self) -> Variant {
let variant = unsafe {
Variant::new_with_var_uninit(|variant_ptr| {
let converter = sys::builtin_fn!($from_fn);
converter(variant_ptr, sys::SysPtr::force_mut(self.sys()));
})
};
variant
}
fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
if variant.get_type() != Self::VARIANT_TYPE.variant_as_nil() {
return Err(FromVariantError::BadType {
expected: Self::VARIANT_TYPE.variant_as_nil(),
actual: variant.get_type(),
}
.into_error(variant.clone()));
}
let result = unsafe {
Self::new_with_uninit(|self_ptr| {
let converter = sys::builtin_fn!($to_fn);
converter(self_ptr, sys::SysPtr::force_mut(variant.var_sys()));
})
};
Ok(result)
}
}
impl GodotType for $T {
type Ffi = Self;
impl_ffi_variant!(@assoc_to_ffi $by_ref_or_val);
fn into_ffi(self) -> Self::Ffi {
self
}
fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError> {
Ok(ffi)
}
fn default_metadata() -> ParamMetadata {
$metadata
}
}
impl Element for $T {}
};
(@assoc_to_ffi by_ref) => {
type ToFfi<'a> = RefArg<'a, Self>;
fn to_ffi(&self) -> Self::ToFfi<'_> {
RefArg::new(self)
}
};
(@assoc_to_ffi by_val) => {
type ToFfi<'a> = Self;
fn to_ffi(&self) -> Self::ToFfi<'_> {
self.clone()
}
};
}
#[rustfmt::skip]
#[allow(clippy::module_inception)]
mod impls {
use super::*;
impl_ffi_variant!(bool, bool_to_variant, bool_from_variant);
impl_ffi_variant!(i64, int_to_variant, int_from_variant; ParamMetadata::INT_IS_INT64);
impl_ffi_variant!(f64, float_to_variant, float_from_variant; ParamMetadata::REAL_IS_DOUBLE);
impl_ffi_variant!(Vector2, vector2_to_variant, vector2_from_variant);
impl_ffi_variant!(Vector3, vector3_to_variant, vector3_from_variant);
impl_ffi_variant!(Vector4, vector4_to_variant, vector4_from_variant);
impl_ffi_variant!(Vector2i, vector2i_to_variant, vector2i_from_variant);
impl_ffi_variant!(Vector3i, vector3i_to_variant, vector3i_from_variant);
impl_ffi_variant!(Vector4i, vector4i_to_variant, vector4i_from_variant);
impl_ffi_variant!(Quaternion, quaternion_to_variant, quaternion_from_variant);
impl_ffi_variant!(Transform2D, transform_2d_to_variant, transform_2d_from_variant);
impl_ffi_variant!(Transform3D, transform_3d_to_variant, transform_3d_from_variant);
impl_ffi_variant!(Basis, basis_to_variant, basis_from_variant);
impl_ffi_variant!(Projection, projection_to_variant, projection_from_variant);
impl_ffi_variant!(Plane, plane_to_variant, plane_from_variant);
impl_ffi_variant!(Rect2, rect2_to_variant, rect2_from_variant);
impl_ffi_variant!(Rect2i, rect2i_to_variant, rect2i_from_variant);
impl_ffi_variant!(Aabb, aabb_to_variant, aabb_from_variant);
impl_ffi_variant!(Color, color_to_variant, color_from_variant);
impl_ffi_variant!(Rid, rid_to_variant, rid_from_variant);
impl_ffi_variant!(ref GString, string_to_variant, string_from_variant);
impl_ffi_variant!(ref StringName, string_name_to_variant, string_name_from_variant);
impl_ffi_variant!(ref NodePath, node_path_to_variant, node_path_from_variant);
impl_ffi_variant!(ref Signal, signal_to_variant, signal_from_variant);
impl_ffi_variant!(ref Callable, callable_to_variant, callable_from_variant);
}
impl<T: Element> Sealed for ThreadConfined<Array<T>> {}
unsafe impl<T: Element> DynamicSend for ThreadConfined<Array<T>> {
type Inner = Array<T>;
fn extract_if_safe(self) -> Option<Self::Inner> {
self.extract()
}
}
impl<T: Element> IntoDynamicSend for Array<T> {
type Target = ThreadConfined<Array<T>>;
fn into_dynamic_send(self) -> Self::Target {
ThreadConfined::new(self)
}
}
impl_dynamic_send!(
Send;
bool, u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
);
impl_dynamic_send!(
Send;
StringName, Color, Rid,
Vector2, Vector2i, Vector2Axis,
Vector3, Vector3i, Vector3Axis,
Vector4, Vector4i,
Rect2, Rect2i, Aabb,
Transform2D, Transform3D, Basis,
Plane, Quaternion, Projection
);
impl_dynamic_send!(
!Send;
Variant, NodePath, GString, VarDictionary, Callable, Signal,
PackedByteArray, PackedInt32Array, PackedInt64Array, PackedFloat32Array, PackedFloat64Array, PackedStringArray,
PackedVector2Array, PackedVector3Array, PackedColorArray
);
impl_dynamic_send!(tuple; );
impl_dynamic_send!(tuple; arg1: A1);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7, arg8: A8);
impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7, arg8: A8, arg9: A9);
#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
mod api_4_3 {
use crate::task::impl_dynamic_send;
impl_dynamic_send!(!Send; PackedVector4Array);
}
const _: () = {
use crate::classes::Object;
use crate::obj::{Gd, IndexEnum};
const fn variant_type<T: crate::task::IntoDynamicSend + GodotType + Element>() -> VariantType {
<T::Ffi as sys::GodotFfi>::VARIANT_TYPE.variant_as_nil()
}
const NIL: VariantType = variant_type::<Variant>();
const BOOL: VariantType = variant_type::<bool>();
const I64: VariantType = variant_type::<i64>();
const F64: VariantType = variant_type::<f64>();
const GSTRING: VariantType = variant_type::<GString>();
const VECTOR2: VariantType = variant_type::<Vector2>();
const VECTOR2I: VariantType = variant_type::<Vector2i>();
const RECT2: VariantType = variant_type::<Rect2>();
const RECT2I: VariantType = variant_type::<Rect2i>();
const VECTOR3: VariantType = variant_type::<Vector3>();
const VECTOR3I: VariantType = variant_type::<Vector3i>();
const TRANSFORM2D: VariantType = variant_type::<Transform2D>();
const TRANSFORM3D: VariantType = variant_type::<Transform3D>();
const VECTOR4: VariantType = variant_type::<Vector4>();
const VECTOR4I: VariantType = variant_type::<Vector4i>();
const PLANE: VariantType = variant_type::<Plane>();
const QUATERNION: VariantType = variant_type::<Quaternion>();
const AABB: VariantType = variant_type::<Aabb>();
const BASIS: VariantType = variant_type::<Basis>();
const PROJECTION: VariantType = variant_type::<Projection>();
const COLOR: VariantType = variant_type::<Color>();
const STRING_NAME: VariantType = variant_type::<StringName>();
const NODE_PATH: VariantType = variant_type::<NodePath>();
const RID: VariantType = variant_type::<Rid>();
const OBJECT: VariantType = variant_type::<Gd<Object>>();
const CALLABLE: VariantType = variant_type::<Callable>();
const SIGNAL: VariantType = variant_type::<Signal>();
const DICTIONARY: VariantType = variant_type::<VarDictionary>();
const ARRAY: VariantType = variant_type::<VarArray>();
const PACKED_BYTE_ARRAY: VariantType = variant_type::<PackedByteArray>();
const PACKED_INT32_ARRAY: VariantType = variant_type::<PackedInt32Array>();
const PACKED_INT64_ARRAY: VariantType = variant_type::<PackedInt64Array>();
const PACKED_FLOAT32_ARRAY: VariantType = variant_type::<PackedFloat32Array>();
const PACKED_FLOAT64_ARRAY: VariantType = variant_type::<PackedFloat64Array>();
const PACKED_STRING_ARRAY: VariantType = variant_type::<PackedStringArray>();
const PACKED_VECTOR2_ARRAY: VariantType = variant_type::<PackedVector2Array>();
const PACKED_VECTOR3_ARRAY: VariantType = variant_type::<PackedVector3Array>();
const PACKED_COLOR_ARRAY: VariantType = variant_type::<PackedColorArray>();
#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
const PACKED_VECTOR4_ARRAY: VariantType = variant_type::<PackedVector4Array>();
const MAX: i32 = VariantType::ENUMERATOR_COUNT as i32;
#[deny(unreachable_patterns)]
match VariantType::STRING {
VariantType { ord: i32::MIN..0 } => panic!("ord is out of defined range!"),
NIL => (),
BOOL => (),
I64 => (),
F64 => (),
GSTRING => (),
VECTOR2 => (),
VECTOR2I => (),
RECT2 => (),
RECT2I => (),
VECTOR3 => (),
VECTOR3I => (),
TRANSFORM2D => (),
VECTOR4 => (),
VECTOR4I => (),
PLANE => (),
QUATERNION => (),
AABB => (),
BASIS => (),
TRANSFORM3D => (),
PROJECTION => (),
COLOR => (),
STRING_NAME => (),
NODE_PATH => (),
RID => (),
OBJECT => (),
CALLABLE => (),
SIGNAL => (),
DICTIONARY => (),
ARRAY => (),
PACKED_BYTE_ARRAY => (),
PACKED_INT32_ARRAY => (),
PACKED_INT64_ARRAY => (),
PACKED_FLOAT32_ARRAY => (),
PACKED_FLOAT64_ARRAY => (),
PACKED_STRING_ARRAY => (),
PACKED_VECTOR2_ARRAY => (),
PACKED_VECTOR3_ARRAY => (),
PACKED_COLOR_ARRAY => (),
#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
PACKED_VECTOR4_ARRAY => (),
VariantType { ord: MAX.. } => panic!("ord is out of defined range!"),
}
};
impl GodotFfiVariant for () {
fn ffi_to_variant(&self) -> Variant {
Variant::nil()
}
fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
if variant.is_nil() {
return Ok(());
}
Err(FromVariantError::BadType {
expected: VariantType::NIL,
actual: variant.get_type(),
}
.into_error(variant.clone()))
}
}
impl GodotType for () {
type Ffi = ();
type ToFfi<'a> = ();
fn to_ffi(&self) -> Self::ToFfi<'_> {}
fn into_ffi(self) -> Self::Ffi {}
fn try_from_ffi(_: Self::Ffi) -> Result<Self, ConvertError> {
Ok(())
}
}
impl GodotFfiVariant for Variant {
fn ffi_to_variant(&self) -> Variant {
self.clone()
}
fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
Ok(variant.clone())
}
}
impl GodotType for Variant {
type Ffi = Variant;
type ToFfi<'a> = RefArg<'a, Variant>;
fn to_ffi(&self) -> Self::ToFfi<'_> {
RefArg::new(self)
}
fn into_ffi(self) -> Self::Ffi {
self
}
fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError> {
Ok(ffi)
}
}