1use godot_ffi as sys;
9use sys::GodotFfi;
10
11use crate::builtin::*;
12use crate::global;
13use crate::meta::error::{ConvertError, FromVariantError};
14use crate::meta::sealed::Sealed;
15use crate::meta::{
16 ArrayElement, GodotFfiVariant, GodotType, PropertyHintInfo, PropertyInfo, RefArg,
17};
18use crate::task::{impl_dynamic_send, DynamicSend, IntoDynamicSend, ThreadConfined};
19
20macro_rules! impl_ffi_variant {
30 (ref $T:ty, $from_fn:ident, $to_fn:ident $(; $GodotTy:ident)?) => {
31 impl_ffi_variant!(@impls by_ref; $T, $from_fn, $to_fn $(; $GodotTy)?);
32 };
33 ($T:ty, $from_fn:ident, $to_fn:ident $(; $GodotTy:ident)?) => {
34 impl_ffi_variant!(@impls by_val; $T, $from_fn, $to_fn $(; $GodotTy)?);
35 };
36
37 (@impls $by_ref_or_val:ident; $T:ty, $from_fn:ident, $to_fn:ident $(; $GodotTy:ident)?) => {
39 impl GodotFfiVariant for $T {
40 fn ffi_to_variant(&self) -> Variant {
41 let variant = unsafe {
42 Variant::new_with_var_uninit(|variant_ptr| {
43 let converter = sys::builtin_fn!($from_fn);
44 converter(variant_ptr, sys::SysPtr::force_mut(self.sys()));
45 })
46 };
47
48 variant
49 }
50
51 fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
52 if variant.get_type() != Self::VARIANT_TYPE.variant_as_nil() {
54 return Err(FromVariantError::BadType {
55 expected: Self::VARIANT_TYPE.variant_as_nil(),
56 actual: variant.get_type(),
57 }
58 .into_error(variant.clone()));
59 }
60
61 let result = unsafe {
62 Self::new_with_uninit(|self_ptr| {
63 let converter = sys::builtin_fn!($to_fn);
64 converter(self_ptr, sys::SysPtr::force_mut(variant.var_sys()));
65 })
66 };
67
68 Ok(result)
69 }
70 }
71
72 impl GodotType for $T {
73 type Ffi = Self;
74 impl_ffi_variant!(@assoc_to_ffi $by_ref_or_val);
75
76 fn into_ffi(self) -> Self::Ffi {
77 self
78 }
79
80 fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError> {
81 Ok(ffi)
82 }
83
84 impl_ffi_variant!(@godot_type_name $T $(, $GodotTy)?);
85 }
86
87 impl ArrayElement for $T {}
88 };
89
90 (@godot_type_name $T:ty) => {
91 fn godot_type_name() -> String {
92 stringify!($T).into()
93 }
94 };
95
96 (@godot_type_name $T:ty, $godot_type_name:ident) => {
97 fn godot_type_name() -> String {
98 stringify!($godot_type_name).into()
99 }
100 };
101
102 (@assoc_to_ffi by_ref) => {
103 type ToFfi<'a> = RefArg<'a, Self>;
104
105 fn to_ffi(&self) -> Self::ToFfi<'_> {
106 RefArg::new(self)
107 }
108 };
109
110 (@assoc_to_ffi by_val) => {
111 type ToFfi<'a> = Self;
112
113 fn to_ffi(&self) -> Self::ToFfi<'_> {
114 self.clone()
115 }
116 };
117}
118
119#[rustfmt::skip]
123#[allow(clippy::module_inception)]
124mod impls {
125 use super::*;
126
127 impl_ffi_variant!(bool, bool_to_variant, bool_from_variant);
131 impl_ffi_variant!(i64, int_to_variant, int_from_variant; int);
132 impl_ffi_variant!(f64, float_to_variant, float_from_variant; float);
133 impl_ffi_variant!(Vector2, vector2_to_variant, vector2_from_variant);
134 impl_ffi_variant!(Vector3, vector3_to_variant, vector3_from_variant);
135 impl_ffi_variant!(Vector4, vector4_to_variant, vector4_from_variant);
136 impl_ffi_variant!(Vector2i, vector2i_to_variant, vector2i_from_variant);
137 impl_ffi_variant!(Vector3i, vector3i_to_variant, vector3i_from_variant);
138 impl_ffi_variant!(Vector4i, vector4i_to_variant, vector4i_from_variant);
139 impl_ffi_variant!(Quaternion, quaternion_to_variant, quaternion_from_variant);
140 impl_ffi_variant!(Transform2D, transform_2d_to_variant, transform_2d_from_variant);
141 impl_ffi_variant!(Transform3D, transform_3d_to_variant, transform_3d_from_variant);
142 impl_ffi_variant!(Basis, basis_to_variant, basis_from_variant);
143 impl_ffi_variant!(Projection, projection_to_variant, projection_from_variant);
144 impl_ffi_variant!(Plane, plane_to_variant, plane_from_variant);
145 impl_ffi_variant!(Rect2, rect2_to_variant, rect2_from_variant);
146 impl_ffi_variant!(Rect2i, rect2i_to_variant, rect2i_from_variant);
147 impl_ffi_variant!(Aabb, aabb_to_variant, aabb_from_variant; AABB);
148 impl_ffi_variant!(Color, color_to_variant, color_from_variant);
149 impl_ffi_variant!(Rid, rid_to_variant, rid_from_variant; RID);
150 impl_ffi_variant!(ref GString, string_to_variant, string_from_variant; String);
151 impl_ffi_variant!(ref StringName, string_name_to_variant, string_name_from_variant);
152 impl_ffi_variant!(ref NodePath, node_path_to_variant, node_path_from_variant);
153 impl_ffi_variant!(ref Dictionary, dictionary_to_variant, dictionary_from_variant);
154 impl_ffi_variant!(ref Signal, signal_to_variant, signal_from_variant);
155 impl_ffi_variant!(ref Callable, callable_to_variant, callable_from_variant);
156}
157
158impl<T: ArrayElement> Sealed for ThreadConfined<Array<T>> {}
162
163unsafe impl<T: ArrayElement> DynamicSend for ThreadConfined<Array<T>> {
164 type Inner = Array<T>;
165 fn extract_if_safe(self) -> Option<Self::Inner> {
166 self.extract()
167 }
168}
169
170impl<T: ArrayElement> IntoDynamicSend for Array<T> {
171 type Target = ThreadConfined<Array<T>>;
172 fn into_dynamic_send(self) -> Self::Target {
173 ThreadConfined::new(self)
174 }
175}
176
177impl_dynamic_send!(
178 Send;
179 bool, u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
180);
181
182impl_dynamic_send!(
183 Send;
184 StringName, Color, Rid,
185 Vector2, Vector2i, Vector2Axis,
186 Vector3, Vector3i, Vector3Axis,
187 Vector4, Vector4i,
188 Rect2, Rect2i, Aabb,
189 Transform2D, Transform3D, Basis,
190 Plane, Quaternion, Projection
191);
192
193impl_dynamic_send!(
194 !Send;
195 Variant, NodePath, GString, Dictionary, Callable, Signal,
196 PackedByteArray, PackedInt32Array, PackedInt64Array, PackedFloat32Array, PackedFloat64Array, PackedStringArray,
197 PackedVector2Array, PackedVector3Array, PackedColorArray
198);
199
200impl_dynamic_send!(tuple; );
202impl_dynamic_send!(tuple; arg1: A1);
203impl_dynamic_send!(tuple; arg1: A1, arg2: A2);
204impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3);
205impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4);
206impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5);
207impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6);
208impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7);
209impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7, arg8: A8);
210impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7, arg8: A8, arg9: A9);
211
212#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
213mod api_4_3 {
214 use crate::task::impl_dynamic_send;
215
216 impl_dynamic_send!(!Send; PackedVector4Array);
217}
218
219const _: () = {
228 use crate::classes::Object;
229 use crate::obj::{Gd, IndexEnum};
230
231 const fn variant_type<T: crate::task::IntoDynamicSend + GodotType + ArrayElement>(
232 ) -> VariantType {
233 <T::Ffi as sys::GodotFfi>::VARIANT_TYPE.variant_as_nil()
234 }
235
236 const NIL: VariantType = variant_type::<Variant>();
237 const BOOL: VariantType = variant_type::<bool>();
238 const I64: VariantType = variant_type::<i64>();
239 const F64: VariantType = variant_type::<f64>();
240 const GSTRING: VariantType = variant_type::<GString>();
241
242 const VECTOR2: VariantType = variant_type::<Vector2>();
243 const VECTOR2I: VariantType = variant_type::<Vector2i>();
244 const RECT2: VariantType = variant_type::<Rect2>();
245 const RECT2I: VariantType = variant_type::<Rect2i>();
246 const VECTOR3: VariantType = variant_type::<Vector3>();
247 const VECTOR3I: VariantType = variant_type::<Vector3i>();
248 const TRANSFORM2D: VariantType = variant_type::<Transform2D>();
249 const TRANSFORM3D: VariantType = variant_type::<Transform3D>();
250 const VECTOR4: VariantType = variant_type::<Vector4>();
251 const VECTOR4I: VariantType = variant_type::<Vector4i>();
252 const PLANE: VariantType = variant_type::<Plane>();
253 const QUATERNION: VariantType = variant_type::<Quaternion>();
254 const AABB: VariantType = variant_type::<Aabb>();
255 const BASIS: VariantType = variant_type::<Basis>();
256 const PROJECTION: VariantType = variant_type::<Projection>();
257 const COLOR: VariantType = variant_type::<Color>();
258 const STRING_NAME: VariantType = variant_type::<StringName>();
259 const NODE_PATH: VariantType = variant_type::<NodePath>();
260 const RID: VariantType = variant_type::<Rid>();
261 const OBJECT: VariantType = variant_type::<Gd<Object>>();
262 const CALLABLE: VariantType = variant_type::<Callable>();
263 const SIGNAL: VariantType = variant_type::<Signal>();
264 const DICTIONARY: VariantType = variant_type::<Dictionary>();
265 const ARRAY: VariantType = variant_type::<VariantArray>();
266 const PACKED_BYTE_ARRAY: VariantType = variant_type::<PackedByteArray>();
267 const PACKED_INT32_ARRAY: VariantType = variant_type::<PackedInt32Array>();
268 const PACKED_INT64_ARRAY: VariantType = variant_type::<PackedInt64Array>();
269 const PACKED_FLOAT32_ARRAY: VariantType = variant_type::<PackedFloat32Array>();
270 const PACKED_FLOAT64_ARRAY: VariantType = variant_type::<PackedFloat64Array>();
271 const PACKED_STRING_ARRAY: VariantType = variant_type::<PackedStringArray>();
272 const PACKED_VECTOR2_ARRAY: VariantType = variant_type::<PackedVector2Array>();
273 const PACKED_VECTOR3_ARRAY: VariantType = variant_type::<PackedVector3Array>();
274 const PACKED_COLOR_ARRAY: VariantType = variant_type::<PackedColorArray>();
275
276 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
277 const PACKED_VECTOR4_ARRAY: VariantType = variant_type::<PackedVector4Array>();
278
279 const MAX: i32 = VariantType::ENUMERATOR_COUNT as i32;
280
281 #[deny(unreachable_patterns)]
283 match VariantType::STRING {
284 VariantType { ord: i32::MIN..0 } => panic!("ord is out of defined range!"),
285 NIL => (),
286 BOOL => (),
287 I64 => (),
288 F64 => (),
289 GSTRING => (),
290 VECTOR2 => (),
291 VECTOR2I => (),
292 RECT2 => (),
293 RECT2I => (),
294 VECTOR3 => (),
295 VECTOR3I => (),
296 TRANSFORM2D => (),
297 VECTOR4 => (),
298 VECTOR4I => (),
299 PLANE => (),
300 QUATERNION => (),
301 AABB => (),
302 BASIS => (),
303 TRANSFORM3D => (),
304 PROJECTION => (),
305 COLOR => (),
306 STRING_NAME => (),
307 NODE_PATH => (),
308 RID => (),
309 OBJECT => (),
310 CALLABLE => (),
311 SIGNAL => (),
312 DICTIONARY => (),
313 ARRAY => (),
314 PACKED_BYTE_ARRAY => (),
315 PACKED_INT32_ARRAY => (),
316 PACKED_INT64_ARRAY => (),
317 PACKED_FLOAT32_ARRAY => (),
318 PACKED_FLOAT64_ARRAY => (),
319 PACKED_STRING_ARRAY => (),
320 PACKED_VECTOR2_ARRAY => (),
321 PACKED_VECTOR3_ARRAY => (),
322 PACKED_COLOR_ARRAY => (),
323
324 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
325 PACKED_VECTOR4_ARRAY => (),
326 VariantType { ord: MAX.. } => panic!("ord is out of defined range!"),
327 }
328};
329
330impl GodotFfiVariant for () {
335 fn ffi_to_variant(&self) -> Variant {
336 Variant::nil()
337 }
338
339 fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
340 if variant.is_nil() {
341 return Ok(());
342 }
343
344 Err(FromVariantError::BadType {
345 expected: VariantType::NIL,
346 actual: variant.get_type(),
347 }
348 .into_error(variant.clone()))
349 }
350}
351
352impl GodotType for () {
353 type Ffi = ();
354 type ToFfi<'a> = ();
355
356 fn to_ffi(&self) -> Self::ToFfi<'_> {}
357
358 fn into_ffi(self) -> Self::Ffi {}
359
360 fn try_from_ffi(_: Self::Ffi) -> Result<Self, ConvertError> {
361 Ok(())
362 }
363
364 fn godot_type_name() -> String {
365 "Variant".to_string()
366 }
367}
368
369impl GodotFfiVariant for Variant {
370 fn ffi_to_variant(&self) -> Variant {
371 self.clone()
372 }
373
374 fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
375 Ok(variant.clone())
376 }
377}
378
379impl GodotType for Variant {
380 type Ffi = Variant;
381 type ToFfi<'a> = RefArg<'a, Variant>;
382
383 fn to_ffi(&self) -> Self::ToFfi<'_> {
384 RefArg::new(self)
385 }
386
387 fn into_ffi(self) -> Self::Ffi {
388 self
389 }
390
391 fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError> {
392 Ok(ffi)
393 }
394
395 fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
396 sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE
397 }
398
399 fn property_info(property_name: &str) -> PropertyInfo {
400 PropertyInfo {
401 variant_type: Self::VARIANT_TYPE.variant_as_nil(),
402 class_id: Self::class_id(),
403 property_name: StringName::from(property_name),
404 hint_info: PropertyHintInfo::none(),
405 usage: global::PropertyUsageFlags::DEFAULT | global::PropertyUsageFlags::NIL_IS_VARIANT,
406 }
407 }
408
409 fn godot_type_name() -> String {
410 "Variant".to_string()
411 }
412}