@@ -33,7 +33,6 @@ use crate::registry::property::{BuiltinExport, Export, Var};
3333/// Check out the [book](https://godot-rust.github.io/book/godot-api/builtins.html#arrays-and-dictionaries) for a tutorial on arrays.
3434///
3535/// # Reference semantics
36- ///
3736/// Like in GDScript, `Array` acts as a reference type: multiple `Array` instances may
3837/// refer to the same underlying array, and changes to one are visible in the other.
3938///
@@ -42,7 +41,6 @@ use crate::registry::property::{BuiltinExport, Export, Var};
4241/// or [`duplicate_deep()`][Self::duplicate_deep].
4342///
4443/// # Element type
45- ///
4644/// Godot's `Array` builtin can be either typed or untyped. In Rust, this maps to three representations:
4745///
4846/// - Untyped array: `VariantArray`, a type alias for `Array<Variant>`. \
@@ -55,14 +53,29 @@ use crate::registry::property::{BuiltinExport, Export, Var};
5553/// Represents either typed or untyped arrays. This is different from `Array<Variant>`, because the latter allows you to insert
5654/// `Variant` objects. However, for an array that has dynamic type `i64`, it is not allowed to insert any variants that are not `i64`.
5755///
58- /// Godot APIs reflect this. You can `Deref`-coerce from any `Array<T>` to `AnyArray` (e.g. when passing arguments), and explicitly
59- /// convert the other way, using [`AnyArray::try_into_typed()`] and [`AnyArray::try_into_untyped()`].
60- ///
6156/// If you plan to use any integer or float types apart from `i64` and `f64`, read
6257/// [this documentation](../meta/trait.ArrayElement.html#integer-and-float-types).
6358///
64- /// ## Typed array example
59+ /// ## Conversions between arrays
60+ /// The following table gives an overview of useful conversions.
61+ ///
62+ /// | From | To | Conversion method |
63+ /// |--------------------|------------------|----------------------------------------------------------|
64+ /// | `AnyArray` | `Array<T>` | [`AnyArray::try_cast_array::<T>`] |
65+ /// | `AnyArray` | `Array<Variant>` | [`AnyArray::try_cast_var_array`] |
66+ /// | `&Array<T>` | `&AnyArray` | Implicit via [deref coercion]; often used in class APIs. |
67+ /// | `Array<T>` | `AnyArray` | [`Array<T>::upcast_any_array`] |
68+ /// | `Array<T>` | `PackedArray<T>` | [`Array<T>::to_packed_array`] |
69+ /// | `PackedArray<T>` | `Array<T>` | [`PackedArray<T>::to_typed_array`] |
70+ /// | `PackedArray<T>` | `Array<Variant>` | [`PackedArray<T>::to_var_array`] |
6571///
72+ /// Note that it's **not** possible to upcast `Array<Gd<Derived>>` to `Array<Gd<Base>>`. `Array<T>` is not covariant over the `T` parameter,
73+ /// otherwise it would be possible to insert `Base` pointers that aren't actually `Derived`.
74+ // Note: the above could theoretically be implemented by making AnyArray<T> generic and covariant over T.
75+ ///
76+ /// [deref coercion]: struct.Array.html#deref-methods-AnyArray
77+ ///
78+ /// ## Typed array example
6679/// ```no_run
6780/// # use godot::prelude::*;
6881/// // Create typed Array<i64> and add values.
@@ -95,7 +108,6 @@ use crate::registry::property::{BuiltinExport, Export, Var};
95108/// ```
96109///
97110/// ## Untyped array example
98- ///
99111/// ```no_run
100112/// # use godot::prelude::*;
101113/// // VarArray allows dynamic element types.
@@ -116,7 +128,6 @@ use crate::registry::property::{BuiltinExport, Export, Var};
116128/// ```
117129///
118130/// # Working with signed ranges and steps
119- ///
120131/// For negative indices, use [`wrapped()`](crate::meta::wrapped).
121132///
122133/// ```no_run
@@ -145,14 +156,12 @@ use crate::registry::property::{BuiltinExport, Export, Var};
145156/// ```
146157///
147158/// # Thread safety
148- ///
149159/// Usage is safe if the `Array` is used on a single thread only. Concurrent reads on
150160/// different threads are also safe, but any writes must be externally synchronized. The Rust
151161/// compiler will enforce this as long as you use only Rust threads, but it cannot protect against
152162/// concurrent modification on other threads (e.g. created through GDScript).
153163///
154164/// # Element type safety
155- ///
156165/// We provide a richer set of element types than Godot, for convenience and stronger invariants in your _Rust_ code.
157166/// This, however, means that the Godot representation of such arrays is not capable of incorporating the additional "Rust-side" information.
158167/// This can lead to situations where GDScript code or the editor UI can insert values that do not fulfill the Rust-side invariants.
@@ -168,11 +177,9 @@ use crate::registry::property::{BuiltinExport, Export, Var};
168177/// Godot doesn't know Rust traits and will only see the `T` part.
169178///
170179/// # Differences from GDScript
171- ///
172180/// Unlike GDScript, all indices and sizes are unsigned, so negative indices are not supported.
173181///
174182/// # Godot docs
175- ///
176183/// [`Array[T]` (stable)](https://docs.godotengine.org/en/stable/classes/class_array.html)
177184pub struct Array < T : ArrayElement > {
178185 // Safety Invariant: The type of all values in `opaque` matches the type `T`.
@@ -761,7 +768,7 @@ impl<T: ArrayElement> Array<T> {
761768 ///
762769 /// Typically, you can use deref coercion to convert `&Array<T>` to `&AnyArray`. This method is useful if you need `AnyArray` by value.
763770 /// It consumes `self` to avoid incrementing the reference count; use `clone()` if you use the original array further.
764- pub fn into_any ( self ) -> AnyArray {
771+ pub fn upcast_any_array ( self ) -> AnyArray {
765772 AnyArray :: from_typed_or_untyped ( self )
766773 }
767774
@@ -890,6 +897,7 @@ impl<T: ArrayElement> Array<T> {
890897 /// Note also that any `GodotType` can be written to a `Variant` array.
891898 ///
892899 /// In the current implementation, both cases will produce a panic rather than undefined behavior, but this should not be relied upon.
900+ #[ cfg( safeguards_strict) ]
893901 unsafe fn assume_type_ref < U : ArrayElement > ( & self ) -> & Array < U > {
894902 // The memory layout of `Array<T>` does not depend on `T`.
895903 std:: mem:: transmute :: < & Array < T > , & Array < U > > ( self )
@@ -1088,12 +1096,6 @@ impl<T: ArrayElement> Array<T> {
10881096 }
10891097}
10901098
1091- #[ test]
1092- fn correct_variant_t ( ) {
1093- assert ! ( Array :: <Variant >:: has_variant_t( ) ) ;
1094- assert ! ( !Array :: <i64 >:: has_variant_t( ) ) ;
1095- }
1096-
10971099impl VarArray {
10981100 /// # Safety
10991101 /// - Variant must have type `VariantType::ARRAY`.
@@ -1371,6 +1373,9 @@ impl<T: ArrayElement> GodotFfiVariant for Array<T> {
13711373// ----------------------------------------------------------------------------------------------------------------------------------------------
13721374// Conversion traits
13731375
1376+ // From impls converting values (like [T; N] or Vec<T>) are explicitly not supported, because there's no perf benefit in submitting ownership.
1377+ // This is different for PackedArray, which can move values. See also related: https://github.com/godot-rust/gdext/pull/1286.
1378+
13741379/// Creates a `Array` from the given Rust array.
13751380impl < T : ArrayElement + ToGodot , const N : usize > From < & [ T ; N ] > for Array < T > {
13761381 fn from ( arr : & [ T ; N ] ) -> Self {
@@ -1444,6 +1449,7 @@ impl<T: ArrayElement + FromGodot> From<&Array<T>> for Vec<T> {
14441449}
14451450
14461451// ----------------------------------------------------------------------------------------------------------------------------------------------
1452+ // Iterators
14471453
14481454/// An iterator over typed elements of an [`Array`].
14491455pub struct Iter < ' a , T : ArrayElement > {
@@ -1515,6 +1521,7 @@ impl<T: ArrayElement> PartialOrd for Array<T> {
15151521}
15161522
15171523// ----------------------------------------------------------------------------------------------------------------------------------------------
1524+ // Expression macros
15181525
15191526/// Constructs [`Array`] literals, similar to Rust's standard `vec!` macro.
15201527///
@@ -1634,6 +1641,7 @@ macro_rules! vslice {
16341641}
16351642
16361643// ----------------------------------------------------------------------------------------------------------------------------------------------
1644+ // Serde support
16371645
16381646#[ cfg( feature = "serde" ) ]
16391647mod serialize {
@@ -1704,3 +1712,36 @@ mod serialize {
17041712 }
17051713 }
17061714}
1715+
1716+ // ----------------------------------------------------------------------------------------------------------------------------------------------
1717+ // Tests
1718+
1719+ /// Verifies that `AnyArray::try_cast*()` cannot be called on concrete arrays.
1720+ ///
1721+ /// > error[E0507]: cannot move out of dereference of `godot::prelude::Array<i64>`
1722+ ///
1723+ /// ```compile_fail
1724+ /// use godot::prelude::*;
1725+ /// let a: Array<i64> = array![1, 2, 3];
1726+ /// a.try_cast_var_array();
1727+ /// ```
1728+ ///
1729+ /// ```compile_fail
1730+ /// use godot::prelude::*;
1731+ /// let a: VarArray = varray![1, 2, 3];
1732+ /// a.try_cast_array::<i64>();
1733+ /// ```
1734+ ///
1735+ /// This works:
1736+ /// ```no_run
1737+ /// use godot::prelude::*;
1738+ /// let a: VarArray = varray![1, 2, 3];
1739+ /// a.upcast_any_array().try_cast_array::<i64>();
1740+ /// ```
1741+ fn __cannot_downcast_from_concrete ( ) { }
1742+
1743+ #[ test]
1744+ fn correct_variant_t ( ) {
1745+ assert ! ( Array :: <Variant >:: has_variant_t( ) ) ;
1746+ assert ! ( !Array :: <i64 >:: has_variant_t( ) ) ;
1747+ }
0 commit comments