-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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: add try_* methods and a try_vec! macro to make Vec usable in without infallible allocation methods #95051
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
/// # Ok::<(), alloc::collections::TryReserveError>(()) | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the policy for cases where an API depends on two unstable features (e.g., in this case more_fallible_allocation_methods
and allocator_api
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure! I've wondered that myself :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #94770
FYI @Ericson2314 @Xuanwo |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Great job trying to tackle the dedup-without-penality problem! An additional technical I would like to see tried is returning I think the This might seem overkill on this PR, but if folks are willing to give it a try I think it's better to do so sooner rather than later. |
I was worried that using I've tried switching the code to use |
@dpaoliello I think the issues in that thread are mainly worrying about arbitrary code. This is a mere implementation detail in Maybe keep a branch for the old version in case someone disagrees with me, but please do push! I would be very curious to see what you've got :). |
Ok, pushed! It's a trivial change, unless I've misunderstood what you were suggesting... |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This is looking really nice! Really wonderful to see more red appear over time to balance out that green :). |
☔ The latest upstream changes (presumably #87667) made this pull request unmergeable. Please resolve the merge conflicts. |
This comment has been minimized.
This comment has been minimized.
@Ericson2314 @ojeda @m-ou-se Ok, RFC created: rust-lang/rfcs#3271 I tried to think of as many alternatives as possible. I also wrote down the starting of an idea to deal with "function variations" in the Future Possibilities section, but it would require a lot more language design and discussion. |
@m-ou-se I'd like to be able to get these functions merged in to unblock folks that need them: if you're worried about cluttering |
In #89123 I chose a name for that function that doesn't start with |
For the Using the OS kernel example, if pushing to an vec fails in kernel, you may need to take a moment to clean up some garbage/kill some processes and then try again. |
@i509VCB I think the right way to do that is a more "emplace"-type mechanism by which
We can do this either way, but the benefits are a lot easier to understand with |
The `vec!` macro has 3 rules, but two are not usable under `no_global_oom_handling` builds of the standard library (even with a zero size): ```rust let _ = vec![42]; // Error: requires `exchange_malloc` lang_item. let _ = vec![42; 0]; // Error: cannot find function `from_elem`. ``` Thus those two rules should not be available to begin with. The remaining one, with an empty matcher, is just a shorthand for `new()` and may not make as much sense to have alone, since the idea behind `vec!` is to enable `Vec`s to be defined with the same syntax as array expressions. Furthermore, the documentation can be confusing since it shows the other rules. Thus perhaps it is better and simpler to disable `vec!` entirely under `no_global_oom_handling` environments, and let users call `new()` instead: ```rust let _: Vec<i32> = vec![]; let _: Vec<i32> = Vec::new(); ``` Notwithstanding this, a `try_vec!` macro would be useful, such as the one introduced in rust-lang/rust#95051. If the shorthand for `new()` is deemed worth keeping on its own, then it may be interesting to have a separate `vec!` macro with a single rule and different, simpler documentation. Signed-off-by: Miguel Ojeda <[email protected]>
…Simulacrum `alloc`: make `vec!` unavailable under `no_global_oom_handling` `alloc`: make `vec!` unavailable under `no_global_oom_handling` The `vec!` macro has 3 rules, but two are not usable under `no_global_oom_handling` builds of the standard library (even with a zero size): ```rust let _ = vec![42]; // Error: requires `exchange_malloc` lang_item. let _ = vec![42; 0]; // Error: cannot find function `from_elem`. ``` Thus those two rules should not be available to begin with. The remaining one, with an empty matcher, is just a shorthand for `new()` and may not make as much sense to have alone, since the idea behind `vec!` is to enable `Vec`s to be defined with the same syntax as array expressions. Furthermore, the documentation can be confusing since it shows the other rules. Thus perhaps it is better and simpler to disable `vec!` entirely under `no_global_oom_handling` environments, and let users call `new()` instead: ```rust let _: Vec<i32> = vec![]; let _: Vec<i32> = Vec::new(); ``` Notwithstanding this, a `try_vec!` macro would be useful, such as the one introduced in rust-lang/rust#95051. If the shorthand for `new()` is deemed worth keeping on its own, then it may be interesting to have a separate `vec!` macro with a single rule and different, simpler documentation. Signed-off-by: Miguel Ojeda <[email protected]>
ping from triage: FYI: when a PR is ready for review, send a message containing @rustbot author |
…hout infallible allocation methods As a part of the work for rust-lang#86942 the `no_global_oom_handling` cfg was added in rust-lang#84266, however enabling that cfg makes it difficult to use `Vec`: the `vec!` macro is missing and there is no way to insert or push new elements, nor to create a `Vec` from an iterator (without resorting to `unsafe` APIs to manually expand and write to the underlying buffer). This change adds `try_` equivalent methods for all methods in `Vec` that are disabled by `no_global_oom_handling` as well as a `try_vec!` as the equivalent of `vec!`. Performance and implementation notes: A goal of this change was to make sure to NOT regress the performance of the existing infallible methods - a naive approach would be to move the actual implementation into the fallible method, then call it from the infallible method and `unwrap()`, but this would add extra compare+branch instructions into the infallible methods. It would also be possible to simply duplicate the code for the fallible version - I did opt for this in a few cases, but where the code was larger and more complex this would lead to a maintenance nightmare. Instead, I moved the implementation into an `*_impl` method that was then specialized based on a new `VecError` trait and returned `Result<_, VecError>`, this trait also provided a pair of methods for raising errors. Never (`!`) was used as the infallible version of this trait (and always panics) and `TryReserveError` as the fallible version (and returns the correct error object). All these `VecError` method were marked with `#[inline]`, so after inlining the compiler could see for the infallible version always returns `Ok()` on success (and panics on error) thus the `?` operator or `unwrap()` call was a no-op, and so the same non-branching instructions as before are generated. I also added `try_from_iter` and `try_expand` methods for completeness, even though their infallible equivalents are trait implementations.
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
@rustbot label +T-libs-api -T-libs |
@rustbot ready |
While most of the APIs at least appear somewhat reasonable (but not ideal or low-abstraction-orthogonal-building-blocks) these two seem more dubious than the others: pub fn try_from_iter<I: IntoIterator<Item = T>>(iter: I) -> Result<Vec<T>, TryReserveError>;
pub fn try_extend<I: IntoIterator<Item = T>>(&mut self, iter: I, ) -> Result<(), TryReserveError>; They basically implement inherent, fallible versions of the Fallible iterator-absorbing methods may need separate implementations that allocate ahead of time (at the risk of allocating a wee bit too much) and hand you back the pieces when stuff breaks. Removing those would also shrink the diff. |
If it makes this more acceptable to @m-ou-se and the libs team, I am not opposed to splitting those two out to be dealt with later. @dpaoliello what do you think? |
☔ The latest upstream changes (presumably #104818) made this pull request unmergeable. Please resolve the merge conflicts. |
Closing this for now. |
mod spec_extend; | ||
|
||
pub(crate) trait VecError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@workingjubilee this is mechanism that allows the eager bail out (just like today) or error throwing.
As a part of the work for #86942 the
no_global_oom_handling
cfg was added in #84266, however enabling that cfg makes it difficult to useVec
: thevec!
macro is missing and there is no way to insert or push new elements, nor to create aVec
from an iterator (without resorting tounsafe
APIs to manually expand and write to the underlying buffer).This change adds
try_
equivalent methods for all methods inVec
that are disabled byno_global_oom_handling
as well as atry_vec!
as the equivalent ofvec!
.Performance and implementation notes: A goal of this change was to make sure to NOT regress the performance of the existing infallible methods - a naive approach would be to move the actual implementation into the fallible method, then call it from the infallible method and
unwrap()
, but this would add extra compare+branch instructions into the infallible methods. It would also be possible to simply duplicate the code for the fallible version - I did opt for this in a few cases, but where the code was larger and more complex this would lead to a maintenance nightmare. Instead, I moved the implementation into an*_impl
method that was then specialized based on a newVecError
trait and returnedResult<_, VecError>
, this trait also provided a pair of methods for raising errors. Never (!
) was used as the infallible version of this trait (and always panics) andTryReserveError
as the fallible version (and returns the correct error object). All theseVecError
method were marked with#[inline]
, so after inlining the compiler could see for the infallible version always returnsOk()
on success (and panics on error) thus the?
operator orunwrap()
call was a no-op, and so the same non-branching instructions as before are generated.I also added
try_from_iter
andtry_expand
methods for completeness, even though their infallible equivalents are trait implementations.List of Vec APIs added:
Other helper APIs added, than can be made
pub(crate)
if folks prefer: