Skip to main content

godot_core/meta/
traits.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 crate::builtin;
11use crate::builtin::{Variant, VariantType};
12use crate::meta::error::ConvertError;
13use crate::meta::{FromGodot, GodotConvert, ToGodot, sealed};
14use crate::registry::info::ParamMetadata;
15
16// Re-export sys traits in this module, so all are in one place.
17#[rustfmt::skip] // Do not reorder.
18pub use sys::{ExtVariantType, GodotFfi};
19
20pub use crate::builtin::meta_reexport::PackedElement;
21
22/// Conversion of [`GodotFfi`] types to/from [`Variant`].
23#[doc(hidden)]
24pub trait GodotFfiVariant: Sized + GodotFfi {
25    fn ffi_to_variant(&self) -> Variant;
26    fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError>;
27}
28
29/// Type that is directly representable in the engine.
30///
31/// This trait cannot be implemented for custom user types; for those, [`GodotConvert`] exists instead.
32/// A type implements `GodotType` when Godot has a direct, native representation for it. For instance:
33/// - [`i64`] implements `GodotType`, since it can be directly represented by Godot's `int` type.
34/// - But [`VariantType`][crate::builtin::VariantType] does not implement `GodotType`. While it is an enum Godot uses,
35///   we have no native way to indicate to Godot that a value should be one of the variants of `VariantType`.
36//
37// Unlike `GodotFfi`, types implementing this trait don't need to fully represent its corresponding Godot
38// type. For instance [`i32`] does not implement `GodotFfi` because it cannot represent all values of
39// Godot's `int` type, however it does implement `GodotType` because we can set the meta-data of values with
40// this type to indicate that they are 32 bits large.
41pub trait GodotType: GodotConvert<Via = Self> + Clone + sealed::Sealed + Sized + 'static
42// 'static is not technically required, but it simplifies a few things (limits e.g. `ObjectArg`).
43{
44    // Value type for this type's FFI representation.
45    #[doc(hidden)]
46    type Ffi: GodotFfiVariant + 'static;
47
48    // Value or reference type when passing this type *to* Godot FFI.
49    #[doc(hidden)]
50    type ToFfi<'f>: GodotFfiVariant
51    where
52        Self: 'f;
53
54    /// Returns the FFI representation of this type, used for argument passing.
55    ///
56    /// Often returns a reference to the value, which can then be used to interact with Godot without cloning/inc-ref-ing the value.
57    /// For scalars and `Copy` types, this usually returns a copy of the value.
58    #[doc(hidden)]
59    fn to_ffi(&self) -> Self::ToFfi<'_>;
60
61    /// Consumes value and converts into FFI representation, used for return types.
62    ///
63    /// Unlike [`to_ffi()`][Self:to_ffi], this method consumes the value and is used for return types rather than argument passing.
64    /// Using `to_ffi()` for return types can be incorrect, since the associated types `Ffi` and `ToFfi<'f>` may differ and the latter
65    /// may not implement return type conversions such as [`GodotFfi::move_return_ptr()`].
66    #[doc(hidden)]
67    fn into_ffi(self) -> Self::Ffi;
68
69    /// Converts from FFI representation to Rust type.
70    #[doc(hidden)]
71    fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError>;
72
73    #[doc(hidden)]
74    fn from_ffi(ffi: Self::Ffi) -> Self {
75        Self::try_from_ffi(ffi).expect("Failed conversion from FFI representation to Rust type")
76    }
77
78    /// Returns the default parameter metadata for method signature registration.
79    ///
80    /// Overridden by scalar types (e.g. `i8` returns [`ParamMetadata::INT_IS_INT8`]) so that `of_builtin::<T>()`
81    /// can embed the correct metadata into the shape without requiring a separate override per type.
82    #[doc(hidden)]
83    fn default_metadata() -> ParamMetadata {
84        ParamMetadata::NONE
85    }
86
87    /// Special-casing for `FromVariant` conversions higher up: true if the variant can be interpreted as `Option<Self>::None`.
88    ///
89    /// Returning false only means that this is not a special case, not that it cannot be `None`. Regular checks are expected to run afterward.
90    ///
91    /// This exists only for var-calls and serves a similar purpose as `GodotNullableType::ffi_is_null()` (although that handles general cases).
92    #[doc(hidden)]
93    fn qualifies_as_special_none(_from_variant: &Variant) -> bool {
94        false
95    }
96
97    /// Convert to `ObjectArg` for efficient object argument passing.
98    ///
99    /// Implemented in `GodotType` because Rust has no specialization, and there's no good way to have trait bounds in `ByObject`, but not in
100    /// other arg-passing strategies `ByValue`/`ByRef`.
101    ///
102    /// # Panics
103    /// If `Self` is not an object type (`Gd<T>`, `Option<Gd<T>>`). Note that `DynGd<T>` isn't directly implemented here, but uses `Gd<T>`'s
104    /// impl on the FFI layer.
105    #[doc(hidden)]
106    fn as_object_arg(&self) -> crate::meta::ObjectArg<'_> {
107        panic!(
108            "as_object_arg() called for non-object type: {}",
109            std::any::type_name::<Self>()
110        )
111    }
112}
113
114// ----------------------------------------------------------------------------------------------------------------------------------------------
115
116/// Types representing nullable Godot objects (e.g., `Gd<T>`, `DynGd<T, D>`).
117///
118/// This trait enables blanket implementations for [`Option<T>`] across conversions and argument passing,
119/// without exposing internal FFI details in public where-clause bounds.
120///
121/// Implemented for `Gd<T>` directly. `DynGd<T, D>` benefits through `Via = Gd<T>`.
122pub(crate) trait GodotNullableType: GodotType {
123    /// Creates a null FFI owned value.
124    #[doc(hidden)]
125    fn ffi_null() -> Self::Ffi;
126
127    /// Creates a null borrowed FFI value.
128    #[doc(hidden)]
129    fn ffi_null_ref<'f>() -> Self::ToFfi<'f>
130    where
131        Self: 'f;
132
133    /// Checks whether an FFI value represents null.
134    #[doc(hidden)]
135    fn ffi_is_null(ffi: &Self::Ffi) -> bool;
136}
137
138// ----------------------------------------------------------------------------------------------------------------------------------------------
139
140/// Marker trait to identify types that can be stored in [`Array<T>`][crate::builtin::Array] and [`Dictionary<K, V>`][crate::builtin::Dictionary].
141///
142/// Implemented for most types that can interact with Godot. A notable exception is `Array<T>` and `Dictionary<K, V>` -- Godot doesn't support
143/// typed collections to be nested. You can still _store_ typed collections, but you need to use [`AnyArray`][crate::builtin::AnyArray] and
144/// [`AnyDictionary`][crate::builtin::AnyDictionary], which can be **either** typed **or** untyped. We also don't support `VarArray` and
145/// `VarDictionary` (special case of the former with `T=Variant`), because godot-rust cannot statically guarantee that the nested collections
146/// are indeed untyped. In a GDScript `Array[Array]`, you can store both typed and untyped arrays, even within the same collection.
147///
148/// See also [`ElementType`][crate::meta::inspect::ElementType] for a runtime representation of this.
149///
150/// # Integer and float types
151/// `u8`, `i8`, `u16`, `i16`, `u32`, `i32` and `f32` are supported by this trait, however they don't have their own array type in Godot.
152/// The engine only knows about `i64` ("int") and `f64` ("float") types. This means that when using any integer or float type, Godot
153/// will treat it as the equivalent of GDScript's `Array[int]` or `Array[float]`, respectively.
154///
155/// As a result, when converting from a Godot typed array to a Rust `Array<T>`, the values stored may not actually fit into a `T`.
156/// For example, you have a GDScript `Array[int]` which stores value 160, and you convert it to a Rust `Array<i8>`. This means that you may
157/// end up with panics on element access (since the `Variant` storing 160 will fail to convert to `i8`). In Debug mode, we add additional
158/// best-effort checks to detect such errors, however they are expensive and not bullet-proof. If you need very rigid type safety, stick to
159/// `i64` and `f64`. The other types however can be extremely convenient and work well, as long as you are aware of the limitations.
160///
161/// `u64` is [entirely unsupported](trait.GodotConvert.html#u64).
162///
163/// Also, keep in mind that Godot uses `Variant` for each element. If performance matters and you have small element types such as `u8`,
164/// consider using packed arrays (e.g. `PackedByteArray`) instead.
165//
166// Note: `Element` does not require `Sealed`. This is intentional: user-defined enums (`#[derive(GodotConvert)]`) implement `Element`
167// via generated code, so the trait must be open. Correctness is ensured by requiring `ToGodot + FromGodot` (both sealed), which
168// guarantees that only types with valid Godot conversions can implement `Element`.
169#[diagnostic::on_unimplemented(
170    message = "Element type not supported in Godot Array or Dictionary (no nesting).",
171    label = "has invalid element type"
172)]
173// TODO(v0.6): consider supertraits like PartialEq or Debug. For enums, align with #[derive(GodotConvert)].
174pub trait Element: ToGodot + FromGodot + 'static {
175    // Note: several indirections in `Element` and the global `element_*` functions go through `GodotConvert::Via`,
176    // to not require Self: `GodotType`. What matters is how array elements map to Godot on the FFI level (`GodotType` trait).
177
178    #[doc(hidden)]
179    fn debug_validate_elements(_array: &builtin::Array<Self>) -> Result<(), ConvertError> {
180        // No-op for most element types.
181        Ok(())
182    }
183}
184
185// ----------------------------------------------------------------------------------------------------------------------------------------------
186// Non-polymorphic helper functions, to avoid constant `<T::Via as GodotType>::` in the code.
187
188#[doc(hidden)]
189pub const fn element_variant_type<T: Element>() -> VariantType {
190    <T::Via as GodotType>::Ffi::VARIANT_TYPE.variant_as_nil()
191}
192
193/// Classifies `T` into one of Godot's builtin types. **Important:** variants are mapped to `NIL`.
194#[doc(hidden)]
195pub(crate) const fn ffi_variant_type<T: GodotConvert + ?Sized>() -> ExtVariantType {
196    <T::Via as GodotType>::Ffi::VARIANT_TYPE
197}
198
199// ----------------------------------------------------------------------------------------------------------------------------------------------
200
201/// Implemented for types that can be used as immutable default parameters in `#[func]` methods.
202///
203/// This trait ensures that default parameter values cannot be mutated by callers, preventing the Python "mutable default argument" problem
204/// where a single default value is shared across multiple calls.
205///
206/// Post-processes the default value in some cases, e.g. makes `Array<T>` read-only via `into_read_only()`.
207///
208/// At the moment, this trait is conservatively implemented for types where immutability can be statically guaranteed.
209/// Depending on usage, the API might be expanded in the future to allow defaults whose immutability is only determined
210/// at runtime (e.g. untyped arrays/dictionaries where all element types are immutable).
211///
212/// # Safety
213/// Allows to use the implementors in a limited `Sync` context. Implementing this trait asserts that `Self` is either:
214/// - `Copy`, i.e. each instance is truly independent.
215/// - Thread-safe in the sense that `clone()` is thread-safe. Individual clones must not offer a way to mutate the value or cause race conditions.
216#[diagnostic::on_unimplemented(
217    message = "#[opt(default = ...)] only supports a set of truly immutable types",
218    label = "this type is not immutable and thus not eligible for a default value"
219)]
220pub unsafe trait GodotImmutable: GodotConvert + Sized {
221    fn into_runtime_immutable(self) -> Self {
222        self
223    }
224}
225
226mod godot_immutable_impls {
227    use super::GodotImmutable;
228    use crate::builtin::*;
229    use crate::meta::Element;
230
231    unsafe impl GodotImmutable for bool {}
232    unsafe impl GodotImmutable for i8 {}
233    unsafe impl GodotImmutable for u8 {}
234    unsafe impl GodotImmutable for i16 {}
235    unsafe impl GodotImmutable for u16 {}
236    unsafe impl GodotImmutable for i32 {}
237    unsafe impl GodotImmutable for u32 {}
238    unsafe impl GodotImmutable for i64 {}
239    unsafe impl GodotImmutable for f32 {}
240    unsafe impl GodotImmutable for f64 {}
241
242    // No NodePath, Callable, Signal, Rid, Variant.
243    unsafe impl GodotImmutable for Aabb {}
244    unsafe impl GodotImmutable for Basis {}
245    unsafe impl GodotImmutable for Color {}
246    unsafe impl GodotImmutable for GString {}
247    unsafe impl GodotImmutable for Plane {}
248    unsafe impl GodotImmutable for Projection {}
249    unsafe impl GodotImmutable for Quaternion {}
250    unsafe impl GodotImmutable for Rect2 {}
251    unsafe impl GodotImmutable for Rect2i {}
252    unsafe impl GodotImmutable for StringName {}
253    unsafe impl GodotImmutable for Transform2D {}
254    unsafe impl GodotImmutable for Transform3D {}
255    unsafe impl GodotImmutable for Vector2 {}
256    unsafe impl GodotImmutable for Vector2i {}
257    unsafe impl GodotImmutable for Vector3 {}
258    unsafe impl GodotImmutable for Vector3i {}
259    unsafe impl GodotImmutable for Vector4 {}
260    unsafe impl GodotImmutable for Vector4i {}
261
262    unsafe impl GodotImmutable for PackedByteArray {}
263    unsafe impl GodotImmutable for PackedColorArray {}
264    unsafe impl GodotImmutable for PackedFloat32Array {}
265    unsafe impl GodotImmutable for PackedFloat64Array {}
266    unsafe impl GodotImmutable for PackedInt32Array {}
267    unsafe impl GodotImmutable for PackedInt64Array {}
268    unsafe impl GodotImmutable for PackedStringArray {}
269    unsafe impl GodotImmutable for PackedVector2Array {}
270    unsafe impl GodotImmutable for PackedVector3Array {}
271    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
272    unsafe impl GodotImmutable for PackedVector4Array {}
273
274    unsafe impl<T> GodotImmutable for Array<T>
275    where
276        T: GodotImmutable + Element,
277    {
278        fn into_runtime_immutable(self) -> Self {
279            self.into_read_only()
280        }
281    }
282}