Skip to content

Commit cf2e124

Browse files
bors[bot]Bromeon
andauthored
Merge #843
843: Add PoolArray::to_vec(), improve doc around read()/write() r=Bromeon a=Bromeon Closes #806. I noticed that the documentation around the `read()` and `write()` methods was a bit lacking, and tried to make it a bit easier to understand. Also moved trait `impl`s after the inherent `impl`. I'm not 100% sure that we really need `to_vec()`. It's nice as a convenience, but it may cause people to do things like ```rs pool_array.to_vec().map(...).collect() // or for elem in pool_array.to_vec() ``` instead of going via `read()`. After all, `read().to_vec()` is not much longer. On the other hand, we already have `PoolArray::from_vec()`, so it's somewhat symmetric. I'd be happy for some input on that. Co-authored-by: Jan Haller <[email protected]>
2 parents 35be953 + f588b6c commit cf2e124

File tree

2 files changed

+105
-59
lines changed

2 files changed

+105
-59
lines changed

gdnative-core/src/core_types/byte_array.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ godot_test!(
4040

4141
// the write shouldn't have affected the original array
4242
assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7], original_read.as_slice());
43+
44+
// check to_vec()
45+
assert_eq!(arr.to_vec(), vec![0, 1, 2, 3, 4, 5, 6, 7]);
4346
}
4447
);
4548

gdnative-core/src/core_types/pool_array.rs

Lines changed: 102 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ use crate::core_types::{Color, GodotString, VariantArray, Vector2, Vector3};
99
use crate::object::NewRef;
1010
use crate::private::get_api;
1111

12+
/// A RAII read access for Godot pool arrays.
13+
pub type Read<'a, T> = Aligned<ReadGuard<'a, T>>;
14+
15+
/// A RAII write access for Godot pool arrays. This will only lock the CoW container once,
16+
/// as opposed to every time with methods like `push()`.
17+
pub type Write<'a, T> = Aligned<WriteGuard<'a, T>>;
18+
1219
/// A reference-counted CoW typed vector using Godot's pool allocator, generic over possible
1320
/// element types.
1421
///
@@ -19,65 +26,21 @@ use crate::private::get_api;
1926
/// If you need other types, look into [`VariantArray`](struct.VariantArray.html) or directly use
2027
/// `Vec<T>` for type safety.
2128
///
22-
/// This type is CoW. The `Clone` implementation of this type creates a new reference without
23-
/// copying the contents.
29+
/// This type is CoW (copy-on-write). The `Clone` implementation of this type creates a new
30+
/// reference without copying the contents.
2431
///
25-
/// When using this type, it's generally better to perform mutations in batch using `write`,
26-
/// or the `append` methods, as opposed to `push` or `set`, because the latter ones trigger
32+
/// If you need to read elements, e.g. for iteration or conversion to another collection,
33+
/// the [`read()`][Self::read] method provides a view that dereferences to `&[T]`.
34+
/// Analogously, [`write()`][Self::write] provides a writable view that dereferences to `&mut [T]`.
35+
///
36+
/// For element mutations, it's usually recommended to do process them in batch using
37+
/// [`write()`][Self::write] or the [`append()`][Self::append] methods, as opposed to
38+
/// [`push()`][Self::push] or [`set()`][Self::set], because the latter ones trigger
2739
/// CoW behavior each time they are called.
2840
pub struct PoolArray<T: PoolElement> {
2941
inner: T::SysArray,
3042
}
3143

32-
/// A RAII read access for Godot typed arrays.
33-
pub type Read<'a, T> = Aligned<ReadGuard<'a, T>>;
34-
35-
/// A RAII write access for Godot typed arrays. This will only lock the CoW container once,
36-
/// as opposed to every time with methods like `push`.
37-
pub type Write<'a, T> = Aligned<WriteGuard<'a, T>>;
38-
39-
impl<T: PoolElement> Drop for PoolArray<T> {
40-
#[inline]
41-
fn drop(&mut self) {
42-
unsafe {
43-
(T::destroy_fn(get_api()))(self.sys_mut());
44-
}
45-
}
46-
}
47-
48-
impl<T: PoolElement> Default for PoolArray<T> {
49-
#[inline]
50-
fn default() -> Self {
51-
PoolArray::new()
52-
}
53-
}
54-
55-
impl<T: PoolElement + fmt::Debug> fmt::Debug for PoolArray<T> {
56-
#[inline]
57-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58-
f.debug_list().entries(self.read().iter()).finish()
59-
}
60-
}
61-
62-
impl<T: PoolElement> Clone for PoolArray<T> {
63-
#[inline]
64-
fn clone(&self) -> Self {
65-
self.new_ref()
66-
}
67-
}
68-
69-
impl<T: PoolElement> NewRef for PoolArray<T> {
70-
/// Creates a new reference to this reference-counted instance.
71-
#[inline]
72-
fn new_ref(&self) -> Self {
73-
unsafe {
74-
let mut inner = T::SysArray::default();
75-
(T::new_copy_fn(get_api()))(&mut inner, self.sys());
76-
PoolArray { inner }
77-
}
78-
}
79-
}
80-
8144
impl<T: PoolElement> PoolArray<T> {
8245
/// Creates an empty array.
8346
#[inline]
@@ -100,26 +63,56 @@ impl<T: PoolElement> PoolArray<T> {
10063
}
10164

10265
/// Creates a `PoolArray` moving elements from `src`.
66+
///
67+
/// If your source type isn't precisely a `Vec<T>`, keep in mind that `PoolElement` implements the
68+
/// `FromIterator` trait, which allows it to be constructed from iterators, typically through `collect()`.
69+
///
70+
/// For example:
71+
/// ```no_run
72+
/// // Int32Array is a type alias for PoolArray<i32>
73+
/// use gdnative::core_types::Int32Array;
74+
///
75+
/// // Collect from range
76+
/// let arr = (0..4).collect::<Int32Array>();
77+
///
78+
/// // Type conversion
79+
/// let vec: Vec<u32> = vec![1, 1, 2, 3, 5]; // note: unsigned
80+
/// let arr = vec.iter().map(|&e| e as i32).collect::<Int32Array>();
81+
/// ```
10382
#[inline]
10483
pub fn from_vec(mut src: Vec<T>) -> Self {
10584
let mut arr = Self::new();
10685
arr.append_vec(&mut src);
10786
arr
10887
}
10988

89+
/// Copies all elements to a `Vec`, leaving this instance untouched.
90+
///
91+
/// Equivalent to `self.read().to_vec()`. Only use this if your destination type is precisely
92+
/// a `Vec<T>`. Otherwise, call [`read()`][Self::read] which can be used as a slice.
93+
///
94+
#[inline]
95+
pub fn to_vec(&self) -> Vec<T>
96+
where
97+
T: Clone,
98+
{
99+
let guard = self.read();
100+
guard.to_vec()
101+
}
102+
110103
/// Appends an element to the end of the array.
111104
///
112-
/// Calling `push` triggers copy-on-write behavior. To insert a large number of elements,
113-
/// consider using `resize` and `write`.
105+
/// Calling `push()` triggers copy-on-write behavior. To insert a large number of elements,
106+
/// consider using [`append()`][Self::append], [`resize()`][Self::resize] or [`write()`][Self::write].
114107
#[inline]
115108
pub fn push(&mut self, val: T) {
116109
self.push_ref(&val)
117110
}
118111

119112
/// Appends an element to the end of the array by reference.
120113
///
121-
/// Calling `push` triggers copy-on-write behavior. To insert a large number of elements,
122-
/// consider using `resize` and `write`.
114+
/// Calling `push_ref()` triggers copy-on-write behavior. To insert a large number of elements,
115+
/// consider using [`append()`][Self::append], [`resize()`][Self::resize] or [`write()`][Self::write].
123116
#[inline]
124117
pub fn push_ref(&mut self, val: &T) {
125118
unsafe {
@@ -225,7 +218,10 @@ impl<T: PoolElement> PoolArray<T> {
225218
self.len() == 0
226219
}
227220

228-
/// Returns a RAII read access into this array.
221+
/// Returns a scoped read-only view into this array.
222+
///
223+
/// The returned read guard implements `Deref` with target type `[T]`, i.e. can be dereferenced to `&[T]`.
224+
/// This means all non-mutating (`&self`) slice methods can be used, see [here](struct.Aligned.html#deref-methods).
229225
#[inline]
230226
pub fn read(&self) -> Read<'_, T> {
231227
unsafe {
@@ -235,8 +231,11 @@ impl<T: PoolElement> PoolArray<T> {
235231
}
236232
}
237233

238-
/// Returns a RAII write access into this array. This triggers CoW once per lock, instead
234+
/// Returns a scoped read-write view into this array. This triggers CoW once per lock, instead
239235
/// of once each mutation.
236+
///
237+
/// The returned write guard implements `DerefMut` with target type `[T]`, i.e. can be dereferenced to `&mut [T]`.
238+
/// This means all mutating and read-only slice methods can be used, see [here](struct.Aligned.html#deref-methods).
240239
#[inline]
241240
pub fn write(&mut self) -> Write<'_, T> {
242241
unsafe {
@@ -268,6 +267,8 @@ impl<T: PoolElement> PoolArray<T> {
268267
impl<T: PoolElement + Copy> PoolArray<T> {
269268
/// Creates a new `PoolArray` by copying from `src`.
270269
///
270+
/// Equivalent to
271+
///
271272
/// # Panics
272273
///
273274
/// If the length of `src` does not fit in `i32`.
@@ -294,6 +295,48 @@ impl<T: PoolElement + Copy> PoolArray<T> {
294295
}
295296
}
296297

298+
impl<T: PoolElement> Drop for PoolArray<T> {
299+
#[inline]
300+
fn drop(&mut self) {
301+
unsafe {
302+
(T::destroy_fn(get_api()))(self.sys_mut());
303+
}
304+
}
305+
}
306+
307+
impl<T: PoolElement> Default for PoolArray<T> {
308+
#[inline]
309+
fn default() -> Self {
310+
PoolArray::new()
311+
}
312+
}
313+
314+
impl<T: PoolElement + fmt::Debug> fmt::Debug for PoolArray<T> {
315+
#[inline]
316+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317+
f.debug_list().entries(self.read().iter()).finish()
318+
}
319+
}
320+
321+
impl<T: PoolElement> Clone for PoolArray<T> {
322+
#[inline]
323+
fn clone(&self) -> Self {
324+
self.new_ref()
325+
}
326+
}
327+
328+
impl<T: PoolElement> NewRef for PoolArray<T> {
329+
/// Creates a new reference to this reference-counted instance.
330+
#[inline]
331+
fn new_ref(&self) -> Self {
332+
unsafe {
333+
let mut inner = T::SysArray::default();
334+
(T::new_copy_fn(get_api()))(&mut inner, self.sys());
335+
PoolArray { inner }
336+
}
337+
}
338+
}
339+
297340
// `FromIterator` and `Extend` implementations collect into `Vec` first, because Rust `Vec`s
298341
// are better at handling unknown lengths than the Godot arrays (`push` CoWs every time!)
299342

0 commit comments

Comments
 (0)