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}