Skip to content

Commit 3771abc

Browse files
committed
Clean up order of Packed*Array methods
1 parent f3ab4f9 commit 3771abc

File tree

1 file changed

+118
-117
lines changed

1 file changed

+118
-117
lines changed

godot-core/src/builtin/packed_array.rs

Lines changed: 118 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)