@@ -78,11 +78,17 @@ impl<T: VariantMetadata> Array<T> {
78
78
}
79
79
80
80
/// Returns the number of elements in the array. Equivalent of `size()` in Godot.
81
+ ///
82
+ /// Retrieving the size incurs an FFI call. If you know the size hasn't changed, you may consider storing
83
+ /// it in a variable. For loops, prefer iterators.
81
84
pub fn len ( & self ) -> usize {
82
85
to_usize ( self . as_inner ( ) . size ( ) )
83
86
}
84
87
85
88
/// Returns `true` if the array is empty.
89
+ ///
90
+ /// Checking for emptiness incurs an FFI call. If you know the size hasn't changed, you may consider storing
91
+ /// it in a variable. For loops, prefer iterators.
86
92
pub fn is_empty ( & self ) -> bool {
87
93
self . as_inner ( ) . is_empty ( )
88
94
}
@@ -150,10 +156,24 @@ impl<T: VariantMetadata> Array<T> {
150
156
///
151
157
/// If `index` is out of bounds.
152
158
fn ptr ( & self , index : usize ) -> * const Variant {
153
- self . check_bounds ( index) ;
159
+ let ptr = self . ptr_or_null ( index) ;
160
+ assert ! (
161
+ !ptr. is_null( ) ,
162
+ "Array index {index} out of bounds (len {len})" ,
163
+ len = self . len( ) ,
164
+ ) ;
165
+ ptr
166
+ }
167
+
168
+ /// Returns a pointer to the element at the given index, or null if out of bounds.
169
+ fn ptr_or_null ( & self , index : usize ) -> * const Variant {
170
+ // SAFETY: array_operator_index_const returns null for invalid indexes.
171
+ let variant_ptr = unsafe {
172
+ let index = to_i64 ( index) ;
173
+ interface_fn ! ( array_operator_index_const) ( self . sys ( ) , index)
174
+ } ;
154
175
155
- // SAFETY: We just checked that the index is not out of bounds.
156
- unsafe { self . ptr_unchecked ( index) }
176
+ Variant :: ptr_from_sys ( variant_ptr)
157
177
}
158
178
159
179
/// Returns a mutable pointer to the element at the given index.
@@ -162,29 +182,23 @@ impl<T: VariantMetadata> Array<T> {
162
182
///
163
183
/// If `index` is out of bounds.
164
184
fn ptr_mut ( & self , index : usize ) -> * mut Variant {
165
- self . check_bounds ( index) ;
166
-
167
- // SAFETY: We just checked that the index is not out of bounds.
168
- unsafe { self . ptr_mut_unchecked ( index) }
185
+ let ptr = self . ptr_mut_or_null ( index) ;
186
+ assert ! (
187
+ !ptr. is_null( ) ,
188
+ "Array index {index} out of bounds (len {len})" ,
189
+ len = self . len( ) ,
190
+ ) ;
191
+ ptr
169
192
}
170
193
171
- /// Returns a pointer to the element at the given index.
172
- ///
173
- /// # Safety
174
- ///
175
- /// Calling this with an out-of-bounds index is undefined behavior.
176
- unsafe fn ptr_unchecked ( & self , index : usize ) -> * const Variant {
177
- let variant_ptr = interface_fn ! ( array_operator_index_const) ( self . sys ( ) , to_i64 ( index) ) ;
178
- Variant :: ptr_from_sys ( variant_ptr)
179
- }
194
+ /// Returns a pointer to the element at the given index, or null if out of bounds.
195
+ fn ptr_mut_or_null ( & self , index : usize ) -> * mut Variant {
196
+ // SAFETY: array_operator_index returns null for invalid indexes.
197
+ let variant_ptr = unsafe {
198
+ let index = to_i64 ( index) ;
199
+ interface_fn ! ( array_operator_index) ( self . sys ( ) , index)
200
+ } ;
180
201
181
- /// Returns a mutable pointer to the element at the given index.
182
- ///
183
- /// # Safety
184
- ///
185
- /// Calling this with an out-of-bounds index is undefined behavior.
186
- unsafe fn ptr_mut_unchecked ( & self , index : usize ) -> * mut Variant {
187
- let variant_ptr = interface_fn ! ( array_operator_index) ( self . sys ( ) , to_i64 ( index) ) ;
188
202
Variant :: ptr_from_sys_mut ( variant_ptr)
189
203
}
190
204
@@ -365,6 +379,7 @@ impl<T: VariantMetadata + FromVariant> Array<T> {
365
379
///
366
380
/// If `index` is out of bounds.
367
381
pub fn get ( & self , index : usize ) -> T {
382
+ // Panics on out-of-bounds
368
383
let ptr = self . ptr ( index) ;
369
384
370
385
// SAFETY: `ptr()` just verified that the index is not out of bounds.
@@ -702,9 +717,11 @@ impl<T: VariantMetadata + ToVariant> From<&[T]> for Array<T> {
702
717
return array;
703
718
}
704
719
array. resize ( len) ;
705
- let ptr = array. ptr_mut ( 0 ) ;
720
+
721
+ let ptr = array. ptr_mut_or_null ( 0 ) ;
706
722
for ( i, element) in slice. iter ( ) . enumerate ( ) {
707
723
// SAFETY: The array contains exactly `len` elements, stored contiguously in memory.
724
+ // Also, the pointer is non-null, as we checked for emptiness above.
708
725
unsafe {
709
726
* ptr. offset ( to_isize ( i) ) = element. to_variant ( ) ;
710
727
}
@@ -767,10 +784,11 @@ impl<'a, T: VariantMetadata + FromVariant> Iterator for Iter<'a, T> {
767
784
if self . next_idx < self . array . len ( ) {
768
785
let idx = self . next_idx ;
769
786
self . next_idx += 1 ;
770
- // Using `ptr_unchecked` rather than going through `get()` so we can avoid a second
771
- // bounds check.
772
- // SAFETY: We just checked that the index is not out of bounds.
773
- let variant = unsafe { & * self . array . ptr_unchecked ( idx) } ;
787
+
788
+ let element_ptr = self . array . ptr_or_null ( idx) ;
789
+
790
+ // SAFETY: We just checked that the index is not out of bounds, so the pointer won't be null.
791
+ let variant = unsafe { & * element_ptr } ;
774
792
let element = T :: from_variant ( variant) ;
775
793
Some ( element)
776
794
} else {
0 commit comments