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