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

Vec improvements #427

Closed
wants to merge 5 commits into from
Closed

Conversation

YuhanLiin
Copy link
Contributor

@YuhanLiin YuhanLiin commented Dec 20, 2023

Add spare_capacity_mut and From implementation for Vec, as well as vec! macro.
Resolves #426 and #344

@YuhanLiin YuhanLiin changed the title Add spare_capacity_mut Vec improvements Dec 20, 2023
@YuhanLiin YuhanLiin marked this pull request as draft December 20, 2023 07:04
src/vec.rs Outdated
fn from(buffer: [T; N]) -> Self {
Self {
// cast [T; N] into [MaybeUninit<T>; N]
buffer: unsafe { buffer.as_ptr().cast::<[MaybeUninit<T>; N]>().read() },
Copy link
Member

Choose a reason for hiding this comment

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

this does a bitwise copy of the elements into the Vec, but will still drop them when buffer goes out of scope. This will cause use-after-frees if T is an owned type, like Box.

You can wrap the buffer into a ManuallyDrop to avoid this.

src/vec.rs Outdated
@@ -858,6 +888,17 @@ impl<T, const N: usize> Drop for Vec<T, N> {
}
}

impl<T, const N: usize> From<[T; N]> for Vec<T, N> {
Copy link
Member

Choose a reason for hiding this comment

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

it feels a bit strange that the array length becomes the capacity. Intuitively I'd say it should be possible to convert a [u8; 10] into a Vec<u8; 20> with 10 filled elements.

This would fail if CAP < N, and there's no way to add where CAP >= N in const generics, so tihs'd have to be TryFrom which perhaps is not that ergonomic?

Copy link
Contributor

Choose a reason for hiding this comment

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

There is a way to generate a compile error in that case. This PR does this: #352

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought doing it this way would allow me to "move" the array into the Vec without copying, but it turns out that copying will happen either way, so might as well allow N < CAP.

@YuhanLiin YuhanLiin marked this pull request as ready for review December 21, 2023 19:44
heapless::Vec::<_, $cap>::new()
};

($($elem:expr),+ ; $cap:expr) => {
Copy link
Member

Choose a reason for hiding this comment

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

this should be consistent with std.

As it's written now, vec![42; 5] in std it would create a vec with five 42's, while in heapless it creates a vec with a single 42 with a capacity of 5.

IMO the macro should behave like this:

  • vec![1,2,3]: 3 elements, capacity is inferred.
  • vec![42; 3]: element repeated 3 times, capacity is inferred.

and then invent some extra syntax for specifying capacity explicitly that doesn't conflict with that.

In #369 we had the same issue, we went with format!(256; "foo {}", 42) where 256 is the capacity, but that doesn't work well here...

@Dirbaio
Copy link
Member

Dirbaio commented Jan 1, 2024

in the end i've merged #352 for the "from array" conversion because it was a bit more complete (more tests).

Could you open separate PRs for the two remaining features so they can be reviewed/discussed separately? (the vec! macro, and spare_capacity_mut).

@YuhanLiin
Copy link
Contributor Author

Continued in #437 and #438

@YuhanLiin YuhanLiin closed this Jan 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature: Add Vec::spare_capacity_mut
3 participants