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