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