godot_core/meta/godot_convert/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
/*
* Copyright (c) godot-rust; Bromeon and contributors.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
mod impls;
use crate::builtin::Variant;
use crate::meta::error::ConvertError;
use crate::meta::traits::GodotFfiVariant;
use crate::meta::GodotType;
/// Indicates that a type can be passed to/from Godot, either directly or through an intermediate "via" type.
///
/// The associated type `Via` specifies _how_ this type is passed across the FFI boundary to/from Godot.
/// Generally [`ToGodot`] needs to be implemented to pass a type to Godot, and [`FromGodot`] to receive this type from Godot.
///
/// [`GodotType`] is a stronger bound than [`GodotConvert`], since it expresses that a type is _directly_ representable
/// in Godot (without intermediate "via"). Every `GodotType` also implements `GodotConvert` with `Via = Self`.
///
/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
#[doc(alias = "via", alias = "transparent")]
#[diagnostic::on_unimplemented(
message = "`GodotConvert` is needed for `#[func]` parameters/returns, as well as `#[var]` and `#[export]` properties",
note = "check following errors for more information"
)]
pub trait GodotConvert {
/// The type through which `Self` is represented in Godot.
type Via: GodotType;
}
/// Defines the canonical conversion to Godot for a type.
///
/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
/// that if [`FromGodot`] is implemented, converting to Godot and back again will return a value equal to the
/// starting value.
///
/// Violating these assumptions is safe but will give unexpected results.
///
/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
///
/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
pub trait ToGodot: Sized + GodotConvert {
/// Target type of [`to_godot()`](ToGodot::to_godot), which can differ from [`Via`][GodotConvert::Via] for pass-by-reference types.
///
/// Note that currently, this only differs from `Via` when `Self` is [`RefArg<'r, T>`][crate::meta::RefArg], which is
/// used inside generated code of engine methods. Other uses of `to_godot()`, such as return types in `#[func]`, still use value types.
/// This may change in future versions.
///
/// See also [`AsArg<T>`](crate::meta::AsArg) used as the "front-end" in Godot API parameters.
type ToVia<'v>: GodotType
where
Self: 'v;
/// Converts this type to the Godot type by reference, usually by cloning.
fn to_godot(&self) -> Self::ToVia<'_>;
/// Converts this type to a [Variant].
// Exception safety: must not panic apart from exceptional circumstances (Nov 2024: only u64).
// This has invariant implications, e.g. in Array::resize().
fn to_variant(&self) -> Variant {
self.to_godot().to_ffi().ffi_to_variant()
}
}
/// Defines the canonical conversion from Godot for a type.
///
/// It is assumed that all the methods return equal values given equal inputs. Additionally, it is assumed
/// that if [`ToGodot`] is implemented, converting to Godot and back again will return a value equal to the
/// starting value.
///
/// Violating these assumptions is safe but will give unexpected results.
///
/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
///
/// This trait can be derived using the [`#[derive(GodotConvert)]`](../register/derive.GodotConvert.html) macro.
pub trait FromGodot: Sized + GodotConvert {
/// Converts the Godot representation to this type, returning `Err` on failure.
fn try_from_godot(via: Self::Via) -> Result<Self, ConvertError>;
/// ⚠️ Converts the Godot representation to this type.
///
/// # Panics
/// If the conversion fails.
fn from_godot(via: Self::Via) -> Self {
Self::try_from_godot(via)
.unwrap_or_else(|err| panic!("FromGodot::from_godot() failed: {err}"))
}
/// Performs the conversion from a [`Variant`], returning `Err` on failure.
fn try_from_variant(variant: &Variant) -> Result<Self, ConvertError> {
let ffi = <Self::Via as GodotType>::Ffi::ffi_from_variant(variant)?;
let via = Self::Via::try_from_ffi(ffi)?;
Self::try_from_godot(via)
}
/// ⚠️ Performs the conversion from a [`Variant`].
///
/// # Panics
/// If the conversion fails.
fn from_variant(variant: &Variant) -> Self {
Self::try_from_variant(variant).unwrap_or_else(|err| {
eprintln!("FromGodot::from_variant() failed: {err}");
panic!()
})
}
}
pub(crate) fn into_ffi_variant<T: ToGodot>(value: &T) -> Variant {
let via = value.to_godot();
let ffi = via.to_ffi();
GodotFfiVariant::ffi_to_variant(&ffi)
}
pub(crate) fn try_from_ffi<T: FromGodot>(
ffi: <T::Via as GodotType>::Ffi,
) -> Result<T, ConvertError> {
let via = <T::Via as GodotType>::try_from_ffi(ffi)?;
T::try_from_godot(via)
}
#[macro_export]
macro_rules! impl_godot_as_self {
($T:ty) => {
impl $crate::meta::GodotConvert for $T {
type Via = $T;
}
impl $crate::meta::ToGodot for $T {
type ToVia<'v> = Self::Via;
#[inline]
fn to_godot(&self) -> Self::ToVia<'_> {
self.clone()
}
}
impl $crate::meta::FromGodot for $T {
#[inline]
fn try_from_godot(via: Self::Via) -> Result<Self, $crate::meta::error::ConvertError> {
Ok(via)
}
}
};
}