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::traits::GodotFfiVariant;
13use crate::meta::{ArgPassing, GodotType, ToArg};
14
15/// Indicates that a type can be passed to/from Godot, either directly or through an intermediate "via" type.
16///
17/// The associated type `Via` specifies _how_ this type is passed across the FFI boundary to/from Godot.
18/// Generally [`ToGodot`] needs to be implemented to pass a type to Godot, and [`FromGodot`] to receive this type from Godot.
19///
20/// [`GodotType`] is a stronger bound than [`GodotConvert`], since it expresses that a type is _directly_ representable
21/// in Godot (without intermediate "via"). Every `GodotType` also implements `GodotConvert` with `Via = Self`.
22///
23/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
24#[doc(alias = "via", alias = "transparent")]
25#[diagnostic::on_unimplemented(
26 message = "`GodotConvert` is needed for `#[func]` parameters/returns, as well as `#[var]` and `#[export]` properties",
27 note = "check following errors for more information"
28)]
29pub trait GodotConvert {
30 /// The type through which `Self` is represented in Godot.
31 type Via: GodotType;
32}
33
34/// Defines the canonical conversion to Godot for a type.
35///
36/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
37/// that if [`FromGodot`] is implemented, converting to Godot and back again will return a value equal to the
38/// starting value.
39///
40/// Violating these assumptions is safe but will give unexpected results.
41///
42/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
43///
44/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
45#[diagnostic::on_unimplemented(
46 message = "passing type `{Self}` to Godot requires `ToGodot` trait, which is usually provided by the library",
47 note = "ToGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
48 note = "if you really need a custom representation (for non-class types), implement ToGodot manually or use #[derive(GodotConvert)].",
49 note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
50)]
51pub trait ToGodot: Sized + GodotConvert {
52 /// Whether arguments of this type are passed by value or by reference.
53 ///
54 /// Can be either [`ByValue`][crate::meta::ByValue] or [`ByRef`][crate::meta::ByRef]. In most cases, you need `ByValue`.
55 ///
56 /// Select `ByValue` if:
57 /// - `Self` is `Copy` (e.g. `i32`, `f64`, `Vector2`, `Color`, etc).
58 /// - You need a conversion (e.g. `Self = MyString`, `Via = GString`).
59 /// - You like the simple life and can't be bothered with lifetimes.
60 ///
61 /// Select `ByRef` if:
62 /// - Performance of argument passing is very important and you have measured it.
63 /// - You store a cached value which can be borrowed (e.g. `&GString`).
64 ///
65 /// Will auto-implement [`AsArg<T>`][crate::meta::AsArg] for either `T` (by-value) or for `&T` (by-reference).
66 /// This has an influence on contexts such as [`Array::push()`][crate::builtin::Array::push], the [`array![...]`][crate::builtin::array]
67 /// macro or generated signal `emit()` signatures.
68 type Pass: ArgPassing;
69
70 /// Converts this type to Godot representation, optimizing for zero-copy when possible.
71 ///
72 /// # Return type
73 /// - For `Pass = ByValue`, returns owned `Self::Via`.
74 /// - For `Pass = ByRef`, returns borrowed `&Self::Via`.
75 fn to_godot(&self) -> ToArg<'_, Self::Via, Self::Pass>;
76
77 /// Converts this type to owned Godot representation.
78 ///
79 /// Always returns `Self::Via`, cloning if necessary for ByRef types.
80 // Future: could potentially split into separate ToGodotOwned trait, which has a blanket impl for T: Clone, while requiring
81 // manual implementation for non-Clone types. This would remove the Via: Clone bound, which can be restrictive.
82 fn to_godot_owned(&self) -> Self::Via
83 where
84 Self::Via: Clone,
85 {
86 Self::Pass::ref_to_owned_via(self)
87 }
88
89 /// Converts this type to a [Variant].
90 // Exception safety: must not panic apart from exceptional circumstances (Nov 2024: only u64).
91 // This has invariant implications, e.g. in Array::resize().
92 fn to_variant(&self) -> Variant {
93 Self::Pass::ref_to_variant(self)
94 }
95}
96
97/// Defines the canonical conversion from Godot for a type.
98///
99/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
100/// that if [`ToGodot`] is implemented, converting to Godot and back again will return a value equal to the
101/// starting value.
102///
103/// Violating these assumptions is safe but will give unexpected results.
104///
105/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
106///
107/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
108#[diagnostic::on_unimplemented(
109 message = "receiving type `{Self}` from Godot requires `FromGodot` trait, which is usually provided by the library",
110 note = "FromGodot is implemented for built-in types (i32, Vector2, GString, …). For objects, use Gd<T> instead of T.",
111 note = "if you really need a custom representation (for non-class types), implement FromGodot manually or use #[derive(GodotConvert)]",
112 note = "see also: https://godot-rust.github.io/docs/gdext/master/godot/meta"
113)]
114pub trait FromGodot: Sized + GodotConvert {
115 /// Converts the Godot representation to this type, returning `Err` on failure.
116 fn try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
117
118 /// ⚠️ Converts the Godot representation to this type.
119 ///
120 /// # Panics
121 /// If the conversion fails.
122 fn from_godot(via: Self::Via) -> Self {
123 Self::try_from_godot(via)
124 .unwrap_or_else(|err| panic!("FromGodot::from_godot() failed: {err}"))
125 }
126
127 /// Performs the conversion from a [`Variant`], returning `Err` on failure.
128 fn try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
129 let ffi = <Self::Via as GodotType>::Ffi::ffi_from_variant(variant)?;
130
131 let via = Self::Via::try_from_ffi(ffi)?;
132 Self::try_from_godot(via)
133 }
134
135 /// ⚠️ Performs the conversion from a [`Variant`].
136 ///
137 /// # Panics
138 /// If the conversion fails.
139 fn from_variant(variant: &Variant) -> Self {
140 Self::try_from_variant(variant).unwrap_or_else(|err| {
141 panic!("FromGodot::from_variant() failed -- {err}");
142 })
143 }
144}
145
146#[macro_export]
147macro_rules! impl_godot_as_self {
148 ($T:ty: $Passing:ident) => {
149 impl $crate::meta::GodotConvert for $T {
150 type Via = $T;
151 }
152
153 $crate::impl_godot_as_self!(@to_godot $T: $Passing);
154
155 impl $crate::meta::FromGodot for $T {
156 #[inline]
157 fn try_from_godot(via: Self::Via) -> Result<Self, $crate::meta::error::ConvertError> {
158 Ok(via)
159 }
160 }
161 };
162
163 (@to_godot $T:ty: ByValue) => {
164 impl $crate::meta::ToGodot for $T {
165 type Pass = $crate::meta::ByValue;
166
167 #[inline]
168 fn to_godot(&self) -> Self::Via {
169 self.clone()
170 }
171 }
172 };
173
174 (@to_godot $T:ty: ByRef) => {
175 impl $crate::meta::ToGodot for $T {
176 type Pass = $crate::meta::ByRef;
177
178 #[inline]
179 fn to_godot(&self) -> &Self::Via {
180 self
181 }
182 }
183 };
184}