Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add as_slice and as_mut_slice for Packed*Array #137

Closed
wants to merge 11 commits into from
Closed

Add as_slice and as_mut_slice for Packed*Array #137

wants to merge 11 commits into from

Conversation

indubitablement2
Copy link

@indubitablement2 indubitablement2 commented Mar 4, 2023

Piggyback off of ptr/ ptr_mut.

@Bromeon Bromeon added feature Adds functionality to the library c: core Core components labels Mar 4, 2023
Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this 👍

I think slices should be safe, since packed arrays are unique (not ref-counted). Would need to spend some deeper thoughts on it though, e.g. if the CoW backing implementation has any impact.

Could you maybe add one test case for each method, in itest/rust/src/packed_array_test.rs? It's enough to choose one concrete specialization, e.g. for i32, no need for genericity.

bors try

godot-core/src/builtin/packed_array.rs Show resolved Hide resolved
godot-core/src/builtin/packed_array.rs Show resolved Hide resolved
bors bot added a commit that referenced this pull request Mar 4, 2023
@bors
Copy link
Contributor

bors bot commented Mar 5, 2023

try

Build succeeded:

@indubitablement2
Copy link
Author

indubitablement2 commented Mar 5, 2023

Added some tests and safety comments.

@lilizoey
Copy link
Member

lilizoey commented Mar 5, 2023

You say Packed*Array is not aliased because it is COW. but they are in fact pass by reference at least within gdscript, and it seems the cow-ness of them is mostly not visible to a gdscript user at least. i am unsure if this is the case with gdextension as well.

see: godotengine/godot#36492 (comment)

does this cause any problems?

@indubitablement2
Copy link
Author

You say Packed*Array is not aliased because it is COW. but they are in fact pass by reference at least within gdscript, and it seems the cow-ness of them is mostly not visible to a gdscript user at least. i am unsure if this is the case with gdextension as well.

see: godotengine/godot#36492 (comment)

does this cause any problems?

Good catch! I only tested within rust. I'm not sure what happen when shared between rust and godot. I will make a test.

"arrays should share the same buffer"
);

// array2 should become a copy of array1 since rc > 1.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "RC > 1" is somewhat irrelevant, now that Godot 4 is released.

I would rather mention that as_mut_slice triggers a copy-on-write.

@indubitablement2
Copy link
Author

Alright, added tests for when arrays are shared between rust and godot. Looks like packed array are always cow except when sharing between godot and godot. You can even make array behave like godot 3 used to by passing it to and from rust.

@lilizoey
Copy link
Member

lilizoey commented Mar 5, 2023

Alright, added tests for when arrays are shared between rust and godot. Looks like packed array are always cow except when sharing between godot and godot. You can even make array behave like godot 3 used to by passing it to and from rust.

Ah ok, that should probably be properly documented. It is a bit unintuitive that these are passed by value in rust but passed by reference in gdscript.

@Bromeon
Copy link
Member

Bromeon commented Mar 5, 2023

Regarding merge conflicts, I made #[itest] self-registering, so you can throw out all the ceremony to call each test individually. Should be easy to rebase 🙂

@indubitablement2
Copy link
Author

Alright, added tests for when arrays are shared between rust and godot. Looks like packed array are always cow except when sharing between godot and godot. You can even make array behave like godot 3 used to by passing it to and from rust.

Ah ok, that should probably be properly documented. It is a bit unintuitive that these are passed by value in rust but passed by reference in gdscript.

I agree, but this is on the godot side. As far as gdextension is concerned, it's all cow.

This is what I've gathered:

_ _ Behavior
godot godot ref
godot rust cow
godot cpp copy (eg: Image.create_from_data())
rust cpp cow

Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates!

bors try

Comment on lines +265 to +286
#[godot_api]
impl PackedArrayTest {
#[func]
fn set_array(&mut self, array: PackedByteArray) {
self.array = array;
}

#[func]
fn get_array(&self) -> PackedByteArray {
self.array.clone()
}

#[func]
fn are_separate_buffer(&self, other: PackedByteArray) -> bool {
self.array.as_slice().as_ptr() != other.as_slice().as_ptr()
}

#[func]
fn do_mutable_access(&mut self) {
self.array.as_mut_slice();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type is currently acting as an abstraction that makes the tests quite a bit harder to understand, because one array is encapsulated, while the other is not.

I would remove the setter/getter as well as any state (struct fields), and just provide two functions:

  1. is_buffer_shared(&self, lhs: &PackedArray, rhs: &PackedArray)
    • basically the opposite of are_separate_buffer, but doesn't use the double negation
  2. trigger_cow(&self, array: &mut PackedArray)
    • same as do_mutable_access, but expressing the intent better

The receiver &self is only necessary because #[func] expects it, but you don't access the object's state. You also don't need to have a #[base] field or a impl GodotExt.

And if you have this abstraction, use it in Rust! 🙂
(see other comment)

Comment on lines +208 to +209
array1.as_slice().as_ptr(),
array2.as_slice().as_ptr(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you could use is_buffer_shared() (see other comment).

Same for similar occurrences.

Comment on lines +195 to +198
let array1 = PackedByteArray::from(&[1, 2]);
let mut array2 = array1.clone();
let array3 = array1.to_variant();
let array4 = godot::engine::Image::create_from_data(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you name those more meaningfully?

array1 -> array
array2 -> cloned
array3 -> variant
array4 -> image_data

bors bot added a commit that referenced this pull request Mar 5, 2023
@bors
Copy link
Contributor

bors bot commented Mar 5, 2023

try

Build succeeded:

@Bromeon
Copy link
Member

Bromeon commented Mar 6, 2023

Why close? 🤔

bors bot added a commit that referenced this pull request Jun 12, 2023
307: Implement `PackedArray::as_slice()`, `as_slice_mut()` r=Bromeon a=Bromeon

Resumes abandoned work of #137.
Closes #306.

Open points:
1. Test CoW across GDScript/Rust boundaries?
2. We now have `slice`, `as_slice` and `as_mut_slice`, where the first returns another array.
    I wonder if it would be clearer to name it `sub_array` or something instead of `slice`?

bors try

Co-authored-by: Jan Haller <bromeon@gmail.com>
bors bot added a commit that referenced this pull request Jun 12, 2023
307: Implement `PackedArray::as_slice()`, `as_slice_mut()` r=Bromeon a=Bromeon

Resumes abandoned work of #137.
Closes #306.

Open points:
1. Test CoW across GDScript/Rust boundaries?
2. We now have `slice`, `as_slice` and `as_mut_slice`, where the first returns another array.
    I wonder if it would be clearer to name it `sub_array` or something instead of `slice`?

bors try

Co-authored-by: Jan Haller <bromeon@gmail.com>
bors bot added a commit that referenced this pull request Jun 12, 2023
307: Implement `PackedArray::as_slice()`, `as_slice_mut()` r=Bromeon a=Bromeon

Resumes abandoned work of #137.
Closes #306.

Open points:
1. Test CoW across GDScript/Rust boundaries?
2. We now have `slice`, `as_slice` and `as_mut_slice`, where the first returns another array.
    I wonder if it would be clearer to name it `sub_array` or something instead of `slice`?

bors try

Co-authored-by: Jan Haller <bromeon@gmail.com>
bors bot added a commit that referenced this pull request Jun 12, 2023
307: Implement `PackedArray::as_slice()`, `as_slice_mut()` r=Bromeon a=Bromeon

Resumes abandoned work of #137.
Closes #306.

Open points:
1. Test CoW across GDScript/Rust boundaries?
2. We now have `slice`, `as_slice` and `as_mut_slice`, where the first returns another array.
    I wonder if it would be clearer to name it `sub_array` or something instead of `slice`?

bors try

Co-authored-by: Jan Haller <bromeon@gmail.com>
bors bot added a commit that referenced this pull request Jun 12, 2023
307: Implement `PackedArray::as_slice()`, `as_slice_mut()` r=Bromeon a=Bromeon

Resumes abandoned work of #137.
Closes #306.

Open points:
1. Test CoW across GDScript/Rust boundaries?
2. We now have `slice`, `as_slice` and `as_mut_slice`, where the first returns another array.
    I wonder if it would be clearer to name it `sub_array` or something instead of `slice`?

bors try

Co-authored-by: Jan Haller <bromeon@gmail.com>
bors bot added a commit that referenced this pull request Jun 13, 2023
307: Implement `PackedArray::as_slice()`, `as_slice_mut()` r=Bromeon a=Bromeon

Resumes abandoned work of #137.
Closes #306.

Open points:
1. Test CoW across GDScript/Rust boundaries?
2. We now have `slice`, `as_slice` and `as_mut_slice`, where the first returns another array.
    I wonder if it would be clearer to name it `sub_array` or something instead of `slice`?

bors try

Co-authored-by: Jan Haller <bromeon@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: core Core components feature Adds functionality to the library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants