Skip to main content

godot_core/meta/godot_convert/
mod.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
8mod impls;
9
10use crate::builtin::Variant;
11use crate::meta::error::ConvertError;
12use crate::meta::shape::GodotShape;
13use crate::meta::traits::GodotFfiVariant;
14use crate::meta::{ArgPassing, GodotType, ToArg};
15
16/// Indicates that a type can be passed to/from Godot, either directly or through an intermediate "via" type.
17///
18/// The associated type `Via` specifies _how_ this type is passed across the FFI boundary to/from Godot.
19/// Generally [`ToGodot`] needs to be implemented to pass a type to Godot, and [`FromGodot`] to receive this type from Godot.
20///
21/// [`GodotType`] is a stronger bound than [`GodotConvert`], since it expresses that a type is _directly_ representable
22/// in Godot (without intermediate "via"). Every `GodotType` also implements `GodotConvert` with `Via = Self`.
23///
24/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
25///
26/// # u64
27/// The type `u64` is **not** supported by `ToGodot` and `FromGodot` traits. You can thus not pass it in `#[func]` parameters/return types.
28///
29/// The reason is that Godot's `Variant` type, and therefore also GDScript, only support _signed_ 64-bit integers (`i64`).
30/// Implicitly wrapping `u64` to `i64` would be surprising behavior, as the value could suddenly change for large numbers.
31/// As such, godot-rust leaves this decision to users: it's possible to define a newtype around `u64` with custom `ToGodot`/`FromGodot` impls.
32#[doc(alias = "via", alias = "transparent")]
33#[diagnostic::on_unimplemented(
34    message = "`GodotConvert` is needed for `#[func]` parameters/returns, as well as `#[var]` and `#[export]` properties",
35    note = "check following errors for more information"
36)]
37pub trait GodotConvert {
38    /// The type through which `Self` is represented in Godot.
39    type Via: GodotType;
40
41    /// Which "shape" this type has for property registration (e.g. builtin, enum, ...).
42    ///
43    /// godot-rust derives property hints, class names, usage flags, and element metadata from this.
44    fn godot_shape() -> GodotShape;
45}
46
47/// Defines the canonical conversion to Godot for a type.
48///
49/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
50/// that if [`FromGodot`] is implemented, converting to Godot and back again will return a value equal to the
51/// starting value.
52///
53/// Violating these assumptions is safe but will give unexpected results.
54///
55/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
56///
57/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
58#[diagnostic::on_unimplemented(
59    message = "passing type `{Self}` to Godot requires `ToGodot` trait, which is usually provided by the library",
60    note = "ToGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
61    note = "if you really need a custom representation (for non-class types), implement ToGodot manually or use #[derive(GodotConvert)].",
62    note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
63)]
64pub trait ToGodot: Sized + GodotConvert {
65    /// Whether arguments of this type are passed by value or by reference.
66    ///
67    /// Can be either [`ByValue`][crate::meta::ByValue] or [`ByRef`][crate::meta::ByRef]. In most cases, you need `ByValue`.
68    ///
69    /// Select `ByValue` if:
70    /// - `Self` is `Copy` (e.g. `i32`, `f64`, `Vector2`, `Color`, etc).
71    /// - You need a conversion (e.g. `Self = MyString`, `Via = GString`).
72    /// - You like the simple life and can't be bothered with lifetimes.
73    ///
74    /// Select `ByRef` if:
75    /// - Performance of argument passing is very important and you have measured it.
76    /// - You store a cached value which can be borrowed (e.g. `&GString`).
77    ///
78    /// Will auto-implement [`AsArg<T>`][crate::meta::AsArg] for either `T` (by-value) or for `&T` (by-reference).
79    /// This has an influence on contexts such as [`Array::push()`][crate::builtin::Array::push], the [`array![...]`][crate::builtin::array]
80    /// macro or generated signal `emit()` signatures.
81    type Pass: ArgPassing;
82
83    /// Converts this type to Godot representation, optimizing for zero-copy when possible.
84    ///
85    /// # Return type
86    /// - For `Pass = ByValue`, returns owned `Self::Via`.
87    /// - For `Pass = ByRef`, returns borrowed `&Self::Via`.
88    fn to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
89
90    /// Converts this type to owned Godot representation.
91    ///
92    /// Always returns `Self::Via`, cloning if necessary for ByRef types.
93    // Future: could potentially split into separate ToGodotOwned trait, which has a blanket impl for T: Clone, while requiring
94    // manual implementation for non-Clone types. This would remove the Via: Clone bound, which can be restrictive.
95    fn to_godot_owned(&self) -> Self::Via
96    where
97        Self::Via: Clone,
98    {
99        Self::Pass::ref_to_owned_via(self)
100    }
101
102    /// Converts this type to a [Variant].
103    // Exception safety: must not panic apart from exceptional circumstances (Nov 2024: only u64).
104    // This has invariant implications, e.g. in Array::resize().
105    fn to_variant(&self) -> Variant {
106        Self::Pass::ref_to_variant(self)
107    }
108}
109
110/// Defines the canonical conversion from Godot for a type.
111///
112/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
113/// that if [`ToGodot`] is implemented, converting to Godot and back again will return a value equal to the
114/// starting value.
115///
116/// Violating these assumptions is safe but will give unexpected results.
117///
118/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
119///
120/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
121#[diagnostic::on_unimplemented(
122    message = "receiving type `{Self}` from Godot requires `FromGodot` trait, which is usually provided by the library",
123    note = "FromGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
124    note = "if you really need a custom representation (for non-class types), implement FromGodot manually or use #[derive(GodotConvert)]",
125    note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
126)]
127pub trait FromGodot: Sized + GodotConvert {
128    /// Converts the Godot representation to this type, returning `Err` on failure.
129    fn try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
130
131    /// ⚠️ Converts the Godot representation to this type.
132    ///
133    /// # Panics
134    /// If the conversion fails.
135    fn from_godot(via: Self::Via) -> Self {
136        Self::try_from_godot(via)
137            .unwrap_or_else(|err| panic!("FromGodot::from_godot() failed: {err}"))
138    }
139
140    /// Performs the conversion from a [`Variant`], returning `Err` on failure.
141    fn try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
142        let ffi = <Self::Via as GodotType>::Ffi::ffi_from_variant(variant)?;
143
144        let via = Self::Via::try_from_ffi(ffi)?;
145        Self::try_from_godot(via)
146    }
147
148    /// ⚠️ Performs the conversion from a [`Variant`].
149    ///
150    /// # Panics
151    /// If the conversion fails.
152    fn from_variant(variant: &Variant) -> Self {
153        Self::try_from_variant(variant).unwrap_or_else(|err| {
154            panic!("FromGodot::from_variant() failed -- {err}");
155        })
156    }
157}
158
159// ----------------------------------------------------------------------------------------------------------------------------------------------
160// Engine conversion traits (for APIs and virtual methods, not user-facing #[func])
161
162/// Engine-internal variant of [`ToGodot`], used for engine APIs and virtual methods.
163///
164/// This trait exists to support types like `u64` that work in engine contexts (backed by C++ `uint64_t`), but cannot be used in user-facing
165/// `#[func]` methods (as they don't fit in GDScript/Variant, which can only store `i64`).
166///
167/// On the FFI level, `u64` are passed as `i64` (same bit pattern). The C++ side reinterprets the bits again as `uint64_t` in engine APIs
168/// and bitfields. User-defined GDScript code generally does not get into contact with `i64` (except for bitfields).
169///
170/// For internal use only; see [`ToGodot`] for user-facing conversions.
171#[doc(hidden)]
172pub trait EngineToGodot: Sized + GodotConvert {
173    /// Whether arguments of this type are passed by value or by reference.
174    type Pass: ArgPassing;
175
176    /// Converts this type to Godot representation, optimizing for zero-copy when possible.
177    fn engine_to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
178
179    /// Converts this type to owned Godot representation.
180    fn engine_to_godot_owned(&self) -> Self::Via
181    where
182        Self::Via: Clone,
183    {
184        Self::Pass::ref_to_owned_via(self)
185    }
186
187    fn engine_to_variant(&self) -> Variant;
188}
189
190// Blanket implementations: all user-facing types work in engine contexts.
191impl<T: ToGodot> EngineToGodot for T {
192    type Pass = T::Pass;
193
194    fn engine_to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass> {
195        <T as ToGodot>::to_godot(self)
196    }
197
198    fn engine_to_godot_owned(&self) -> Self::Via
199    where
200        Self::Via: Clone,
201    {
202        <T as ToGodot>::to_godot_owned(self)
203    }
204
205    fn engine_to_variant(&self) -> Variant {
206        <T as ToGodot>::to_variant(self)
207    }
208}
209
210/// Engine-internal variant of [`FromGodot`], used for engine APIs and virtual methods.
211///
212/// See [`EngineToGodot`] for rationale.
213///
214/// For internal use only; see [`FromGodot`] for user-facing conversions.
215#[doc(hidden)]
216pub trait EngineFromGodot: Sized + GodotConvert {
217    /// Converts the Godot representation to this type, returning `Err` on failure.
218    fn engine_try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
219
220    fn engine_try_from_variant(variant: &Variant) -> Result<Self, ConvertError>;
221}
222
223impl<T: FromGodot> EngineFromGodot for T {
224    fn engine_try_from_godot(via: Self::Via) -> Result<Self, ConvertError> {
225        <T as FromGodot>::try_from_godot(via)
226    }
227
228    fn engine_try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
229        <T as FromGodot>::try_from_variant(variant)
230    }
231}
232
233// ----------------------------------------------------------------------------------------------------------------------------------------------
234// Impls
235
236#[macro_export]
237macro_rules! impl_godot_as_self {
238    ($T:ty: $Passing:ident) => {
239        impl $crate::meta::GodotConvert for $T {
240            type Via = $T;
241
242            fn godot_shape() -> $crate::meta::shape::GodotShape {
243                $crate::meta::shape::GodotShape::of_builtin::<$T>()
244            }
245        }
246
247        $crate::impl_godot_as_self!(@to_godot $T: $Passing);
248
249        impl $crate::meta::FromGodot for $T {
250            #[inline]
251            fn try_from_godot(via: Self::Via) -> Result<Self, $crate::meta::error::ConvertError> {
252                Ok(via)
253            }
254        }
255    };
256
257    (@to_godot $T:ty: ByValue) => {
258        impl $crate::meta::ToGodot for $T {
259            type Pass = $crate::meta::ByValue;
260
261            #[inline]
262            fn to_godot(&self) -> Self::Via {
263                self.clone()
264            }
265        }
266    };
267
268    (@to_godot $T:ty: ByRef) => {
269        impl $crate::meta::ToGodot for $T {
270            type Pass = $crate::meta::ByRef;
271
272            #[inline]
273            fn to_godot(&self) -> &Self::Via {
274                self
275            }
276        }
277    };
278
279    (@to_godot $T:ty: ByVariant) => {
280        impl $crate::meta::ToGodot for $T {
281            type Pass = $crate::meta::ByVariant;
282
283            #[inline]
284            fn to_godot(&self) -> &Self::Via {
285                self
286            }
287        }
288    };
289
290}