Skip to main content

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;
9use sys::GodotFfi;
10
11use crate::builtin::*;
12use crate::meta::error::{ConvertError, FromVariantError};
13use crate::meta::sealed::Sealed;
14use crate::meta::{Element, GodotFfiVariant, GodotType, RefArg};
15use crate::registry::info::ParamMetadata;
16use crate::task::{DynamicSend, IntoDynamicSend, ThreadConfined, impl_dynamic_send};
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// Historical note: In Godot 4.0, certain types needed to be passed as initialized pointers in their from_variant implementations, because
24// 4.0 used `*ptr = value` to return the type, and some types in C++ override `operator=` in a way that requires the pointer to be initialized.
25// However, those same types would cause memory leaks in Godot 4.1 if pre-initialized. A compat layer `new_with_uninit_or_init()` addressed this.
26// As these Godot versions are no longer supported, the current implementation uses `new_with_uninit()` uniformly for all versions.
27macro_rules! impl_ffi_variant {
28    // With explicit metadata (e.g. for i64, f64).
29    (ref $T:ty, $from_fn:ident, $to_fn:ident; $metadata:expr) => {
30        impl_ffi_variant!(@impls by_ref, $metadata; $T, $from_fn, $to_fn);
31    };
32    ($T:ty, $from_fn:ident, $to_fn:ident; $metadata:expr) => {
33        impl_ffi_variant!(@impls by_val, $metadata; $T, $from_fn, $to_fn);
34    };
35
36    // Without metadata (defaults to ParamMetadata::NONE).
37    (ref $T:ty, $from_fn:ident, $to_fn:ident) => {
38        impl_ffi_variant!(@impls by_ref, ParamMetadata::NONE; $T, $from_fn, $to_fn);
39    };
40    ($T:ty, $from_fn:ident, $to_fn:ident) => {
41        impl_ffi_variant!(@impls by_val, ParamMetadata::NONE; $T, $from_fn, $to_fn);
42    };
43
44    // Implementations
45    (@impls $by_ref_or_val:ident, $metadata:expr; $T:ty, $from_fn:ident, $to_fn:ident) => {
46        impl GodotFfiVariant for $T {
47            fn ffi_to_variant(&self) -> Variant {
48                let variant = unsafe {
49                    Variant::new_with_var_uninit(|variant_ptr| {
50                        let converter = sys::builtin_fn!($from_fn);
51                        converter(variant_ptr, sys::SysPtr::force_mut(self.sys()));
52                    })
53                };
54
55                variant
56            }
57
58            fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
59                // Type check -- at the moment, a strict match is required.
60                if variant.get_type() != Self::VARIANT_TYPE.variant_as_nil() {
61                    return Err(FromVariantError::BadType {
62                        expected: Self::VARIANT_TYPE.variant_as_nil(),
63                        actual: variant.get_type(),
64                    }
65                    .into_error(variant.clone()));
66                }
67
68                let result = unsafe {
69                    Self::new_with_uninit(|self_ptr| {
70                        let converter = sys::builtin_fn!($to_fn);
71                        converter(self_ptr, sys::SysPtr::force_mut(variant.var_sys()));
72                    })
73                };
74
75                Ok(result)
76            }
77        }
78
79        impl GodotType for $T {
80            type Ffi = Self;
81            impl_ffi_variant!(@assoc_to_ffi $by_ref_or_val);
82
83            fn into_ffi(self) -> Self::Ffi {
84                self
85            }
86
87            fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError> {
88                Ok(ffi)
89            }
90
91            fn default_metadata() -> ParamMetadata {
92                $metadata
93            }
94        }
95
96        impl Element for $T {}
97    };
98
99    (@assoc_to_ffi by_ref) => {
100        type ToFfi<'a> =  RefArg<'a, Self>;
101
102        fn to_ffi(&self) -> Self::ToFfi<'_> {
103            RefArg::new(self)
104        }
105    };
106
107    (@assoc_to_ffi by_val) => {
108        type ToFfi<'a> = Self;
109
110        fn to_ffi(&self) -> Self::ToFfi<'_> {
111            self.clone()
112        }
113    };
114}
115
116// ----------------------------------------------------------------------------------------------------------------------------------------------
117// General impls
118
119#[rustfmt::skip]
120#[allow(clippy::module_inception)]
121mod impls {
122    use super::*;
123
124    // IMPORTANT: the presence/absence of `ref` here should be aligned with the ArgPassing variant
125    // used in codegen get_builtin_arg_passing().
126
127    impl_ffi_variant!(bool, bool_to_variant, bool_from_variant);
128    impl_ffi_variant!(i64, int_to_variant, int_from_variant; ParamMetadata::INT_IS_INT64);
129    impl_ffi_variant!(f64, float_to_variant, float_from_variant; ParamMetadata::REAL_IS_DOUBLE);
130    impl_ffi_variant!(Vector2, vector2_to_variant, vector2_from_variant);
131    impl_ffi_variant!(Vector3, vector3_to_variant, vector3_from_variant);
132    impl_ffi_variant!(Vector4, vector4_to_variant, vector4_from_variant);
133    impl_ffi_variant!(Vector2i, vector2i_to_variant, vector2i_from_variant);
134    impl_ffi_variant!(Vector3i, vector3i_to_variant, vector3i_from_variant);
135    impl_ffi_variant!(Vector4i, vector4i_to_variant, vector4i_from_variant);
136    impl_ffi_variant!(Quaternion, quaternion_to_variant, quaternion_from_variant);
137    impl_ffi_variant!(Transform2D, transform_2d_to_variant, transform_2d_from_variant);
138    impl_ffi_variant!(Transform3D, transform_3d_to_variant, transform_3d_from_variant);
139    impl_ffi_variant!(Basis, basis_to_variant, basis_from_variant);
140    impl_ffi_variant!(Projection, projection_to_variant, projection_from_variant);
141    impl_ffi_variant!(Plane, plane_to_variant, plane_from_variant);
142    impl_ffi_variant!(Rect2, rect2_to_variant, rect2_from_variant);
143    impl_ffi_variant!(Rect2i, rect2i_to_variant, rect2i_from_variant);
144    impl_ffi_variant!(Aabb, aabb_to_variant, aabb_from_variant);
145    impl_ffi_variant!(Color, color_to_variant, color_from_variant);
146    impl_ffi_variant!(Rid, rid_to_variant, rid_from_variant);
147    impl_ffi_variant!(ref GString, string_to_variant, string_from_variant);
148    impl_ffi_variant!(ref StringName, string_name_to_variant, string_name_from_variant);
149    impl_ffi_variant!(ref NodePath, node_path_to_variant, node_path_from_variant);
150    impl_ffi_variant!(ref Signal, signal_to_variant, signal_from_variant);
151    impl_ffi_variant!(ref Callable, callable_to_variant, callable_from_variant);
152}
153
154// ----------------------------------------------------------------------------------------------------------------------------------------------
155// Async trait support
156
157impl<T: Element> Sealed for ThreadConfined<Array<T>> {}
158
159unsafe impl<T: Element> DynamicSend for ThreadConfined<Array<T>> {
160    type Inner = Array<T>;
161    fn extract_if_safe(self) -> Option<Self::Inner> {
162        self.extract()
163    }
164}
165
166impl<T: Element> IntoDynamicSend for Array<T> {
167    type Target = ThreadConfined<Array<T>>;
168    fn into_dynamic_send(self) -> Self::Target {
169        ThreadConfined::new(self)
170    }
171}
172
173impl_dynamic_send!(
174    Send;
175    bool, u8, u16, u32, u64, i8, i16, i32, i64, f32, f64
176);
177
178impl_dynamic_send!(
179    Send;
180    StringName, Color, Rid,
181    Vector2, Vector2i, Vector2Axis,
182    Vector3, Vector3i, Vector3Axis,
183    Vector4, Vector4i,
184    Rect2, Rect2i, Aabb,
185    Transform2D, Transform3D, Basis,
186    Plane, Quaternion, Projection
187);
188
189impl_dynamic_send!(
190    !Send;
191    Variant, NodePath, GString, VarDictionary, Callable, Signal,
192    PackedByteArray, PackedInt32Array, PackedInt64Array, PackedFloat32Array, PackedFloat64Array, PackedStringArray,
193    PackedVector2Array, PackedVector3Array, PackedColorArray
194);
195
196// This should be kept in sync with crate::obj::signal::variadic.
197impl_dynamic_send!(tuple; );
198impl_dynamic_send!(tuple; arg1: A1);
199impl_dynamic_send!(tuple; arg1: A1, arg2: A2);
200impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3);
201impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4);
202impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5);
203impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6);
204impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7);
205impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7, arg8: A8);
206impl_dynamic_send!(tuple; arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, arg6: A6, arg7: A7, arg8: A8, arg9: A9);
207
208#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
209mod api_4_3 {
210    use crate::task::impl_dynamic_send;
211
212    impl_dynamic_send!(!Send; PackedVector4Array);
213}
214
215// ----------------------------------------------------------------------------------------------------------------------------------------------
216// Internal verification
217
218// Compile time check that we cover all the Variant types with trait implementations for:
219// - IntoDynamicSend
220// - DynamicSend
221// - GodotType
222// - Element
223const _: () = {
224    use crate::classes::Object;
225    use crate::obj::{Gd, IndexEnum};
226
227    const fn variant_type<T: crate::task::IntoDynamicSend + GodotType + Element>() -> VariantType {
228        <T::Ffi as sys::GodotFfi>::VARIANT_TYPE.variant_as_nil()
229    }
230
231    const NIL: VariantType = variant_type::<Variant>();
232    const BOOL: VariantType = variant_type::<bool>();
233    const I64: VariantType = variant_type::<i64>();
234    const F64: VariantType = variant_type::<f64>();
235    const GSTRING: VariantType = variant_type::<GString>();
236
237    const VECTOR2: VariantType = variant_type::<Vector2>();
238    const VECTOR2I: VariantType = variant_type::<Vector2i>();
239    const RECT2: VariantType = variant_type::<Rect2>();
240    const RECT2I: VariantType = variant_type::<Rect2i>();
241    const VECTOR3: VariantType = variant_type::<Vector3>();
242    const VECTOR3I: VariantType = variant_type::<Vector3i>();
243    const TRANSFORM2D: VariantType = variant_type::<Transform2D>();
244    const TRANSFORM3D: VariantType = variant_type::<Transform3D>();
245    const VECTOR4: VariantType = variant_type::<Vector4>();
246    const VECTOR4I: VariantType = variant_type::<Vector4i>();
247    const PLANE: VariantType = variant_type::<Plane>();
248    const QUATERNION: VariantType = variant_type::<Quaternion>();
249    const AABB: VariantType = variant_type::<Aabb>();
250    const BASIS: VariantType = variant_type::<Basis>();
251    const PROJECTION: VariantType = variant_type::<Projection>();
252    const COLOR: VariantType = variant_type::<Color>();
253    const STRING_NAME: VariantType = variant_type::<StringName>();
254    const NODE_PATH: VariantType = variant_type::<NodePath>();
255    const RID: VariantType = variant_type::<Rid>();
256    const OBJECT: VariantType = variant_type::<Gd<Object>>();
257    const CALLABLE: VariantType = variant_type::<Callable>();
258    const SIGNAL: VariantType = variant_type::<Signal>();
259    const DICTIONARY: VariantType = variant_type::<VarDictionary>();
260    const ARRAY: VariantType = variant_type::<VarArray>();
261    const PACKED_BYTE_ARRAY: VariantType = variant_type::<PackedByteArray>();
262    const PACKED_INT32_ARRAY: VariantType = variant_type::<PackedInt32Array>();
263    const PACKED_INT64_ARRAY: VariantType = variant_type::<PackedInt64Array>();
264    const PACKED_FLOAT32_ARRAY: VariantType = variant_type::<PackedFloat32Array>();
265    const PACKED_FLOAT64_ARRAY: VariantType = variant_type::<PackedFloat64Array>();
266    const PACKED_STRING_ARRAY: VariantType = variant_type::<PackedStringArray>();
267    const PACKED_VECTOR2_ARRAY: VariantType = variant_type::<PackedVector2Array>();
268    const PACKED_VECTOR3_ARRAY: VariantType = variant_type::<PackedVector3Array>();
269    const PACKED_COLOR_ARRAY: VariantType = variant_type::<PackedColorArray>();
270
271    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
272    const PACKED_VECTOR4_ARRAY: VariantType = variant_type::<PackedVector4Array>();
273
274    const MAX: i32 = VariantType::ENUMERATOR_COUNT as i32;
275
276    // The matched value is not relevant, we just want to ensure that the full list from 0 to MAX is covered.
277    #[deny(unreachable_patterns)]
278    match VariantType::STRING {
279        VariantType { ord: i32::MIN..0 } => panic!("ord is out of defined range!"),
280        NIL => (),
281        BOOL => (),
282        I64 => (),
283        F64 => (),
284        GSTRING => (),
285        VECTOR2 => (),
286        VECTOR2I => (),
287        RECT2 => (),
288        RECT2I => (),
289        VECTOR3 => (),
290        VECTOR3I => (),
291        TRANSFORM2D => (),
292        VECTOR4 => (),
293        VECTOR4I => (),
294        PLANE => (),
295        QUATERNION => (),
296        AABB => (),
297        BASIS => (),
298        TRANSFORM3D => (),
299        PROJECTION => (),
300        COLOR => (),
301        STRING_NAME => (),
302        NODE_PATH => (),
303        RID => (),
304        OBJECT => (),
305        CALLABLE => (),
306        SIGNAL => (),
307        DICTIONARY => (),
308        ARRAY => (),
309        PACKED_BYTE_ARRAY => (),
310        PACKED_INT32_ARRAY => (),
311        PACKED_INT64_ARRAY => (),
312        PACKED_FLOAT32_ARRAY => (),
313        PACKED_FLOAT64_ARRAY => (),
314        PACKED_STRING_ARRAY => (),
315        PACKED_VECTOR2_ARRAY => (),
316        PACKED_VECTOR3_ARRAY => (),
317        PACKED_COLOR_ARRAY => (),
318
319        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
320        PACKED_VECTOR4_ARRAY => (),
321        VariantType { ord: MAX.. } => panic!("ord is out of defined range!"),
322    }
323};
324
325// ----------------------------------------------------------------------------------------------------------------------------------------------
326// Explicit impls
327
328// Unit
329impl GodotFfiVariant for () {
330    fn ffi_to_variant(&self) -> Variant {
331        Variant::nil()
332    }
333
334    fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
335        if variant.is_nil() {
336            return Ok(());
337        }
338
339        Err(FromVariantError::BadType {
340            expected: VariantType::NIL,
341            actual: variant.get_type(),
342        }
343        .into_error(variant.clone()))
344    }
345}
346
347impl GodotType for () {
348    type Ffi = ();
349    type ToFfi<'a> = ();
350
351    fn to_ffi(&self) -> Self::ToFfi<'_> {}
352
353    fn into_ffi(self) -> Self::Ffi {}
354
355    fn try_from_ffi(_: Self::Ffi) -> Result<Self, ConvertError> {
356        Ok(())
357    }
358}
359
360impl GodotFfiVariant for Variant {
361    fn ffi_to_variant(&self) -> Variant {
362        self.clone()
363    }
364
365    fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
366        Ok(variant.clone())
367    }
368}
369
370impl GodotType for Variant {
371    type Ffi = Variant;
372    type ToFfi<'a> = RefArg<'a, Variant>;
373
374    fn to_ffi(&self) -> Self::ToFfi<'_> {
375        RefArg::new(self)
376    }
377
378    fn into_ffi(self) -> Self::Ffi {
379        self
380    }
381
382    fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError> {
383        Ok(ffi)
384    }
385}