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}