godot_core/builtin/variant/
impls.rs

1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use 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
18// For godot-cpp, see https://github.com/godotengine/godot-cpp/blob/master/include/godot_cpp/core/type_info.hpp.
19
20// ----------------------------------------------------------------------------------------------------------------------------------------------
21// Macro definitions
22
23// Certain types need to be passed as initialized pointers in their from_variant implementations in 4.0. Because
24// 4.0 uses `*ptr = value` to return the type, and some types in C++ override `operator=` in C++ in a way
25// that requires the pointer to be initialized. But some other types will cause a memory leak in 4.1 if initialized.
26//
27// Therefore, we can use `init` to indicate when it must be initialized in 4.0.
28macro_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    // Implementations
37    (@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                // Type check -- at the moment, a strict match is required.
52                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// ----------------------------------------------------------------------------------------------------------------------------------------------
129// General impls
130
131#[rustfmt::skip]
132#[allow(clippy::module_inception)]
133mod impls {
134    use super::*;
135
136    // IMPORTANT: the presence/absence of `ref` here should be aligned with the ArgPassing variant
137    // used in codegen get_builtin_arg_passing().
138
139    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        // This should be kept in sync with crate::registry::signal::variadic.
219        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
243// Compile time check that we cover all the Variant types with trait implementations for:
244// - IntoDynamicSend
245// - DynamicSend
246// - GodotType
247// - ArrayElement
248const _: () = {
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    // The matched value is not relevant, we just want to ensure that the full list from 0 to MAX is covered.
309    #[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
357// ----------------------------------------------------------------------------------------------------------------------------------------------
358// Explicit impls
359
360// Unit
361impl 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}