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](index.html) 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](index.html) for further information about conversions.
56///
57/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
58///
59/// # `Result<T, E>`
60/// It is possible to return `Result<T, E>` from `#[func]`, when `T: ToGodot` and [`E: ErrorToGodot`][crate::meta::error::ErrorToGodot].
61/// However, `Result<T, E>` currently does not implement `ToGodot` itself, as it is not generally infallible.
62///
63/// # Panics
64/// Currently, the methods `to_godot()`, `to_godot_owned()` and `to_variant()` are infallible and never panic, i.e. you can convert every value
65/// to a Godot representation. If new types are supported in the future that may not satisfy this (example: `Result<T, E>`), it's possible
66/// that panics are introduced _only for those new types_.
67#[diagnostic::on_unimplemented(
68    message = "passing type `{Self}` to Godot requires `ToGodot` trait, which is usually provided by the library",
69    note = "ToGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
70    note = "if you really need a custom representation (for non-class types), implement ToGodot manually or use #[derive(GodotConvert)].",
71    note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
72)]
73pub trait ToGodot: Sized + GodotConvert {
74    /// Whether arguments of this type are passed by value or by reference.
75    ///
76    /// Can be either [`ByValue`][crate::meta::ByValue] or [`ByRef`][crate::meta::ByRef]. In most cases, you need `ByValue`.
77    ///
78    /// Select `ByValue` if:
79    /// - `Self` is `Copy` (e.g. `i32`, `f64`, `Vector2`, `Color`, etc).
80    /// - You need a conversion (e.g. `Self = MyString`, `Via = GString`).
81    /// - You like the simple life and can't be bothered with lifetimes.
82    ///
83    /// Select `ByRef` if:
84    /// - Performance of argument passing is very important and you have measured it.
85    /// - You store a cached value which can be borrowed (e.g. `&GString`).
86    ///
87    /// Will auto-implement [`AsArg<T>`][crate::meta::AsArg] for either `T` (by-value) or for `&T` (by-reference).
88    /// This has an influence on contexts such as [`Array::push()`][crate::builtin::Array::push], the [`array![...]`][crate::builtin::array]
89    /// macro or generated signal `emit()` signatures.
90    type Pass: ArgPassing;
91
92    /// Converts this type to Godot representation, optimizing for zero-copy when possible.
93    ///
94    /// # Return type
95    /// - For `Pass = ByValue`, returns owned `Self::Via`.
96    /// - For `Pass = ByRef`, returns borrowed `&Self::Via`.
97    fn to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
98
99    /// Converts this type to owned Godot representation.
100    ///
101    /// Always returns `Self::Via`, cloning if necessary for ByRef types.
102    fn to_godot_owned(&self) -> Self::Via {
103        Self::Pass::ref_to_owned_via(self)
104    }
105
106    /// Converts this type to a [Variant].
107    // Exception safety: introducing a panic would have invariant implications, e.g. in Array::resize().
108    fn to_variant(&self) -> Variant {
109        Self::Pass::ref_to_variant(self)
110    }
111}
112
113/// Defines the canonical conversion from Godot for a type.
114///
115/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
116/// that if [`ToGodot`] is implemented, converting to Godot and back again will return a value equal to the
117/// starting value.
118///
119/// Violating these assumptions is safe but will give unexpected results.
120///
121/// Please read the [`godot::meta` module docs](index.html) for further information about conversions.
122///
123/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
124#[diagnostic::on_unimplemented(
125    message = "receiving type `{Self}` from Godot requires `FromGodot` trait, which is usually provided by the library",
126    note = "FromGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
127    note = "if you really need a custom representation (for non-class types), implement FromGodot manually or use #[derive(GodotConvert)]",
128    note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
129)]
130pub trait FromGodot: Sized + GodotConvert {
131    /// Converts the Godot representation to this type, returning `Err` on failure.
132    fn try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
133
134    /// ⚠️ Converts the Godot representation to this type.
135    ///
136    /// # Panics
137    /// If the conversion fails.
138    fn from_godot(via: Self::Via) -> Self {
139        Self::try_from_godot(via)
140            .unwrap_or_else(|err| panic!("FromGodot::from_godot() failed: {err}"))
141    }
142
143    /// Performs the conversion from a [`Variant`], returning `Err` on failure.
144    fn try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
145        let ffi = <Self::Via as GodotType>::Ffi::ffi_from_variant(variant)?;
146
147        let via = Self::Via::try_from_ffi(ffi)?;
148        Self::try_from_godot(via)
149    }
150
151    /// ⚠️ Performs the conversion from a [`Variant`].
152    ///
153    /// # Panics
154    /// If the conversion fails.
155    fn from_variant(variant: &Variant) -> Self {
156        Self::try_from_variant(variant).unwrap_or_else(|err| {
157            panic!("FromGodot::from_variant() failed -- {err}");
158        })
159    }
160}
161
162// ----------------------------------------------------------------------------------------------------------------------------------------------
163// Engine conversion traits (for APIs and virtual methods, not user-facing #[func])
164
165/// Engine-internal variant of [`ToGodot`], used for engine APIs and virtual methods.
166///
167/// 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
168/// `#[func]` methods (as they don't fit in GDScript/Variant, which can only store `i64`).
169///
170/// 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
171/// and bitfields. User-defined GDScript code generally does not get into contact with `i64` (except for bitfields).
172///
173/// For internal use only; see [`ToGodot`] for user-facing conversions.
174#[doc(hidden)]
175pub trait EngineToGodot: Sized + GodotConvert {
176    /// Whether arguments of this type are passed by value or by reference.
177    type Pass: ArgPassing;
178
179    /// Converts this type to Godot representation, optimizing for zero-copy when possible.
180    fn engine_to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
181
182    /// Converts this type to owned Godot representation.
183    fn engine_to_godot_owned(&self) -> Self::Via {
184        Self::Pass::ref_to_owned_via(self)
185    }
186
187    fn engine_to_variant(&self) -> Variant;
188
189    /// Consuming conversion to `Variant` for `#[func]` varcall return values. Relevant for `Result<T, E>`.
190    ///
191    /// Defaults to infallible [`Self::engine_to_variant()`] for types without `ToGodot` (e.g. `u64`). For `ToGodot` types,
192    /// the blanket impl delegates to [`ToGodot::__godot_try_into_variant()`].
193    //
194    // Could alternatively be avoided by splitting Signature in-call methods into `in_varcall`/`in_ptrcall` (EngineToGodot, for virtual
195    // methods + property accessors) and `in_func_varcall`/`in_func_ptrcall` (ToGodot, for #[func]). That avoids this trait method but
196    // duplicates more code in signature.rs and requires is_func plumbing in the macro. Trying this resulted in ~120 additional LoC.
197    fn engine_try_into_variant(
198        self,
199        _call_ctx: &crate::meta::CallContext,
200    ) -> Result<Variant, crate::meta::error::CallError> {
201        Ok(self.engine_to_variant())
202    }
203
204    /// Consuming conversion to the Godot `Via` type for `#[func]` ptrcall return values.
205    ///
206    /// Defaults to infallible [`Self::engine_to_godot_owned()`]. For `ToGodot` types,
207    /// the blanket impl delegates to [`ToGodot::__godot_try_into_godot_owned()`].
208    fn engine_try_into_godot_owned(
209        self,
210        _call_ctx: &crate::meta::CallContext,
211    ) -> Result<Self::Via, crate::meta::error::CallError> {
212        Ok(self.engine_to_godot_owned())
213    }
214}
215
216// Blanket implementations: all user-facing types work in engine contexts.
217impl<T: ToGodot> EngineToGodot for T {
218    type Pass = T::Pass;
219
220    fn engine_to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass> {
221        <T as ToGodot>::to_godot(self)
222    }
223
224    fn engine_to_godot_owned(&self) -> Self::Via {
225        <T as ToGodot>::to_godot_owned(self)
226    }
227
228    fn engine_to_variant(&self) -> Variant {
229        <T as ToGodot>::to_variant(self)
230    }
231
232    fn engine_try_into_variant(
233        self,
234        _call_ctx: &crate::meta::CallContext,
235    ) -> Result<Variant, crate::meta::error::CallError> {
236        Ok(self.to_variant())
237    }
238
239    fn engine_try_into_godot_owned(
240        self,
241        _call_ctx: &crate::meta::CallContext,
242    ) -> Result<Self::Via, crate::meta::error::CallError> {
243        Ok(self.to_godot_owned())
244    }
245}
246
247/// Engine-internal variant of [`FromGodot`], used for engine APIs and virtual methods.
248///
249/// See [`EngineToGodot`] for rationale.
250///
251/// For internal use only; see [`FromGodot`] for user-facing conversions.
252#[doc(hidden)]
253pub trait EngineFromGodot: Sized + GodotConvert {
254    /// Converts the Godot representation to this type, returning `Err` on failure.
255    fn engine_try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
256
257    fn engine_try_from_variant(variant: &Variant) -> Result<Self, ConvertError>;
258}
259
260impl<T: FromGodot> EngineFromGodot for T {
261    fn engine_try_from_godot(via: Self::Via) -> Result<Self, ConvertError> {
262        <T as FromGodot>::try_from_godot(via)
263    }
264
265    fn engine_try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
266        <T as FromGodot>::try_from_variant(variant)
267    }
268}
269
270// ----------------------------------------------------------------------------------------------------------------------------------------------
271// Impls
272
273#[macro_export]
274macro_rules! impl_godot_as_self {
275    ($T:ty: $Passing:ident) => {
276        impl $crate::meta::GodotConvert for $T {
277            type Via = $T;
278
279            fn godot_shape() -> $crate::meta::shape::GodotShape {
280                $crate::meta::shape::GodotShape::of_builtin::<$T>()
281            }
282        }
283
284        $crate::impl_godot_as_self!(@to_godot $T: $Passing);
285
286        impl $crate::meta::FromGodot for $T {
287            #[inline]
288            fn try_from_godot(via: Self::Via) -> Result<Self, $crate::meta::error::ConvertError> {
289                Ok(via)
290            }
291        }
292    };
293
294    (@to_godot $T:ty: ByValue) => {
295        impl $crate::meta::ToGodot for $T {
296            type Pass = $crate::meta::ByValue;
297
298            #[inline]
299            fn to_godot(&self) -> Self::Via {
300                self.clone()
301            }
302        }
303    };
304
305    (@to_godot $T:ty: ByRef) => {
306        impl $crate::meta::ToGodot for $T {
307            type Pass = $crate::meta::ByRef;
308
309            #[inline]
310            fn to_godot(&self) -> &Self::Via {
311                self
312            }
313        }
314    };
315
316    (@to_godot $T:ty: ByVariant) => {
317        impl $crate::meta::ToGodot for $T {
318            type Pass = $crate::meta::ByVariant;
319
320            #[inline]
321            fn to_godot(&self) -> &Self::Via {
322                self
323            }
324        }
325    };
326}