@@ -50,7 +50,9 @@ macro_rules! impl_packed_array {
5050 ) => {
5151 // TODO expand type names in doc comments (use e.g. `paste` crate)
5252 #[ 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.
5456 ///
5557 /// Note that, unlike `Array`, this type has value semantics: each copy will be independent
5658 /// 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 {
6264 /// editor (for `#[export]`) will effectively keep an independent copy of the array. Writes to the packed array from Rust are thus not
6365 /// reflected on the other side -- you may need to replace the entire array.
6466 ///
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.
6668 ///
6769 /// # Thread safety
6870 ///
@@ -79,15 +81,35 @@ macro_rules! impl_packed_array {
7981 fn from_opaque( opaque: $Opaque) -> Self {
8082 Self { opaque }
8183 }
82- }
8384
84- // This impl relies on `$Inner` which is not (yet) available in unit tests
85- impl $PackedArray {
8685 /// Constructs an empty array.
8786 pub fn new( ) -> Self {
8887 Self :: default ( )
8988 }
9089
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+
91113 /// Returns the number of elements in the array. Equivalent of `size()` in Godot.
92114 pub fn len( & self ) -> usize {
93115 to_usize( self . as_inner( ) . size( ) )
@@ -98,6 +120,86 @@ macro_rules! impl_packed_array {
98120 self . as_inner( ) . is_empty( )
99121 }
100122
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+
101203 /// Converts this array to a Rust vector, making a copy of its contents.
102204 pub fn to_vec( & self ) -> Vec <$Element> {
103205 let len = self . len( ) ;
@@ -117,18 +219,6 @@ macro_rules! impl_packed_array {
117219 vec
118220 }
119221
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-
132222 /// Returns a sub-range `begin..end`, as a new packed array.
133223 ///
134224 /// This method is called `slice()` in Godot.
@@ -183,40 +273,6 @@ macro_rules! impl_packed_array {
183273 }
184274 }
185275
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-
220276 /// Searches the array for the first occurrence of a value and returns its index, or
221277 /// `None` if not found. Starts searching at index `from`; pass `None` to search the
222278 /// entire array.
@@ -244,72 +300,18 @@ macro_rules! impl_packed_array {
244300 }
245301 }
246302
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.
286304 ///
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.
291306 ///
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 ) )
307310 }
308311
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)
313315 }
314316
315317 /// Reverses the order of the elements in the array.
@@ -318,17 +320,16 @@ macro_rules! impl_packed_array {
318320 }
319321
320322 /// 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 .
324326 pub fn sort( & mut self ) {
325327 self . as_inner( ) . sort( ) ;
326328 }
327329
328330 // Include specific functions in the code only if the Packed*Array provides the function.
329331 impl_specific_packed_array_functions!( $PackedArray) ;
330332
331-
332333 /// # Panics
333334 ///
334335 /// Always.
0 commit comments