godot_core/registry/property/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
8//! Registration support for property types.
9
10use godot_ffi::GodotNullableFfi;
11
12use crate::meta::{ClassId, FromGodot, GodotConvert, GodotType, ToGodot};
13
14mod phantom_var;
15
16pub use phantom_var::PhantomVar;
17
18// ----------------------------------------------------------------------------------------------------------------------------------------------
19// Var trait
20
21// Note: HTML link for #[var] works if this symbol is inside prelude, but not in register::property.
22/// Trait for types used in [`#[var]`](../register/derive.GodotClass.html#properties-and-exports) fields.
23///
24/// Defines how a value is passed to/from Godot's property system, through [`var_get()`][Self::var_get] and [`var_set()`][Self::var_set]
25/// associated functions. Further customizes how generated Rust getters and setters operate, in fields annotated with `#[var(pub)]`, through
26/// [`var_pub_get()`][Self::var_pub_get] and [`var_pub_set()`][Self::var_pub_set].
27///
28/// The `Var` trait does not require [`FromGodot`] or [`ToGodot`]: a value can be used as a property even if it can't be used in `#[func]`
29/// parameters or return types.
30///
31/// See also [`Export`], a subtrait for properties exported to the editor UI using `#[export]`.
32///
33/// # Implementing the trait
34/// Most godot-rust types implement `Var` out of the box, so you won't need to do anything. If a type doesn't support it, that's usually a sign
35/// that it shouldn't be used in property contexts.
36///
37/// For enums, you can use the [`#[derive(Var)]`](../derive.Var.html) macro, in combination with `GodotConvert` as `#[derive(GodotConvert, Var)]`.
38///
39/// If you need to manually implement `Var` and your field type already supports `ToGodot` and `FromGodot`, just implement the [`SimpleVar`]
40/// trait instead of `Var`. It will automatically provide a reasonable standard implementation of `Var`.
41#[doc(alias = "property")]
42//
43// on_unimplemented: we also mention #[export] here, because we can't control the order of error messages.
44// Missing Export often also means missing Var trait, and so the Var error message appears first.
45#[diagnostic::on_unimplemented(
46 message = "`#[var]` properties require `Var` trait; #[export] ones require `Export` trait",
47 label = "type cannot be used as a property",
48 note = "see also: https://godot-rust.github.io/book/register/properties.html"
49)]
50pub trait Var: GodotConvert {
51 /// Type used in generated Rust getters/setters for `#[var(pub)]`.
52 //
53 // Note: we deliberately don't require `PubType: ToGodot + FromGodot`. Many manual `Var` impls (`Option<T>`, `Array<T>`, `Dictionary<K,V>`,
54 // `OnEditor<T>`, `OnReady<T>`, `DynGd<T,D>`) have `PubType` types that don't implement those traits. As a consequence, internal (non-pub)
55 // property getters/setters go through `GodotConvert::Via` (which has `GodotType` -> `EngineToGodot` bounds), and the stricter
56 // `ToGodot`/`FromGodot` bounds check (`ensure_func_bounds`) is skipped for them. Only `#[var(pub)]` getters use `PubType` directly.
57 type PubType;
58
59 /// Get property value via FFI-level `Via` type. Called for internal (non-pub) getters registered with Godot.
60 fn var_get(field: &Self) -> Self::Via;
61
62 /// Set property value via FFI-level `Via` type. Called for internal (non-pub) setters registered with Godot.
63 fn var_set(field: &mut Self, value: Self::Via);
64
65 /// Get property value as `PubType`. Called for `#[var(pub)]` getters exposed in Rust API.
66 fn var_pub_get(field: &Self) -> Self::PubType;
67
68 /// Set property value as `PubType`. Called for `#[var(pub)]` setters exposed in Rust API.
69 fn var_pub_set(field: &mut Self, value: Self::PubType);
70}
71
72/// Simplified way to implement the `Var` trait, for godot-convertible types.
73///
74/// Implementing this trait will auto-implement [`Var`] in a standard way for types supporting [`ToGodot`] and [`FromGodot`].
75///
76/// Types implementing this trait will use `clone()` for the public getter and direct assignment for the public setter, with `PubType = Self`.
77/// This is the standard behavior for most types.
78pub trait SimpleVar: ToGodot + FromGodot + Clone {}
79
80/// Blanket impl for types with standard Godot conversion; see [`SimpleVar`] for details.
81impl<T> Var for T
82where
83 T: SimpleVar,
84 T::Via: Clone,
85{
86 type PubType = Self;
87
88 fn var_get(field: &Self) -> Self::Via {
89 <T as ToGodot>::to_godot_owned(field)
90 }
91
92 fn var_set(field: &mut Self, value: Self::Via) {
93 *field = <T as FromGodot>::from_godot(value);
94 }
95
96 fn var_pub_get(field: &Self) -> Self::PubType {
97 field.clone()
98 }
99
100 fn var_pub_set(field: &mut Self, value: Self::PubType) {
101 *field = value;
102 }
103}
104
105// ----------------------------------------------------------------------------------------------------------------------------------------------
106// Export trait
107
108// Note: HTML link for #[export] works if this symbol is inside prelude, but not in register::property.
109/// Trait implemented for types that can be used as [`#[export]`](../register/derive.GodotClass.html#properties-and-exports) fields.
110///
111/// To export objects, see the [_Exporting_ section of `Gd<T>`](../obj/struct.Gd.html#exporting).
112///
113/// For enums, this trait can be derived using the [`#[derive(Export)]`](../derive.Export.html) macro.
114#[doc(alias = "property")]
115//
116// on_unimplemented: mentioning both Var + Export; see above.
117#[diagnostic::on_unimplemented(
118 message = "`#[var]` properties require `Var` trait; #[export] ones require `Export` trait",
119 label = "type cannot be used as a property",
120 note = "see also: https://godot-rust.github.io/book/register/properties.html",
121 note = "`Gd` and `DynGd` cannot be exported directly; wrap them in `Option<...>` or `OnEditor<...>`."
122)]
123pub trait Export: Var {
124 /// If this is a class inheriting `Node`, returns the `ClassId`; otherwise `None`.
125 ///
126 /// Only overridden for `Gd<T>`, to detect erroneous exports of `Node` inside a `Resource` class.
127 #[allow(clippy::wrong_self_convention)]
128 #[doc(hidden)]
129 fn as_node_class() -> Option<ClassId> {
130 None
131 }
132}
133
134/// Marker trait to identify `GodotType`s that can be directly used with an `#[export]`.
135///
136/// Implemented pretty much for all [`GodotType`]s that are not [`GodotClass`][crate::obj::GodotClass]es.
137/// By itself, this trait has no implications for the [`Var`] or [`Export`] traits.
138///
139/// Types which don't implement the `BuiltinExport` trait can't be used directly as an `#[export]`
140/// and must be handled using associated algebraic types, such as:
141/// * [`Option<T>`], which represents optional value that can be null when used.
142/// * [`OnEditor<T>`][crate::obj::OnEditor], which represents value that must not be null when used.
143// Some Godot Types which are inherently non-nullable (e.g., `Gd<T>`),
144// might have their value set to null by the editor. Additionally, Godot must generate
145// initial, default value for such properties, causing memory leaks.
146// Such `GodotType`s don't implement `BuiltinExport`.
147//
148// Note: This marker trait is required to create a blanket implementation for `OnEditor<T>`, where `T` is anything other than `GodotClass`.
149// An alternative approach would involve introducing an extra associated type to `GodotType` trait. However, this would not be ideal --
150// `GodotType` is used in contexts unrelated to `#[export]`, and unnecessary complexity should be avoided. We can't use specialization.
151pub trait BuiltinExport {}
152
153// ----------------------------------------------------------------------------------------------------------------------------------------------
154// Doctests to test compile errors
155
156/// This function only exists as a place to add doc-tests for the `Var` trait and `#[var]` attribute.
157///
158/// The `#[var(no_get, no_set)]` combination is not allowed; if you don't want a property, omit `#[var]` entirely:
159///
160/// ```compile_fail
161/// use godot::prelude::*;
162///
163/// #[derive(GodotClass)]
164/// #[class(init)]
165/// struct Foo {
166/// #[var(no_get, no_set)]
167/// field: i32,
168/// }
169/// ```
170///
171/// Custom getter must return the correct type (matching the field's `PubType`):
172///
173/// ```compile_fail
174/// use godot::prelude::*;
175///
176/// #[derive(GodotClass)]
177/// #[class(init)]
178/// struct Foo {
179/// #[var(get = my_getter)]
180/// field: GString,
181/// }
182///
183/// #[godot_api]
184/// impl Foo {
185/// fn my_getter(&self) -> i32 { 42 }
186/// }
187/// ```
188///
189/// Custom setter must accept the correct type (matching the field's `PubType`):
190///
191/// ```compile_fail
192/// use godot::prelude::*;
193///
194/// #[derive(GodotClass)]
195/// #[class(init)]
196/// struct Foo {
197/// #[var(set = my_setter)]
198/// field: GString,
199/// }
200///
201/// #[godot_api]
202/// impl Foo {
203/// fn my_setter(&mut self, value: i32) {}
204/// }
205/// ```
206fn __var_doctests() {}
207
208/// This function only exists as a place to add doc-tests for the `Export` trait.
209///
210/// Test with export of exportable type should succeed:
211/// ```no_run
212/// use godot::prelude::*;
213///
214/// #[derive(GodotClass)]
215/// #[class(init)]
216/// struct Foo {
217/// #[export]
218/// obj: Option<Gd<Resource>>,
219/// #[export]
220/// array: Array<Gd<Resource>>,
221/// }
222/// ```
223///
224/// Tests with export of non-exportable type should fail:
225/// ```compile_fail
226/// use godot::prelude::*;
227///
228/// #[derive(GodotClass)]
229/// #[class(init)]
230/// struct Foo {
231/// #[export]
232/// obj: Option<Gd<Object>>,
233/// }
234/// ```
235///
236/// Neither `Gd<T>` nor `DynGd<T, D>` can be used with an `#[export]` directly:
237///
238/// ```compile_fail
239/// use godot::prelude::*;
240///
241/// #[derive(GodotClass)]
242/// #[class(init, base = Node)]
243/// struct MyClass {
244/// #[export]
245/// editor_property: Gd<Resource>,
246/// }
247/// ```
248///
249/// ```compile_fail
250/// use godot::prelude::*;
251///
252/// #[derive(GodotClass)]
253/// #[class(init, base = Node)]
254/// struct MyClass {
255/// #[export]
256/// editor_property: DynGd<Node, dyn Display>,
257/// }
258/// ```
259///
260/// ```compile_fail
261/// use godot::prelude::*;
262///
263/// #[derive(GodotClass)]
264/// #[class(init)]
265/// struct Foo {
266/// #[export]
267/// array: Array<Gd<Object>>,
268/// }
269/// ```
270fn __export_doctests() {}
271
272// ----------------------------------------------------------------------------------------------------------------------------------------------
273// Blanket impls for Option<T>
274
275impl<T> Var for Option<T>
276where
277 T: Var + FromGodot,
278 Option<T>: GodotConvert<Via = Option<T::Via>>,
279{
280 type PubType = Option<T::Via>; // Same as Self::Via.
281
282 fn var_get(field: &Self) -> Self::Via {
283 field.as_ref().map(T::var_get)
284 }
285
286 fn var_set(field: &mut Self, value: Self::Via) {
287 match value {
288 Some(via) => match field {
289 // If field is already set, delegate to setter (non-null) on field; otherwise assign new value.
290 Some(inner) => T::var_set(inner, via),
291 None => *field = Some(T::from_godot(via)),
292 },
293 None => *field = None,
294 }
295 }
296
297 fn var_pub_get(field: &Self) -> Self::PubType {
298 Self::var_get(field)
299 }
300
301 fn var_pub_set(field: &mut Self, value: Self::PubType) {
302 Self::var_set(field, value)
303 }
304}
305
306impl<T> Export for Option<T>
307where
308 T: Export,
309 Option<T>: Var,
310{
311}
312
313impl<T> BuiltinExport for Option<T>
314where
315 T: GodotType,
316 T::Ffi: GodotNullableFfi,
317{
318}
319
320// ----------------------------------------------------------------------------------------------------------------------------------------------
321// Export machinery
322
323/// Functions used to translate user-provided arguments into export hints.
324///
325/// You are not supposed to use these functions directly. They are used by the `#[export]` macro to generate the correct export hint.
326///
327/// Each function is named the same as the equivalent Godot annotation.
328/// For instance, `@export_range` in Godot is `fn export_range` here.
329pub mod export_fns {
330 use godot_ffi::VariantType;
331
332 use crate::builtin::GString;
333 use crate::meta::GodotConvert;
334 use crate::meta::shape::{GodotElementShape, GodotShape};
335 use crate::obj::EngineEnum;
336 use crate::registry::info::{PropertyHint, PropertyHintInfo};
337 use crate::registry::property::Export;
338 use crate::sys;
339
340 /// Turn a list of variables into a comma separated string containing only the identifiers corresponding
341 /// to a true boolean variable.
342 macro_rules! comma_separate_boolean_idents {
343 ($( $ident:ident),* $(,)?) => {
344 {
345 let mut strings = Vec::new();
346
347 $(
348 if $ident {
349 strings.push(stringify!($ident));
350 }
351 )*
352
353 strings.join(",")
354 }
355 };
356 }
357
358 // We want this to match the options available on `@export_range(..)`
359 /// Mark an exported numerical value to use the editor's range UI.
360 ///
361 /// You'll never call this function itself, but will instead use the macro `#[export(range=(...))]`, as below. The syntax is
362 /// very similar to Godot's [`@export_range`](https://docs.godotengine.org/en/stable/classes/class_%40gdscript.html#class-gdscript-annotation-export-range).
363 /// `min`, `max`, and `step` are `f32` positional arguments, with `step` being optional and defaulting to `1.0`. The rest of
364 /// the arguments can be written in any order. The symbols of type `bool` just need to have those symbols written, and those of type `Option<T>` will be written as `{KEY}={VALUE}`, e.g. `suffix="px"`.
365 ///
366 /// ```
367 /// # use godot::prelude::*;
368 /// #[derive(GodotClass)]
369 /// #[class(init, base=Node)]
370 /// struct MyClassWithRangedValues {
371 /// #[export(range=(0.0, 400.0, 1.0, or_greater, suffix="px"))]
372 /// icon_width: i32,
373 /// #[export(range=(-180.0, 180.0, degrees))]
374 /// angle: f32,
375 /// }
376 /// ```
377 #[allow(clippy::too_many_arguments)]
378 pub fn export_range(
379 min: f64,
380 max: f64,
381 step: Option<f64>,
382 or_greater: bool,
383 or_less: bool,
384 exp: bool,
385 radians_as_degrees: bool,
386 degrees: bool,
387 hide_slider: bool,
388 suffix: Option<String>,
389 ) -> PropertyHintInfo {
390 // From Godot 4.4, GDScript uses `.0` for integral floats, see https://github.com/godotengine/godot/pull/47502.
391 // We still register them the old way, to test compatibility. See also property_template_test.rs.
392
393 let hint_beginning = if let Some(step) = step {
394 format!("{min},{max},{step}")
395 } else {
396 format!("{min},{max}")
397 };
398
399 let rest = comma_separate_boolean_idents!(
400 or_greater,
401 or_less,
402 exp,
403 radians_as_degrees,
404 degrees,
405 hide_slider
406 );
407
408 let mut hint_string = hint_beginning;
409 if !rest.is_empty() {
410 hint_string.push_str(&format!(",{rest}"));
411 }
412 if let Some(suffix) = suffix {
413 hint_string.push_str(&format!(",suffix:{suffix}"));
414 }
415
416 PropertyHintInfo {
417 hint: PropertyHint::RANGE,
418 hint_string: GString::from(&hint_string),
419 }
420 }
421
422 #[doc(hidden)]
423 pub struct ExportValueWithKey<T> {
424 variant: String,
425 key: Option<T>,
426 }
427
428 impl<T: std::fmt::Display> ExportValueWithKey<T> {
429 fn as_hint_string(&self) -> String {
430 crate::meta::shape::format_hint_entry(&self.variant, self.key.as_ref())
431 }
432
433 fn slice_as_hint_string<V>(values: &[V]) -> String
434 where
435 for<'a> &'a V: Into<Self>,
436 {
437 let values = values
438 .iter()
439 .map(|v| v.into().as_hint_string())
440 .collect::<Vec<_>>();
441
442 values.join(",")
443 }
444 }
445
446 impl<T, S> From<&(S, Option<T>)> for ExportValueWithKey<T>
447 where
448 T: Clone,
449 S: AsRef<str>,
450 {
451 fn from((variant, key): &(S, Option<T>)) -> Self {
452 Self {
453 variant: variant.as_ref().into(),
454 key: key.clone(),
455 }
456 }
457 }
458
459 type ExportEnumEntry = ExportValueWithKey<i64>;
460
461 /// Equivalent to `@export_enum` in Godot.
462 ///
463 /// A name without a key would be represented as `(name, None)`, and a name with a key as `(name, Some(key))`.
464 ///
465 /// # Examples
466 ///
467 /// ```no_run
468 /// # use godot::register::property::export_fns::export_enum;
469 /// export_enum(&[("a", None), ("b", Some(10))]);
470 /// ```
471 pub fn export_enum<T>(variants: &[T]) -> PropertyHintInfo
472 where
473 for<'a> &'a T: Into<ExportEnumEntry>,
474 {
475 let hint_string: String = ExportEnumEntry::slice_as_hint_string(variants);
476
477 PropertyHintInfo {
478 hint: PropertyHint::ENUM,
479 hint_string: GString::from(&hint_string),
480 }
481 }
482
483 pub fn export_exp_easing(attenuation: bool, positive_only: bool) -> PropertyHintInfo {
484 let hint_string = comma_separate_boolean_idents!(attenuation, positive_only);
485
486 PropertyHintInfo {
487 hint: PropertyHint::EXP_EASING,
488 hint_string: GString::from(&hint_string),
489 }
490 }
491
492 type BitFlag = ExportValueWithKey<u32>;
493
494 /// Equivalent to `@export_flags` in Godot.
495 ///
496 /// A flag without a key would be represented as `(flag, None)`, and a flag with a key as `(flag, Some(key))`.
497 ///
498 /// # Examples
499 ///
500 /// ```no_run
501 /// # use godot::register::property::export_fns::export_flags;
502 /// export_flags(&[("a", None), ("b", Some(10))]);
503 /// ```
504 pub fn export_flags<T>(bits: &[T]) -> PropertyHintInfo
505 where
506 for<'a> &'a T: Into<BitFlag>,
507 {
508 let hint_string = BitFlag::slice_as_hint_string(bits);
509
510 PropertyHintInfo {
511 hint: PropertyHint::FLAGS,
512 hint_string: GString::from(&hint_string),
513 }
514 }
515
516 /// Handles `@export_file`, `@export_global_file`, `@export_dir` and `@export_global_dir`.
517 pub fn export_file_or_dir<T: Export>(
518 is_file: bool,
519 is_global: bool,
520 filter: impl AsRef<str>,
521 ) -> PropertyHintInfo {
522 let filter = filter.as_ref();
523 sys::strict_assert!(is_file || filter.is_empty()); // Dir never has filter.
524
525 export_file_or_dir_inner(&T::Via::godot_shape(), is_file, is_global, filter)
526 }
527
528 fn export_file_or_dir_inner(
529 shape: &GodotShape,
530 is_file: bool,
531 is_global: bool,
532 filter: &str,
533 ) -> PropertyHintInfo {
534 let hint = match (is_file, is_global) {
535 (true, true) => PropertyHint::GLOBAL_FILE,
536 (true, false) => PropertyHint::FILE,
537 (false, true) => PropertyHint::GLOBAL_DIR,
538 (false, false) => PropertyHint::DIR,
539 };
540
541 // Returned value depends on field type.
542 match shape {
543 // GString field:
544 // { "type": 4, "hint": 13, "hint_string": "*.png" }
545 GodotShape::Builtin {
546 variant_type: VariantType::STRING,
547 ..
548 } => PropertyHintInfo {
549 hint,
550 hint_string: GString::from(filter),
551 },
552
553 // Array<GString> or PackedStringArray field:
554 // { "type": 28, "hint": 23, "hint_string": "4/13:*.png" }
555 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
556 GodotShape::Builtin {
557 variant_type: VariantType::PACKED_STRING_ARRAY,
558 ..
559 } => to_string_array_hint(hint, filter),
560
561 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
562 GodotShape::TypedArray {
563 element:
564 GodotElementShape::Builtin {
565 variant_type: VariantType::STRING,
566 },
567 } => to_string_array_hint(hint, filter),
568
569 _ => {
570 // E.g. `global_file`.
571 let attribute_name = hint.as_str().to_lowercase();
572
573 // TODO nicer error handling.
574 // Compile time may be difficult (at least without extra traits... maybe const fn?). But at least more context info, field name etc.
575 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
576 panic!(
577 "#[export({attribute_name})] only supports GString, Array<String> or PackedStringArray field types\n\
578 encountered: {shape:?}"
579 );
580
581 #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
582 panic!(
583 "#[export({attribute_name})] only supports GString type prior to Godot 4.3\n\
584 encountered: {shape:?}"
585 );
586 }
587 }
588 }
589
590 /// For `Array<GString>` and `PackedStringArray` fields using one of the `@export[_global]_{file|dir}` annotations.
591 ///
592 /// Formats: `"4/13:"`, `"4/15:*.png"`, ...
593 fn to_string_array_hint(hint: PropertyHint, filter: &str) -> PropertyHintInfo {
594 PropertyHintInfo {
595 hint: PropertyHint::TYPE_STRING,
596 hint_string: GString::from(&crate::meta::shape::format_elements_typed(
597 VariantType::STRING,
598 hint,
599 filter,
600 )),
601 }
602 }
603
604 pub fn export_placeholder<S: AsRef<str>>(placeholder: S) -> PropertyHintInfo {
605 PropertyHintInfo {
606 hint: PropertyHint::PLACEHOLDER_TEXT,
607 hint_string: GString::from(placeholder.as_ref()),
608 }
609 }
610
611 macro_rules! default_export_funcs {
612 (
613 $( $function_name:ident => $property_hint:ident, )*
614 ) => {
615 $(
616 pub fn $function_name() -> PropertyHintInfo {
617 PropertyHintInfo {
618 hint: PropertyHint::$property_hint,
619 hint_string: GString::new()
620 }
621 }
622 )*
623 };
624 }
625
626 // The left side of these declarations follows the export annotation provided by GDScript, whereas the
627 // right side are the corresponding property hint. Godot is not always consistent between the two, such
628 // as `export_multiline` being `PROPERTY_HINT_MULTILINE_TEXT`.
629 default_export_funcs!(
630 export_storage => NONE, // Storage exports don't display in the editor.
631 export_flags_2d_physics => LAYERS_2D_PHYSICS,
632 export_flags_2d_render => LAYERS_2D_RENDER,
633 export_flags_2d_navigation => LAYERS_2D_NAVIGATION,
634 export_flags_3d_physics => LAYERS_3D_PHYSICS,
635 export_flags_3d_render => LAYERS_3D_RENDER,
636 export_flags_3d_navigation => LAYERS_3D_NAVIGATION,
637 export_multiline => MULTILINE_TEXT,
638 export_color_no_alpha => COLOR_NO_ALPHA,
639 );
640}
641
642mod export_impls {
643 use super::*;
644 use crate::builtin::*;
645
646 macro_rules! impl_property_by_godot_convert {
647 ($Ty:ty, no_export) => {
648 // For types without Export (Callable, Signal, Rid).
649 impl SimpleVar for $Ty {}
650 };
651
652 ($Ty:ty) => {
653 impl SimpleVar for $Ty {}
654 impl_property_by_godot_convert!(@export $Ty);
655 impl_property_by_godot_convert!(@builtin $Ty);
656 };
657
658 (@export $Ty:ty) => {
659 impl Export for $Ty {}
660 };
661
662 (@builtin $Ty:ty) => {
663 impl BuiltinExport for $Ty {}
664 }
665 }
666
667 // Bounding boxes
668 impl_property_by_godot_convert!(Aabb);
669 impl_property_by_godot_convert!(Rect2);
670 impl_property_by_godot_convert!(Rect2i);
671
672 // Matrices
673 impl_property_by_godot_convert!(Basis);
674 impl_property_by_godot_convert!(Transform2D);
675 impl_property_by_godot_convert!(Transform3D);
676 impl_property_by_godot_convert!(Projection);
677
678 // Vectors
679 impl_property_by_godot_convert!(Vector2);
680 impl_property_by_godot_convert!(Vector2i);
681 impl_property_by_godot_convert!(Vector3);
682 impl_property_by_godot_convert!(Vector3i);
683 impl_property_by_godot_convert!(Vector4);
684 impl_property_by_godot_convert!(Vector4i);
685
686 // Misc math
687 impl_property_by_godot_convert!(Quaternion);
688 impl_property_by_godot_convert!(Plane);
689
690 // Stringy types
691 impl_property_by_godot_convert!(GString);
692 impl_property_by_godot_convert!(StringName);
693 impl_property_by_godot_convert!(NodePath);
694
695 impl_property_by_godot_convert!(Color);
696 impl_property_by_godot_convert!(Variant);
697
698 // Primitives
699 impl_property_by_godot_convert!(f64);
700 impl_property_by_godot_convert!(i64);
701 impl_property_by_godot_convert!(bool);
702
703 // Godot uses f64 internally for floats, and if Godot tries to pass an invalid f32 into a rust property
704 // then the property will just round the value or become inf.
705 impl_property_by_godot_convert!(f32);
706
707 // Godot uses i64 internally for integers, and if Godot tries to pass an invalid integer into a property
708 // accepting one of the below values then rust will panic. In the editor this will appear as the property
709 // failing to be set to a value and an error printed in the console. During runtime this will crash the
710 // program and print the panic from rust stating that the property cannot store the value.
711 impl_property_by_godot_convert!(i32);
712 impl_property_by_godot_convert!(i16);
713 impl_property_by_godot_convert!(i8);
714 impl_property_by_godot_convert!(u32);
715 impl_property_by_godot_convert!(u16);
716 impl_property_by_godot_convert!(u8);
717
718 // Callables and Signals are useless when exported to the editor, so we only need to make them available as
719 // properties.
720 impl_property_by_godot_convert!(Callable, no_export);
721 impl_property_by_godot_convert!(Signal, no_export);
722
723 // RIDs when exported act slightly weird. They are largely read-only, however you can reset them to their
724 // default value. This seems to me very unintuitive. Since if we are storing an RID we would likely not
725 // want that RID to be spuriously resettable. And if used for debugging purposes we can use another
726 // mechanism than exporting the RID to the editor. Such as exporting a string containing the RID.
727 //
728 // Additionally, RIDs aren't persistent, and can sometimes behave a bit weirdly when passed from the
729 // editor to the runtime.
730 impl_property_by_godot_convert!(Rid, no_export);
731
732 // Var/Export for Array<T> and PackedArray<T> are implemented in the files of their struct declaration.
733
734 // impl_property_by_godot_convert!(Signal);
735}