@@ -23,6 +23,38 @@ mod invalid_accessor;
23
23
pub mod hint;
24
24
25
25
/// Trait for exportable types.
26
+ ///
27
+ /// ## Rust collections
28
+ ///
29
+ /// `Export` is intentionally unimplemented for standard Rust collections, such as [`Vec`] or
30
+ /// [`HashMap`][std::collections::HashMap]. The reason is that such types exhibit surprising
31
+ /// behavior when used from GDScript, due to how [`ToVariant`]/[`FromVariant`] conversions work
32
+ /// for these types.
33
+ ///
34
+ /// Godot has no concept of Rust collections, and cannot operate on them. Whenever a standard
35
+ /// collection is converted to [`Variant`] via [`ToVariant`], what actually happens is that:
36
+ ///
37
+ /// - First, a new Godot collection of the corresponding "kind" is allocated.
38
+ /// - Then, the Rust collection is iterated over, and each element is converted and inserted into
39
+ /// the new collection, possibly triggering many more allocations in the process.
40
+ ///
41
+ /// With properties, this whole process happens anew *with each access to the property*, which
42
+ /// means that:
43
+ ///
44
+ /// - Modifying such properties from the remote debugger, or calling methods on the property
45
+ /// directly from GDScript (e.g. `thing.exported_vec.append("foo")`) do not produce the desired
46
+ /// behavior by the user.
47
+ /// - Seemingly innocuous expressions such as
48
+ /// `thing.exported_vec[0] + thing.exported_vec[1] + thing.exported_vec[2]` can be much more
49
+ /// expensive computationally than what the user would expect.
50
+ ///
51
+ /// As such, we do not allow these types to be exported as properties directly as a precaution.
52
+ /// If you wish to export collections to GDScript, consider the following options:
53
+ ///
54
+ /// - Exporting a [`Variant`] collection such as [`VariantArray`] or [`Dictionary`] explicitly,
55
+ /// embracing their respective semantics.
56
+ /// - Exporting not a property, but methods that have to be explicitly called, to set clear
57
+ /// expectations that the return value might be expensive to produce.
26
58
pub trait Export : crate :: core_types:: ToVariant {
27
59
/// A type-specific hint type that is valid for the type being exported.
28
60
///
@@ -455,8 +487,6 @@ pub struct Property<T> {
455
487
}
456
488
457
489
mod impl_export {
458
- use std:: collections:: { HashMap , HashSet } ;
459
-
460
490
use super :: * ;
461
491
462
492
/// Hint type indicating that there are no hints available for the time being.
@@ -615,41 +645,4 @@ mod impl_export {
615
645
hint. unwrap_or_default ( ) . export_info ( )
616
646
}
617
647
}
618
-
619
- impl < K , V > Export for HashMap < K , V >
620
- where
621
- K : std:: hash:: Hash + ToVariantEq + ToVariant ,
622
- V : ToVariant ,
623
- {
624
- type Hint = NoHint ;
625
-
626
- #[ inline]
627
- fn export_info ( _hint : Option < Self :: Hint > ) -> ExportInfo {
628
- ExportInfo :: new ( VariantType :: Dictionary )
629
- }
630
- }
631
-
632
- impl < T > Export for HashSet < T >
633
- where
634
- T : ToVariant ,
635
- {
636
- type Hint = NoHint ;
637
-
638
- #[ inline]
639
- fn export_info ( _hint : Option < Self :: Hint > ) -> ExportInfo {
640
- ExportInfo :: new ( VariantType :: VariantArray )
641
- }
642
- }
643
-
644
- impl < T > Export for Vec < T >
645
- where
646
- T : ToVariant ,
647
- {
648
- type Hint = NoHint ;
649
-
650
- #[ inline]
651
- fn export_info ( _hint : Option < Self :: Hint > ) -> ExportInfo {
652
- ExportInfo :: new ( VariantType :: VariantArray )
653
- }
654
- }
655
648
}
0 commit comments