godot_core/meta/traits.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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
/*
* 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/.
*/
use godot_ffi as sys;
use crate::builtin::Variant;
use crate::global::PropertyUsageFlags;
use crate::meta::error::ConvertError;
use crate::meta::{
sealed, ClassName, FromGodot, GodotConvert, PropertyHintInfo, PropertyInfo, ToGodot,
};
use crate::registry::method::MethodParamOrReturnInfo;
// Re-export sys traits in this module, so all are in one place.
use crate::registry::property::builtin_type_string;
use crate::{builtin, meta};
pub use sys::{GodotFfi, GodotNullableFfi};
/// Conversion of [`GodotFfi`] types to/from [`Variant`].
#[doc(hidden)]
pub trait GodotFfiVariant: Sized + GodotFfi {
fn ffi_to_variant(&self) -> Variant;
fn ffi_from_variant(variant: &Variant) -> Result<Self, ConvertError>;
}
/// Type that is directly representable in the engine.
///
/// This trait cannot be implemented for custom user types; for those, [`GodotConvert`] exists instead.
/// A type implements `GodotType` when Godot has a direct, native representation for it. For instance:
/// - [`i64`] implements `GodotType`, since it can be directly represented by Godot's `int` type.
/// - But [`VariantType`][crate::builtin::VariantType] does not implement `GodotType`. While it is an enum Godot uses,
/// we have no native way to indicate to Godot that a value should be one of the variants of `VariantType`.
//
// Unlike `GodotFfi`, types implementing this trait don't need to fully represent its corresponding Godot
// type. For instance [`i32`] does not implement `GodotFfi` because it cannot represent all values of
// Godot's `int` type, however it does implement `GodotType` because we can set the metadata of values with
// this type to indicate that they are 32 bits large.
pub trait GodotType: GodotConvert<Via = Self> + sealed::Sealed + Sized + 'static
// 'static is not technically required, but it simplifies a few things (limits e.g. ObjectArg).
{
// Value type for this type's FFI representation.
#[doc(hidden)]
type Ffi: GodotFfiVariant + 'static;
// Value or reference type when passing this type *to* Godot FFI.
#[doc(hidden)]
type ToFfi<'f>: GodotFfiVariant
where
Self: 'f;
/// Returns the FFI representation of this type, used for argument passing.
///
/// Often returns a reference to the value, which can then be used to interact with Godot without cloning/inc-ref-ing the value.
/// For scalars and `Copy` types, this usually returns a copy of the value.
#[doc(hidden)]
fn to_ffi(&self) -> Self::ToFfi<'_>;
/// Consumes value and converts into FFI representation, used for return types.
///
/// Unlike [`to_ffi()`][Self:to_ffi], this method consumes the value and is used for return types rather than argument passing.
/// Using `to_ffi()` for return types can be incorrect, since the associated types `Ffi` and `ToFfi<'f>` may differ and the latter
/// may not implement return type conversions such as [`GodotFfi::move_return_ptr()`].
#[doc(hidden)]
fn into_ffi(self) -> Self::Ffi;
/// Converts from FFI representation to Rust type.
#[doc(hidden)]
fn try_from_ffi(ffi: Self::Ffi) -> Result<Self, ConvertError>;
#[doc(hidden)]
fn from_ffi(ffi: Self::Ffi) -> Self {
Self::try_from_ffi(ffi).expect("Failed conversion from FFI representation to Rust type")
}
#[doc(hidden)]
fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
Self::Ffi::default_param_metadata()
}
#[doc(hidden)]
fn class_name() -> ClassName {
// If we use `ClassName::of::<()>()` then this type shows up as `(no base)` in documentation.
ClassName::none()
}
#[doc(hidden)]
fn property_info(property_name: &str) -> PropertyInfo {
PropertyInfo {
variant_type: Self::Ffi::variant_type(),
class_name: Self::class_name(),
property_name: builtin::StringName::from(property_name),
hint_info: Self::property_hint_info(),
usage: PropertyUsageFlags::DEFAULT,
}
}
#[doc(hidden)]
fn property_hint_info() -> PropertyHintInfo {
// The default implementation is mostly good for builtin types.
//PropertyHintInfo::with_type_name::<Self>()
PropertyHintInfo::none()
}
#[doc(hidden)]
fn argument_info(property_name: &str) -> MethodParamOrReturnInfo {
MethodParamOrReturnInfo::new(Self::property_info(property_name), Self::param_metadata())
}
#[doc(hidden)]
fn return_info() -> Option<MethodParamOrReturnInfo> {
Some(MethodParamOrReturnInfo::new(
Self::property_info(""),
Self::param_metadata(),
))
}
#[doc(hidden)]
fn godot_type_name() -> String;
/// Special-casing for `FromVariant` conversions higher up: true if the variant can be interpreted as `Option<Self>::None`.
///
/// Returning false only means that this is not a special case, not that it cannot be `None`. Regular checks are expected to run afterward.
///
/// This exists only for varcalls and serves a similar purpose as `GodotNullableFfi::is_null()` (although that handles general cases).
#[doc(hidden)]
fn qualifies_as_special_none(_from_variant: &Variant) -> bool {
false
}
}
// ----------------------------------------------------------------------------------------------------------------------------------------------
/// Marker trait to identify types that can be stored in [`Array<T>`][crate::builtin::Array].
///
/// The types, for which this trait is implemented, overlap mostly with [`GodotType`].
///
/// Notable differences are:
/// - Only `VariantArray`, not `Array<T>` is allowed (typed arrays cannot be nested).
/// - `Option` is only supported for `Option<Gd<T>>`, but not e.g. `Option<i32>`.
///
/// # Integer and float types
/// `u8`, `i8`, `u16`, `i16`, `u32`, `i32` and `f32` are supported by this trait, however they don't have their own array type in Godot.
/// The engine only knows about `i64` ("int") and `f64` ("float") types. This means that when using any integer or float type, Godot
/// will treat it as the equivalent of GDScript's `Array[int]` or `Array[float]`, respectively.
///
/// As a result, when converting from a Godot typed array to a Rust `Array<T>`, the values stored may not actually fit into a `T`.
/// For example, you have a GDScript `Array[int]` which stores value 160, and you convert it to a Rust `Array<i8>`. This means that you may
/// end up with panics on element access (since the `Variant` storing 160 will fail to convert to `i8`). In Debug mode, we add additional
/// best-effort checks to detect such errors, however they are expensive and not bullet-proof. If you need very rigid type safety, stick to
/// `i64` and `f64`. The other types however can be extremely convenient and work well, as long as you are aware of the limitations.
///
/// `u64` is entirely unsupported since it cannot be safely stored inside a `Variant`.
///
/// Also, keep in mind that Godot uses `Variant` for each element. If performance matters and you have small element types such as `u8`,
/// consider using packed arrays (e.g. `PackedByteArray`) instead.
#[diagnostic::on_unimplemented(
message = "`Array<T>` can only store element types supported in Godot arrays (no nesting).",
label = "has invalid element type"
)]
pub trait ArrayElement: GodotType + ToGodot + FromGodot + sealed::Sealed + meta::ParamType {
/// Returns the representation of this type as a type string.
///
/// Used for elements in arrays (the latter despite `ArrayElement` not having a direct relation).
///
/// See [`PropertyHint::TYPE_STRING`] and
/// [upstream docs](https://docs.godotengine.org/en/stable/classes/class_%40globalscope.html#enum-globalscope-propertyhint).
#[doc(hidden)]
fn element_type_string() -> String {
// Most array elements and all packed array elements are builtin types, so this is a good default.
builtin_type_string::<Self>()
}
#[doc(hidden)]
fn debug_validate_elements(_array: &builtin::Array<Self>) -> Result<(), ConvertError> {
// No-op for most element types.
Ok(())
}
}
/// Marker trait to identify types that can be stored in `Packed*Array` types.
#[diagnostic::on_unimplemented(
message = "`Packed*Array` can only store element types supported in Godot packed arrays.",
label = "has invalid element type"
)]
pub trait PackedArrayElement: GodotType + sealed::Sealed {
/// See [`ArrayElement::element_type_string()`].
#[doc(hidden)]
fn element_type_string() -> String {
builtin_type_string::<Self>()
}
}
// Implement all packed array element types.
impl PackedArrayElement for u8 {}
impl PackedArrayElement for i32 {}
impl PackedArrayElement for i64 {}
impl PackedArrayElement for f32 {}
impl PackedArrayElement for f64 {}
impl PackedArrayElement for builtin::Vector2 {}
impl PackedArrayElement for builtin::Vector3 {}
#[cfg(since_api = "4.3")]
impl PackedArrayElement for builtin::Vector4 {}
impl PackedArrayElement for builtin::Color {}
impl PackedArrayElement for builtin::GString {}