@@ -50,7 +50,9 @@ macro_rules! impl_packed_array {
50
50
) => {
51
51
// TODO expand type names in doc comments (use e.g. `paste` crate)
52
52
#[ doc = concat!( "Implements Godot's `" , stringify!( $PackedArray) , "` type," ) ]
53
- #[ doc = concat!( "which is an efficient array of `" , stringify!( $Element) , "`s." ) ]
53
+ #[ doc = concat!( "which is a space-efficient array of `" , stringify!( $Element) , "`s." ) ]
54
+ ///
55
+ /// Check out the [book](https://godot-rust.github.io/book/godot-api/builtins.html#packed-arrays) for a tutorial on packed arrays.
54
56
///
55
57
/// Note that, unlike `Array`, this type has value semantics: each copy will be independent
56
58
/// of the original. Under the hood, Godot uses copy-on-write, so copies are still cheap
@@ -62,7 +64,7 @@ macro_rules! impl_packed_array {
62
64
/// editor (for `#[export]`) will effectively keep an independent copy of the array. Writes to the packed array from Rust are thus not
63
65
/// reflected on the other side -- you may need to replace the entire array.
64
66
///
65
- /// See also [# godot/76150](https://github.com/godotengine/godot/issues/76150) for details.
67
+ /// See also [godot/# 76150](https://github.com/godotengine/godot/issues/76150) for details.
66
68
///
67
69
/// # Thread safety
68
70
///
@@ -79,15 +81,35 @@ macro_rules! impl_packed_array {
79
81
fn from_opaque( opaque: $Opaque) -> Self {
80
82
Self { opaque }
81
83
}
82
- }
83
84
84
- // This impl relies on `$Inner` which is not (yet) available in unit tests
85
- impl $PackedArray {
86
85
/// Constructs an empty array.
87
86
pub fn new( ) -> Self {
88
87
Self :: default ( )
89
88
}
90
89
90
+ /// Returns a copy of the value at the specified index, or `None` if out-of-bounds.
91
+ ///
92
+ /// If you know the index is valid, use the `[]` operator (`Index`/`IndexMut` traits) instead.
93
+ pub fn get( & self , index: usize ) -> Option <$Element> {
94
+ let ptr = self . ptr_or_none( index) ?;
95
+
96
+ // SAFETY: if index was out of bounds, `ptr` would be `None` and return early.
97
+ unsafe { Some ( ( * ptr) . clone( ) ) }
98
+ }
99
+
100
+ /// Returns `true` if the array contains the given value.
101
+ ///
102
+ /// _Godot equivalent: `has`_
103
+ #[ doc( alias = "has" ) ]
104
+ pub fn contains( & self , value: $Element) -> bool {
105
+ self . as_inner( ) . has( Self :: into_arg( value) )
106
+ }
107
+
108
+ /// Returns the number of times a value is in the array.
109
+ pub fn count( & self , value: $Element) -> usize {
110
+ to_usize( self . as_inner( ) . count( Self :: into_arg( value) ) )
111
+ }
112
+
91
113
/// Returns the number of elements in the array. Equivalent of `size()` in Godot.
92
114
pub fn len( & self ) -> usize {
93
115
to_usize( self . as_inner( ) . size( ) )
@@ -98,6 +120,86 @@ macro_rules! impl_packed_array {
98
120
self . as_inner( ) . is_empty( )
99
121
}
100
122
123
+ /// Clears the array, removing all elements.
124
+ pub fn clear( & mut self ) {
125
+ self . as_inner( ) . clear( ) ;
126
+ }
127
+
128
+ /// Sets the value at the specified index.
129
+ ///
130
+ /// # Panics
131
+ ///
132
+ /// If `index` is out of bounds.
133
+ #[ deprecated = "Use [] operator (IndexMut) instead." ]
134
+ pub fn set( & mut self , index: usize , value: $Element) {
135
+ let ptr_mut = self . ptr_mut( index) ;
136
+
137
+ // SAFETY: `ptr_mut` just checked that the index is not out of bounds.
138
+ unsafe {
139
+ * ptr_mut = value;
140
+ }
141
+ }
142
+
143
+ /// Appends an element to the end of the array. Equivalent of `append` and `push_back`
144
+ /// in GDScript.
145
+ #[ doc( alias = "append" ) ]
146
+ #[ doc( alias = "push_back" ) ]
147
+ pub fn push( & mut self , value: $Element) {
148
+ self . as_inner( ) . push_back( Self :: into_arg( value) ) ;
149
+ }
150
+
151
+ /// Inserts a new element at a given index in the array. The index must be valid, or at
152
+ /// the end of the array (`index == len()`).
153
+ ///
154
+ /// Note: On large arrays, this method is much slower than `push` as it will move all
155
+ /// the array's elements after the inserted element. The larger the array, the slower
156
+ /// `insert` will be.
157
+ pub fn insert( & mut self , index: usize , value: $Element) {
158
+ // Intentional > and not >=.
159
+ if index > self . len( ) {
160
+ self . panic_out_of_bounds( index) ;
161
+ }
162
+
163
+ self . as_inner( ) . insert( to_i64( index) , Self :: into_arg( value) ) ;
164
+ }
165
+
166
+ /// Removes and returns the element at the specified index. Similar to `remove_at` in
167
+ /// GDScript, but also returns the removed value.
168
+ ///
169
+ /// On large arrays, this method is much slower than `pop_back` as it will move all the array's
170
+ /// elements after the removed element. The larger the array, the slower `remove` will be.
171
+ ///
172
+ /// # Panics
173
+ ///
174
+ /// If `index` is out of bounds.
175
+ // Design note: This returns the removed value instead of `()` for consistency with
176
+ // `Array` and with `Vec::remove`. Compared to shifting all the subsequent array
177
+ // elements to their new position, the overhead of retrieving this element is trivial.
178
+ #[ doc( alias = "remove_at" ) ]
179
+ pub fn remove( & mut self , index: usize ) -> $Element {
180
+ let element = self [ index] . clone( ) ; // panics on out-of-bounds
181
+ self . as_inner( ) . remove_at( to_i64( index) ) ;
182
+ element
183
+ }
184
+
185
+ /// Assigns the given value to all elements in the array. This can be used together
186
+ /// with `resize` to create an array with a given size and initialized elements.
187
+ pub fn fill( & mut self , value: $Element) {
188
+ self . as_inner( ) . fill( Self :: into_arg( value) ) ;
189
+ }
190
+
191
+ /// Resizes the array to contain a different number of elements. If the new size is
192
+ /// smaller, elements are removed from the end. If the new size is larger, new elements
193
+ /// are set to [`Default::default()`].
194
+ pub fn resize( & mut self , size: usize ) {
195
+ self . as_inner( ) . resize( to_i64( size) ) ;
196
+ }
197
+
198
+ /// Appends another array at the end of this array. Equivalent of `append_array` in GDScript.
199
+ pub fn extend_array( & mut self , other: & $PackedArray) {
200
+ self . as_inner( ) . append_array( other. clone( ) ) ;
201
+ }
202
+
101
203
/// Converts this array to a Rust vector, making a copy of its contents.
102
204
pub fn to_vec( & self ) -> Vec <$Element> {
103
205
let len = self . len( ) ;
@@ -117,18 +219,6 @@ macro_rules! impl_packed_array {
117
219
vec
118
220
}
119
221
120
- /// Clears the array, removing all elements.
121
- pub fn clear( & mut self ) {
122
- self . as_inner( ) . clear( ) ;
123
- }
124
-
125
- /// Resizes the array to contain a different number of elements. If the new size is
126
- /// smaller, elements are removed from the end. If the new size is larger, new elements
127
- /// are set to [`Default::default()`].
128
- pub fn resize( & mut self , size: usize ) {
129
- self . as_inner( ) . resize( to_i64( size) ) ;
130
- }
131
-
132
222
/// Returns a sub-range `begin..end`, as a new packed array.
133
223
///
134
224
/// This method is called `slice()` in Godot.
@@ -183,40 +273,6 @@ macro_rules! impl_packed_array {
183
273
}
184
274
}
185
275
186
- /// Returns a copy of the value at the specified index.
187
- ///
188
- /// # Panics
189
- ///
190
- /// If `index` is out of bounds.
191
- pub fn get( & self , index: usize ) -> Option <$Element> {
192
- let ptr = self . ptr_or_none( index) ?;
193
-
194
- // SAFETY: if index was out of bounds, `ptr` would be `None` and return early.
195
- unsafe { Some ( ( * ptr) . clone( ) ) }
196
- }
197
-
198
- /// Finds the index of an existing value in a sorted array using binary search.
199
- /// Equivalent of `bsearch` in GDScript.
200
- ///
201
- /// If the value is not present in the array, returns the insertion index that would
202
- /// maintain sorting order.
203
- ///
204
- /// Calling `binary_search` on an unsorted array results in unspecified behavior.
205
- pub fn binary_search( & self , value: $Element) -> usize {
206
- to_usize( self . as_inner( ) . bsearch( Self :: into_arg( value) , true ) )
207
- }
208
-
209
- /// Returns the number of times a value is in the array.
210
- pub fn count( & self , value: $Element) -> usize {
211
- to_usize( self . as_inner( ) . count( Self :: into_arg( value) ) )
212
- }
213
-
214
- /// Returns `true` if the array contains the given value. Equivalent of `has` in
215
- /// GDScript.
216
- pub fn contains( & self , value: $Element) -> bool {
217
- self . as_inner( ) . has( Self :: into_arg( value) )
218
- }
219
-
220
276
/// Searches the array for the first occurrence of a value and returns its index, or
221
277
/// `None` if not found. Starts searching at index `from`; pass `None` to search the
222
278
/// entire array.
@@ -244,72 +300,18 @@ macro_rules! impl_packed_array {
244
300
}
245
301
}
246
302
247
- /// Sets the value at the specified index.
248
- ///
249
- /// # Panics
250
- ///
251
- /// If `index` is out of bounds.
252
- pub fn set( & mut self , index: usize , value: $Element) {
253
- let ptr_mut = self . ptr_mut( index) ;
254
-
255
- // SAFETY: `ptr_mut` just checked that the index is not out of bounds.
256
- unsafe {
257
- * ptr_mut = value;
258
- }
259
- }
260
-
261
- /// Appends an element to the end of the array. Equivalent of `append` and `push_back`
262
- /// in GDScript.
263
- #[ doc( alias = "append" ) ]
264
- #[ doc( alias = "push_back" ) ]
265
- pub fn push( & mut self , value: $Element) {
266
- self . as_inner( ) . push_back( Self :: into_arg( value) ) ;
267
- }
268
-
269
- /// Inserts a new element at a given index in the array. The index must be valid, or at
270
- /// the end of the array (`index == len()`).
271
- ///
272
- /// Note: On large arrays, this method is much slower than `push` as it will move all
273
- /// the array's elements after the inserted element. The larger the array, the slower
274
- /// `insert` will be.
275
- pub fn insert( & mut self , index: usize , value: $Element) {
276
- // Intentional > and not >=.
277
- if index > self . len( ) {
278
- self . panic_out_of_bounds( index) ;
279
- }
280
-
281
- self . as_inner( ) . insert( to_i64( index) , Self :: into_arg( value) ) ;
282
- }
283
-
284
- /// Removes and returns the element at the specified index. Similar to `remove_at` in
285
- /// GDScript, but also returns the removed value.
303
+ /// Finds the index of an existing value in a _sorted_ array using binary search.
286
304
///
287
- /// On large arrays, this method is much slower than `pop_back` as it will move all the array's
288
- /// elements after the removed element. The larger the array, the slower `remove` will be.
289
- ///
290
- /// # Panics
305
+ /// If the value is not present in the array, returns the insertion index that would maintain sorting order.
291
306
///
292
- /// If `index` is out of bounds.
293
- // Design note: This returns the removed value instead of `()` for consistency with
294
- // `Array` and with `Vec::remove`. Compared to shifting all the subsequent array
295
- // elements to their new position, the overhead of retrieving this element is trivial.
296
- #[ doc( alias = "remove_at" ) ]
297
- pub fn remove( & mut self , index: usize ) -> $Element {
298
- let element = self [ index] . clone( ) ; // panics on out-of-bounds
299
- self . as_inner( ) . remove_at( to_i64( index) ) ;
300
- element
301
- }
302
-
303
- /// Assigns the given value to all elements in the array. This can be used together
304
- /// with `resize` to create an array with a given size and initialized elements.
305
- pub fn fill( & mut self , value: $Element) {
306
- self . as_inner( ) . fill( Self :: into_arg( value) ) ;
307
+ /// Calling `bsearch()` on an unsorted array results in unspecified (but safe) behavior.
308
+ pub fn bsearch( & self , value: $Element) -> usize {
309
+ to_usize( self . as_inner( ) . bsearch( Self :: into_arg( value) , true ) )
307
310
}
308
311
309
- /// Appends another array at the end of this array. Equivalent of `append_array` in
310
- /// GDScript.
311
- pub fn extend_array( & mut self , other: & $PackedArray) {
312
- self . as_inner( ) . append_array( other. clone( ) ) ;
312
+ #[ deprecated = "Renamed to bsearch like in Godot, to avoid confusion with Rust's slice::binary_search." ]
313
+ pub fn binary_search( & self , value: $Element) -> usize {
314
+ self . bsearch( value)
313
315
}
314
316
315
317
/// Reverses the order of the elements in the array.
@@ -318,17 +320,16 @@ macro_rules! impl_packed_array {
318
320
}
319
321
320
322
/// Sorts the elements of the array in ascending order.
321
- // Presumably, just like `Array`, this is not a stable sort so we might call it
322
- // `sort_unstable`. But Packed*Array elements that compare equal are always identical,
323
- // so it doesn 't matter .
323
+ ///
324
+ /// This sort is [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability), since elements inside packed arrays are
325
+ /// indistinguishable. Relative order between equal elements thus isn 't observable .
324
326
pub fn sort( & mut self ) {
325
327
self . as_inner( ) . sort( ) ;
326
328
}
327
329
328
330
// Include specific functions in the code only if the Packed*Array provides the function.
329
331
impl_specific_packed_array_functions!( $PackedArray) ;
330
332
331
-
332
333
/// # Panics
333
334
///
334
335
/// Always.
0 commit comments