Skip to content

Tracking Issue for Vec::push_within_capacity #100486

Open

Description

@the8472

View all comments

Feature gate: #![feature(vec_push_within_capacity)]

This is a tracking issue for Vec::push_within_capacity

It enables pushing into a Vec if there is any capacity left and otherwise returns the value. I.e. it avoids implicit resizing. This can be useful when one wants to explicitly control it (e.g. via try_reserve) or uses a Vec in an unsafe manner where moving the elements would be a problem.

Public API

// alloc::Vec

impl Vec<T, A> {
    pub fn push_within_capacity(&mut self, value: T) -> Result<&mut T, T>;
}

Steps / History

Unresolved Questions

Footnotes

  1. https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html ↩

Activity

  1. added
    T-libs-api[DEPRECATED; DO NOT USE]
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Aug 13, 2022
  2. em-tg commented on Mar 19, 2023

    @em-tg

    Would it be possible for push_within_capacity to take self by shared reference? If the backing store is never re-allocated then calling this wouldn't invalidate any references to the Vec's contents, I'd think.

  3. the8472 commented on Mar 19, 2023

    @the8472
    MemberAuthor

    It still needs to bump the length field.

  4. em-tg commented on Mar 19, 2023

    @em-tg

    Wouldn't wrapping the length in UnsafeCell work for that? The public api only exposes the len() getter.

  5. em-tg commented on Mar 20, 2023

    @em-tg

    Ah wait I think I see the issue. You'd lose Sync by doing that. Sorry, still pretty new to Rust and just thought I'd ask!

  6. tiby312 commented on Jun 19, 2023

    @tiby312

    I think this is a great feature. I often find myself just assuming my buffer reserving code is working since it is a hard bug to catch when it's not working given push automatically reserves.

  7. krtab commented on Oct 27, 2023

    @krtab
    Contributor

    Hi!

    I think this could enter its FCP:

  8. kornelski commented on Feb 11, 2024

    @kornelski
    Contributor

    I find it very useful, and have similar helpers in my codebases. It generates much leaner code than the usual push when the optimizer can't be convinced that the capacity is sufficient (e.g. when it's calculated in a non-trivial way, or the vec-appending code isn't all inlined). It has a useful side effect of verifying that a sufficient capacity has been precalculated, and there aren't unexpected reallocations.

    However, just push is not enough. I'm missing similar functionality for extend_from_slice — _within_capacity.

  9. elichai commented on Feb 11, 2024

    @elichai
    Contributor

    I hope this isn't completely useful,
    But is there some kind of mechanism we can use to allow all these try_ functionality without adding dozens of try_ in all collections, could being generic over the effect of try allow something like this?

  10. Darksonn commented on May 1, 2024

    @Darksonn
    Member

    How about insert_within_capacity? It's very non-trivial to reimplement insert without an allocation codepath.

  11. the8472 commented on May 1, 2024

    @the8472
    MemberAuthor

    Sounds interesting, though a bit niche (just like this method). If you have a use-case you should file an ACP for it.
    Ditto @kornelski

    If you several a bunch of methods like this in mind then we could perhaps bundle them to see if there are some overarching things to consider.

  12. zeroflaw commented on May 9, 2024

    @zeroflaw

    Now that it's possible to do a try_reserve, I find myself using these extension methods a lot more often. push_within_capacity here gives us an escape hatch to do an unchecked_push.
    I included an example of insert_within_capacity and try_insert_within_capacity

    // ===== trait Ext =====
    
    pub trait Ext<T> {
        /// Appends an element to the back of a collection without checking
        /// if the collection has enough capacity.
        ///
        /// # Safety
        /// The user must ensure that `self.len() < self.capacity()`.
        ///
        unsafe fn unchecked_push(&mut self, value: T);
    
        /// Removes the last element from a vector without checking
        /// if the collection is empty.
        ///
        /// # Safety
        /// The user must ensure that `self.len() != 0`.
        ///
        unsafe fn unchecked_pop(&mut self) -> T;
    
        /// Inserts an element at position index within the vector, 
        /// without checking if the collection has enough capacity, 
        /// or the position index is out of bounds.
        /// all elements after the position index are shifted to the right. 
        /// 
        /// # Safety
        /// The user must ensure that `index <= self.len()` and `self.len() < self.capacity()`
        ///
        unsafe fn unchecked_insert(&mut self, index: usize, value: T);
    
    
        /// Inserts an element at position index within the vector, 
        /// if there is sufficient spare capacity, otherwise an error is returned with the element.
        /// 
        /// # Errors
        /// if insufficient capacity, an error is returned with the element
        /// 
        /// # Panics
        /// Panics if index > len.
        /// 
        fn insert_within_capacity(&mut self, index: usize, element: T) -> Result<(), T>;
    
        /// Inserts an element at position index within the vector, 
        /// if there is sufficient spare capacity, and index is within bounds,
        /// otherwise an error is returned with the element.
        /// 
        /// # Errors
        /// if insufficient capacity, or the index is out of bounds, an error is returned with the element
        /// 
        fn try_insert_within_capacity(&mut self, index: usize, element: T) -> Result<(), T>;
    }
    
    // ===== impl Vec =====
    
    impl<T> Ext<T> for Vec<T> {
        unsafe fn unchecked_push(&mut self, value: T) {
            std::hint::assert_unchecked(self.len() < self.capacity());
            self.push_within_capacity(value).unwrap_unchecked();
        }
    
        unsafe fn unchecked_pop(&mut self) -> T {
            std::hint::assert_unchecked(!self.is_empty());
            self.pop().unwrap_unchecked()
        }
        
        unsafe fn unchecked_insert(&mut self, index: usize, element: T) {
            std::hint::assert_unchecked(index <= self.len());
            std::hint::assert_unchecked(self.len() < self.capacity());
            self.insert(index, element);
        }
        
        fn insert_within_capacity(&mut self, index: usize, element: T) -> Result<(), T> {
            if self.len() == self.capacity() {
                return Err(element);
            }
            unsafe { std::hint::assert_unchecked(self.len() < self.capacity()) };
            self.insert(index, element);
            Ok(())
        }
        
        fn try_insert_within_capacity(&mut self, index: usize, element: T) -> Result<(), T> {
            if self.len() == self.capacity() || index > self.len() {
                return Err(element);
            }
            unsafe { self.unchecked_insert(index, element); }
            Ok(())
        }
    }
  13. kornelski commented on May 9, 2024

    @kornelski
    Contributor

    There are two ways to implement such functionality, and I'm not sure which way to propose:

    1. Add more methods on Vec with a _within_capacity version. I think this would work well, but I've got a lot of pushback about adding try_ versions of methods. Rust doesn't have a feature like Swift's function naming/overloading to keep all of these functionality tweaks elegantly together.

    2. A reference type like FixedCapacityVecView<'_> that imitates interface of Vec, but without reallocation. This seems like a big addition, especially if it will duplicate most of Vec's interface, but most users will probably only need push and extend.

  14. GoldsteinE commented on Jun 5, 2024

    @GoldsteinE
    Contributor

    This FixedCapacityVecView<'_> is kinda similar to std::io::BorrowedBuf<'_> in both its API and idea.

  15. 11 remaining items

  16. added 2 commits that reference this issue on Nov 5, 2025
  17. added a commit that references this issue on Nov 6, 2025
  18. added 3 commits that reference this issue on Nov 7, 2025
  19. WaffleLapkin commented on Nov 13, 2025

    @WaffleLapkin
    Member

    #148534 changed the signature to return a reference to the pushed element, just like push_mut & co.

  20. added a commit that references this issue on Nov 30, 2025
  21. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions