Explorar el Código

Bump bumpalo from 3.10.0 to 3.12.0 in /zeroidc (#1857)

* Bump bumpalo from 3.10.0 to 3.12.0 in /zeroidc

Bumps [bumpalo](https://github.com/fitzgen/bumpalo) from 3.10.0 to 3.12.0.
- [Release notes](https://github.com/fitzgen/bumpalo/releases)
- [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fitzgen/bumpalo/compare/3.10.0...3.12.0)

---
updated-dependencies:
- dependency-name: bumpalo
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>

* vendor bumpalo update to fix dependabot

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grant Limberg <[email protected]>
dependabot[bot] hace 2 años
padre
commit
6aea546d6f

+ 2 - 2
zeroidc/Cargo.lock

@@ -57,9 +57,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.10.0"
+version = "3.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
+checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
 
 [[package]]
 name = "bytes"

+ 1 - 1
zeroidc/vendor/bumpalo/.cargo-checksum.json

@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"506ba9e82e7d0354739d7ea9a051fd8e77e0a2842b25063d97d72c84f73b5620","Cargo.toml":"ef3049ea38d9acf8d7a1b3a72fb559548232e5e4562fde190e29530d1caff9f2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"65f94e99ddaf4f5d1782a6dae23f35d4293a9a01444a13135a6887017d353cee","README.md":"1b8b798489668a6053520f90534a795ba73e33928022d10d364dfd8f8df7b5a3","src/alloc.rs":"ab0f23fa11c26efdd8f0596ebdf0e3faa75d097881fb59639b0fb23340c106bc","src/boxed.rs":"8a54f74527691012a1416e7e65ae1dc9f9f4711afd252704a7222b04cce60194","src/collections/collect_in.rs":"0588a4ff3967a4323abb4218bbd615af4b123639ab4fae9130c6590c258b3d15","src/collections/mod.rs":"d58dc46eb4f9fcdde574f09bc5b8646f53e42d49c169561d98e0c23e5b36848a","src/collections/raw_vec.rs":"a4eebed2bd81a039e4f120f1e4230585b8f3bbb42c27f79af28d0c05ee7b6866","src/collections/str/lossy.rs":"c5d62b16e01071e2a574ae41ef6693ad12f1e6c786c5d38f7a13ebd6cb23c088","src/collections/str/mod.rs":"d82a8bd417fbf52a589d89a16ea2a0ac4f6ac920c3976ab1f5b6ac0c8493c4f2","src/collections/string.rs":"7719005ca29d6031c7bf06ebcfd94ea27891da1aadd797ca45aadff598d2b7ee","src/collections/vec.rs":"7a757c495e4688a8db8482105206338e86df0ea2774765382091a36602cf3638","src/lib.rs":"72d2f350246d7365b893f40bc106c6bdd6bb2dbb1fc836d6e04f6d76ca2c282f"},"package":"37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"}
+{"files":{"CHANGELOG.md":"8b5a7a49c720ba2678c07184f50b3608e2165fbf6704da494fba23c864e691e0","Cargo.toml":"8d5fd21d2b3ed1d7149e864d43f843fd469ccdcd9893ac3c2bef8518294a61dd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"65f94e99ddaf4f5d1782a6dae23f35d4293a9a01444a13135a6887017d353cee","README.md":"00c9224790248ec71d1505615429699fd685b0290a0c2b6d7c0df0214e7f80eb","src/alloc.rs":"ab0f23fa11c26efdd8f0596ebdf0e3faa75d097881fb59639b0fb23340c106bc","src/boxed.rs":"5fc935f8e1a7bc1b8f6a39b2bcc4355a2be4743f2308fe3ffd557455a3a27cb2","src/collections/collect_in.rs":"0588a4ff3967a4323abb4218bbd615af4b123639ab4fae9130c6590c258b3d15","src/collections/mod.rs":"d58dc46eb4f9fcdde574f09bc5b8646f53e42d49c169561d98e0c23e5b36848a","src/collections/raw_vec.rs":"8829cc9a693fde38aa93e47a7bbbc2dac247620d07f60519f2e6cb44f5494bc5","src/collections/str/lossy.rs":"c5d62b16e01071e2a574ae41ef6693ad12f1e6c786c5d38f7a13ebd6cb23c088","src/collections/str/mod.rs":"d82a8bd417fbf52a589d89a16ea2a0ac4f6ac920c3976ab1f5b6ac0c8493c4f2","src/collections/string.rs":"388d39b999788baf5c14ccc3f5cb57da728060ea3295ddfc28f0f2e1ca5858ec","src/collections/vec.rs":"2eaf52e085e6d04767e97b224e82688dd0debd231c6536d6034f431376aa8bf0","src/lib.rs":"9eb2bdb8359b368a6f3091a66b3a5eb1216672ec1605cb18d5da28292c381cb9"},"package":"0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"}

+ 49 - 0
zeroidc/vendor/bumpalo/CHANGELOG.md

@@ -28,6 +28,55 @@ Released YYYY-MM-DD.
 
 --------------------------------------------------------------------------------
 
+## 3.12.0
+
+Released 2023-01-17.
+
+### Added
+
+* Added the `bumpalo::boxed::Box::bump` and `bumpalo::collections::String::bump`
+  getters to get the underlying `Bump` that a string or box was allocated into.
+
+### Changed
+
+* Some uses of `Box` that MIRI did not previously consider as UB are now
+  reported as UB, and `bumpalo`'s internals have been adjusted to avoid the new
+  UB.
+
+--------------------------------------------------------------------------------
+
+## 3.11.1
+
+Released 2022-10-18.
+
+### Security
+
+* Fixed a bug where when `std::vec::IntoIter` was ported to
+  `bumpalo::collections::vec::IntoIter`, it didn't get its underlying `Bump`'s
+  lifetime threaded through. This meant that `rustc` was not checking the
+  borrows for `bumpalo::collections::IntoIter` and this could result in
+  use-after-free bugs.
+
+--------------------------------------------------------------------------------
+
+## 3.11.0
+
+Released 2022-08-17.
+
+### Added
+
+* Added support for per-`Bump` allocation limits. These are enforced only in the
+  slow path when allocating new chunks in the `Bump`, not in the bump allocation
+  hot path, and therefore impose near zero overhead.
+* Added the `bumpalo::boxed::Box::into_inner` method.
+
+### Changed
+
+* Updated to Rust 2021 edition.
+* The minimum supported Rust version (MSRV) is now 1.56.0.
+
+--------------------------------------------------------------------------------
+
 ## 3.10.0
 
 Released 2022-06-01.

+ 5 - 5
zeroidc/vendor/bumpalo/Cargo.toml

@@ -10,9 +10,9 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
 name = "bumpalo"
-version = "3.10.0"
+version = "3.12.0"
 authors = ["Nick Fitzgerald <[email protected]>"]
 exclude = [
     "/.github/*",
@@ -51,13 +51,13 @@ harness = false
 required-features = ["collections"]
 
 [dev-dependencies.criterion]
-version = "0.3.0"
+version = "0.3.6"
 
 [dev-dependencies.quickcheck]
-version = "0.9.0"
+version = "1.0.3"
 
 [dev-dependencies.rand]
-version = "0.7"
+version = "0.8.5"
 
 [features]
 allocator_api = []

+ 11 - 9
zeroidc/vendor/bumpalo/README.md

@@ -147,7 +147,8 @@ in its space itself.
     // Drop our `Box<CountDrops>`.
     drop(c);
 
-    // Its `Drop` implementation was run, and so `NUM_DROPS` has been incremented.
+    // Its `Drop` implementation was run, and so `NUM_DROPS` has been
+    // incremented.
     assert_eq!(NUM_DROPPED.load(Ordering::SeqCst), 1);
 }
 ```
@@ -158,11 +159,11 @@ Bumpalo is a `no_std` crate. It depends only on the `alloc` and `core` crates.
 
 ### Thread support
 
-The `Bump` is `!Sync`, which makes it hard to use in certain situations around threads ‒ for
-example in `rayon`.
+The `Bump` is `!Sync`, which makes it hard to use in certain situations around
+threads ‒ for example in `rayon`.
 
-The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a pool of `Bump`
-allocators for use in such situations.
+The [`bumpalo-herd`](https://crates.io/crates/bumpalo-herd) crate provides a
+pool of `Bump` allocators for use in such situations.
 
 ### Nightly Rust `allocator_api` Support
 
@@ -181,7 +182,8 @@ First, enable the `allocator_api` feature in your `Cargo.toml`:
 bumpalo = { version = "3.9", features = ["allocator_api"] }
 ```
 
-Next, enable the `allocator_api` nightly Rust feature in your `src/lib.rs` or `src/main.rs`:
+Next, enable the `allocator_api` nightly Rust feature in your `src/lib.rs` or
+`src/main.rs`:
 
 ```rust,ignore
 #![feature(allocator_api)]
@@ -207,8 +209,8 @@ v.push(2);
 
 #### Minimum Supported Rust Version (MSRV)
 
-This crate is guaranteed to compile on stable Rust **1.54** and up. It might
+This crate is guaranteed to compile on stable Rust **1.56** and up. It might
 compile with older versions but that may change in any new patch release.
 
-We reserve the right to increment the MSRV on minor releases, however we will strive
-to only do it deliberately and for good reasons.
+We reserve the right to increment the MSRV on minor releases, however we will
+strive to only do it deliberately and for good reasons.

+ 25 - 8
zeroidc/vendor/bumpalo/src/boxed.rs

@@ -130,7 +130,7 @@ use {
             future::Future,
             hash::{Hash, Hasher},
             iter::FusedIterator,
-            mem,
+            mem::ManuallyDrop,
             ops::{Deref, DerefMut},
             pin::Pin,
             task::{Context, Poll},
@@ -171,6 +171,24 @@ impl<'a, T> Box<'a, T> {
     pub fn pin_in(x: T, a: &'a Bump) -> Pin<Box<'a, T>> {
         Box(a.alloc(x)).into()
     }
+
+    /// Consumes the `Box`, returning the wrapped value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bumpalo::{Bump, boxed::Box};
+    ///
+    /// let b = Bump::new();
+    ///
+    /// let hello = Box::new_in("hello".to_owned(), &b);
+    /// assert_eq!(Box::into_inner(hello), "hello");
+    /// ```
+    pub fn into_inner(b: Box<'a, T>) -> T {
+        // `Box::into_raw` returns a pointer that is properly aligned and non-null.
+        // The underlying `Bump` only frees the memory, but won't call the destructor.
+        unsafe { core::ptr::read(Box::into_raw(b)) }
+    }
 }
 
 impl<'a, T: ?Sized> Box<'a, T> {
@@ -262,9 +280,8 @@ impl<'a, T: ?Sized> Box<'a, T> {
     /// ```
     #[inline]
     pub fn into_raw(b: Box<'a, T>) -> *mut T {
-        let ptr = b.0 as *mut T;
-        mem::forget(b);
-        ptr
+        let mut b = ManuallyDrop::new(b);
+        b.deref_mut().0 as *mut T
     }
 
     /// Consumes and leaks the `Box`, returning a mutable reference,
@@ -644,9 +661,9 @@ impl<'a, F: ?Sized + Future + Unpin> Future for Box<'a, F> {
 
 /// This impl replaces unsize coercion.
 impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
-    fn from(mut arr: Box<'a, [T; N]>) -> Box<'a, [T]> {
+    fn from(arr: Box<'a, [T; N]>) -> Box<'a, [T]> {
+        let mut arr = ManuallyDrop::new(arr);
         let ptr = core::ptr::slice_from_raw_parts_mut(arr.as_mut_ptr(), N);
-        mem::forget(arr);
         unsafe { Box::from_raw(ptr) }
     }
 }
@@ -654,10 +671,10 @@ impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
 /// This impl replaces unsize coercion.
 impl<'a, T, const N: usize> TryFrom<Box<'a, [T]>> for Box<'a, [T; N]> {
     type Error = Box<'a, [T]>;
-    fn try_from(mut slice: Box<'a, [T]>) -> Result<Box<'a, [T; N]>, Box<'a, [T]>> {
+    fn try_from(slice: Box<'a, [T]>) -> Result<Box<'a, [T; N]>, Box<'a, [T]>> {
         if slice.len() == N {
+            let mut slice = ManuallyDrop::new(slice);
             let ptr = slice.as_mut_ptr() as *mut [T; N];
-            mem::forget(slice);
             Ok(unsafe { Box::from_raw(ptr) })
         } else {
             Err(slice)

+ 3 - 8
zeroidc/vendor/bumpalo/src/collections/raw_vec.rs

@@ -60,15 +60,10 @@ impl<'a, T> RawVec<'a, T> {
     /// Like `new` but parameterized over the choice of allocator for
     /// the returned RawVec.
     pub fn new_in(a: &'a Bump) -> Self {
-        // !0 is usize::MAX. This branch should be stripped at compile time.
-        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`
-        //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
-
-        // Unique::empty() doubles as "unallocated" and "zero-sized allocation"
+        // `cap: 0` means "unallocated". zero-sized types are ignored.
         RawVec {
-            ptr: unsafe { NonNull::new_unchecked(mem::align_of::<T>() as *mut T) },
-            // FIXME(mark-i-m): use `cap` when ifs are allowed in const
-            cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
+            ptr: NonNull::dangling(),
+            cap: 0,
             a,
         }
     }

+ 27 - 7
zeroidc/vendor/bumpalo/src/collections/string.rs

@@ -228,9 +228,9 @@ macro_rules! format {
 ///
 /// let b = Bump::new();
 ///
-/// let story = String::from_str_in("Once upon a time...", &b);
+/// let mut story = String::from_str_in("Once upon a time...", &b);
 ///
-/// let ptr = story.as_ptr();
+/// let ptr = story.as_mut_ptr();
 /// let len = story.len();
 /// let capacity = story.capacity();
 ///
@@ -243,7 +243,7 @@ macro_rules! format {
 /// // We can re-build a String out of ptr, len, and capacity. This is all
 /// // unsafe because we are responsible for making sure the components are
 /// // valid:
-/// let s = unsafe { String::from_raw_parts_in(ptr as *mut _, len, capacity, &b) } ;
+/// let s = unsafe { String::from_raw_parts_in(ptr, len, capacity, &b) } ;
 ///
 /// assert_eq!(String::from_str_in("Once upon a time...", &b), s);
 /// ```
@@ -737,14 +737,14 @@ impl<'bump> String<'bump> {
     /// let b = Bump::new();
     ///
     /// unsafe {
-    ///     let s = String::from_str_in("hello", &b);
-    ///     let ptr = s.as_ptr();
+    ///     let mut s = String::from_str_in("hello", &b);
+    ///     let ptr = s.as_mut_ptr();
     ///     let len = s.len();
     ///     let capacity = s.capacity();
     ///
     ///     mem::forget(s);
     ///
-    ///     let s = String::from_raw_parts_in(ptr as *mut _, len, capacity, &b);
+    ///     let s = String::from_raw_parts_in(ptr, len, capacity, &b);
     ///
     ///     assert_eq!(s, "hello");
     /// }
@@ -798,6 +798,24 @@ impl<'bump> String<'bump> {
         String { vec: bytes }
     }
 
+    /// Returns a shared reference to the allocator backing this `String`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bumpalo::{Bump, collections::String};
+    ///
+    /// // uses the same allocator as the provided `String`
+    /// fn copy_string<'bump>(s: &String<'bump>) -> &'bump str {
+    ///     s.bump().alloc_str(s.as_str())
+    /// }
+    /// ```
+    #[inline]
+    #[must_use]
+    pub fn bump(&self) -> &'bump Bump {
+        self.vec.bump()
+    }
+
     /// Converts a `String` into a byte vector.
     ///
     /// This consumes the `String`, so we do not need to copy its contents.
@@ -1550,7 +1568,7 @@ impl<'bump> String<'bump> {
     /// assert_eq!(s, "β is beta");
     ///
     /// // A full range clears the string
-    /// s.drain(..);
+    /// drop(s.drain(..));
     /// assert_eq!(s, "");
     /// ```
     pub fn drain<'a, R>(&'a mut self, range: R) -> Drain<'a, 'bump>
@@ -2098,6 +2116,8 @@ impl<'a, 'bump> Drop for Drain<'a, 'bump> {
     }
 }
 
+// TODO: implement `AsRef<str/[u8]>` and `as_str`
+
 impl<'a, 'bump> Iterator for Drain<'a, 'bump> {
     type Item = char;
 

+ 138 - 18
zeroidc/vendor/bumpalo/src/collections/vec.rs

@@ -675,6 +675,26 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
         }
     }
 
+    /// Returns a shared reference to the allocator backing this `Vec`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bumpalo::{Bump, collections::Vec};
+    ///
+    /// // uses the same allocator as the provided `Vec`
+    /// fn add_strings<'bump>(vec: &mut Vec<'bump, &'bump str>) {
+    ///     for string in ["foo", "bar", "baz"] {
+    ///         vec.push(vec.bump().alloc_str(string));
+    ///     }
+    /// }
+    /// ```
+    #[inline]
+    #[must_use]
+    pub fn bump(&self) -> &'bump Bump {
+        self.buf.bump()
+    }
+
     /// Returns the number of elements the vector can hold without
     /// reallocating.
     ///
@@ -977,6 +997,91 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
         self
     }
 
+    /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
+    /// valid for zero sized reads if the vector didn't allocate.
+    ///
+    /// The caller must ensure that the vector outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    /// Modifying the vector may cause its buffer to be reallocated,
+    /// which would also make any pointers to it invalid.
+    ///
+    /// The caller must also ensure that the memory the pointer (non-transitively) points to
+    /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+    /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bumpalo::{Bump, collections::Vec};
+    ///
+    /// let bump = Bump::new();
+    ///
+    /// let x = bumpalo::vec![in &bump; 1, 2, 4];
+    /// let x_ptr = x.as_ptr();
+    ///
+    /// unsafe {
+    ///     for i in 0..x.len() {
+    ///         assert_eq!(*x_ptr.add(i), 1 << i);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// [`as_mut_ptr`]: Vec::as_mut_ptr
+    #[inline]
+    pub fn as_ptr(&self) -> *const T {
+        // We shadow the slice method of the same name to avoid going through
+        // `deref`, which creates an intermediate reference.
+        let ptr = self.buf.ptr();
+        unsafe {
+            if ptr.is_null() {
+                core::hint::unreachable_unchecked();
+            }
+        }
+        ptr
+    }
+
+    /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
+    /// raw pointer valid for zero sized reads if the vector didn't allocate.
+    ///
+    /// The caller must ensure that the vector outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    /// Modifying the vector may cause its buffer to be reallocated,
+    /// which would also make any pointers to it invalid.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bumpalo::{Bump, collections::Vec};
+    ///
+    /// let bump = Bump::new();
+    ///
+    /// // Allocate vector big enough for 4 elements.
+    /// let size = 4;
+    /// let mut x: Vec<i32> = Vec::with_capacity_in(size, &bump);
+    /// let x_ptr = x.as_mut_ptr();
+    ///
+    /// // Initialize elements via raw pointer writes, then set length.
+    /// unsafe {
+    ///     for i in 0..size {
+    ///         x_ptr.add(i).write(i as i32);
+    ///     }
+    ///     x.set_len(size);
+    /// }
+    /// assert_eq!(&*x, &[0, 1, 2, 3]);
+    /// ```
+    #[inline]
+    pub fn as_mut_ptr(&mut self) -> *mut T {
+        // We shadow the slice method of the same name to avoid going through
+        // `deref_mut`, which creates an intermediate reference.
+        let ptr = self.buf.ptr();
+        unsafe {
+            if ptr.is_null() {
+                core::hint::unreachable_unchecked();
+            }
+        }
+        ptr
+    }
+
     /// Sets the length of a vector.
     ///
     /// This will explicitly set the size of the vector, without actually
@@ -1026,19 +1131,27 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
     /// ```
     ///
     /// In this example, the vector gets expanded from zero to four items
-    /// without any memory allocations occurring, resulting in vector
-    /// values of unallocated memory:
+    /// but we directly initialize uninitialized memory:
     ///
+    // TODO: rely upon `spare_capacity_mut`
     /// ```
     /// use bumpalo::{Bump, collections::Vec};
     ///
+    /// let len = 4;
     /// let b = Bump::new();
     ///
-    /// let mut vec: Vec<char> = Vec::new_in(&b);
+    /// let mut vec: Vec<u8> = Vec::with_capacity_in(len, &b);
+    ///
+    /// for i in 0..len {
+    ///     // SAFETY: we initialize memory via `pointer::write`
+    ///     unsafe { vec.as_mut_ptr().add(i).write(b'a') }
+    /// }
     ///
     /// unsafe {
-    ///     vec.set_len(4);
+    ///     vec.set_len(len);
     /// }
+    ///
+    /// assert_eq!(b"aaaa", &*vec);
     /// ```
     #[inline]
     pub unsafe fn set_len(&mut self, new_len: usize) {
@@ -1343,7 +1456,7 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
         } else {
             unsafe {
                 self.len -= 1;
-                Some(ptr::read(self.get_unchecked(self.len())))
+                Some(ptr::read(self.as_ptr().add(self.len())))
             }
         }
     }
@@ -1381,7 +1494,7 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
         let count = (*other).len();
         self.reserve(count);
         let len = self.len();
-        ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count);
+        ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count);
         self.len += count;
     }
 
@@ -1848,7 +1961,7 @@ impl<'bump, T: 'bump> ops::DerefMut for Vec<'bump, T> {
 
 impl<'bump, T: 'bump> IntoIterator for Vec<'bump, T> {
     type Item = T;
-    type IntoIter = IntoIter<T>;
+    type IntoIter = IntoIter<'bump, T>;
 
     /// Creates a consuming iterator, that is, one that moves each value out of
     /// the vector (from start to end). The vector cannot be used after calling
@@ -1868,7 +1981,7 @@ impl<'bump, T: 'bump> IntoIterator for Vec<'bump, T> {
     /// }
     /// ```
     #[inline]
-    fn into_iter(mut self) -> IntoIter<T> {
+    fn into_iter(mut self) -> IntoIter<'bump, T> {
         unsafe {
             let begin = self.as_mut_ptr();
             // assume(!begin.is_null());
@@ -2129,19 +2242,19 @@ impl<'bump, T> Drop for Vec<'bump, T> {
 /// (provided by the [`IntoIterator`] trait).
 ///
 /// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
-pub struct IntoIter<T> {
-    phantom: PhantomData<T>,
+pub struct IntoIter<'bump, T> {
+    phantom: PhantomData<&'bump [T]>,
     ptr: *const T,
     end: *const T,
 }
 
-impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
+impl<'bump, T: fmt::Debug> fmt::Debug for IntoIter<'bump, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
     }
 }
 
-impl<'bump, T: 'bump> IntoIter<T> {
+impl<'bump, T: 'bump> IntoIter<'bump, T> {
     /// Returns the remaining items of this iterator as a slice.
     ///
     /// # Examples
@@ -2183,10 +2296,10 @@ impl<'bump, T: 'bump> IntoIter<T> {
     }
 }
 
-unsafe impl<T: Send> Send for IntoIter<T> {}
-unsafe impl<T: Sync> Sync for IntoIter<T> {}
+unsafe impl<'bump, T: Send> Send for IntoIter<'bump, T> {}
+unsafe impl<'bump, T: Sync> Sync for IntoIter<'bump, T> {}
 
-impl<'bump, T: 'bump> Iterator for IntoIter<T> {
+impl<'bump, T: 'bump> Iterator for IntoIter<'bump, T> {
     type Item = T;
 
     #[inline]
@@ -2227,7 +2340,7 @@ impl<'bump, T: 'bump> Iterator for IntoIter<T> {
     }
 }
 
-impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<T> {
+impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<'bump, T> {
     #[inline]
     fn next_back(&mut self) -> Option<T> {
         unsafe {
@@ -2248,9 +2361,16 @@ impl<'bump, T: 'bump> DoubleEndedIterator for IntoIter<T> {
     }
 }
 
-impl<'bump, T: 'bump> ExactSizeIterator for IntoIter<T> {}
+impl<'bump, T: 'bump> ExactSizeIterator for IntoIter<'bump, T> {}
 
-impl<'bump, T: 'bump> FusedIterator for IntoIter<T> {}
+impl<'bump, T: 'bump> FusedIterator for IntoIter<'bump, T> {}
+
+impl<'bump, T> Drop for IntoIter<'bump, T> {
+    fn drop(&mut self) {
+        // drop all remaining elements
+        self.for_each(drop);
+    }
+}
 
 /// A draining iterator for `Vec<'bump, T>`.
 ///

+ 272 - 98
zeroidc/vendor/bumpalo/src/lib.rs

@@ -252,10 +252,46 @@ impl<E: Display> Display for AllocOrInitError<E> {
 /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
 /// [`Ok`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
 /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
+///
+/// ### `Bump` Allocation Limits
+///
+/// `bumpalo` supports setting a limit on the maximum bytes of memory that can
+/// be allocated for use in a particular `Bump` arena. This limit can be set and removed with
+/// [`set_allocation_limit`][Bump::set_allocation_limit].
+/// The allocation limit is only enforced when allocating new backing chunks for
+/// a `Bump`. Updating the allocation limit will not affect existing allocations
+/// or any future allocations within the `Bump`'s current chunk.
+///
+/// #### Example
+///
+/// ```
+/// let bump = bumpalo::Bump::new();
+///
+/// assert_eq!(bump.allocation_limit(), None);
+/// bump.set_allocation_limit(Some(0));
+///
+/// assert!(bump.try_alloc(5).is_err());
+///
+/// bump.set_allocation_limit(Some(6));
+///
+/// assert_eq!(bump.allocation_limit(), Some(6));
+///
+/// bump.set_allocation_limit(None);
+///
+/// assert_eq!(bump.allocation_limit(), None);
+/// ```
+///
+/// #### Warning
+///
+/// Because of backwards compatibility, allocations that fail
+/// due to allocation limits will not present differently than
+/// errors due to resource exhaustion.
+
 #[derive(Debug)]
 pub struct Bump {
     // The current chunk we are bump allocating within.
     current_chunk_footer: Cell<NonNull<ChunkFooter>>,
+    allocation_limit: Cell<Option<usize>>,
 }
 
 #[repr(C)]
@@ -276,6 +312,12 @@ struct ChunkFooter {
 
     // Bump allocation finger that is always in the range `self.data..=self`.
     ptr: Cell<NonNull<u8>>,
+
+    // The bytes allocated in all chunks so far, the canonical empty chunk has
+    // a size of 0 and for all other chunks, `allocated_bytes` will be
+    // the allocated_bytes of the current chunk plus the allocated bytes
+    // of the `prev` chunk.
+    allocated_bytes: usize,
 }
 
 /// A wrapper type for the canonical, statically allocated empty chunk.
@@ -305,6 +347,9 @@ static EMPTY_CHUNK: EmptyChunkFooter = EmptyChunkFooter(ChunkFooter {
     prev: Cell::new(unsafe {
         NonNull::new_unchecked(&EMPTY_CHUNK as *const EmptyChunkFooter as *mut ChunkFooter)
     }),
+
+    // Empty chunks count as 0 allocated bytes in an arena.
+    allocated_bytes: 0,
 });
 
 impl EmptyChunkFooter {
@@ -407,6 +452,15 @@ const FIRST_ALLOCATION_GOAL: usize = 1 << 9;
 // take the alignment into account.
 const DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER: usize = FIRST_ALLOCATION_GOAL - OVERHEAD;
 
+/// The memory size and alignment details for a potential new chunk
+/// allocation.
+#[derive(Debug, Clone, Copy)]
+struct NewChunkMemoryDetails {
+    new_size_without_footer: usize,
+    align: usize,
+    size: usize,
+}
+
 /// Wrapper around `Layout::from_size_align` that adds debug assertions.
 #[inline]
 unsafe fn layout_from_size_align(size: usize, align: usize) -> Layout {
@@ -422,6 +476,12 @@ fn allocation_size_overflow<T>() -> T {
     panic!("requested allocation size overflowed")
 }
 
+// This can be migrated to directly use `usize::abs_diff` when the MSRV
+// reaches `1.60`
+fn abs_diff(a: usize, b: usize) -> usize {
+    usize::max(a, b) - usize::min(a, b)
+}
+
 impl Bump {
     /// Construct a new arena to bump allocate into.
     ///
@@ -471,18 +531,138 @@ impl Bump {
         if capacity == 0 {
             return Ok(Bump {
                 current_chunk_footer: Cell::new(EMPTY_CHUNK.get()),
+                allocation_limit: Cell::new(None),
             });
         }
 
-        let chunk_footer = Self::new_chunk(
-            None,
-            unsafe { layout_from_size_align(capacity, 1) },
-            EMPTY_CHUNK.get(),
-        )
-        .ok_or(AllocErr)?;
+        let layout = unsafe { layout_from_size_align(capacity, 1) };
+
+        let chunk_footer = unsafe {
+            Self::new_chunk(
+                Bump::new_chunk_memory_details(None, layout).ok_or(AllocErr)?,
+                layout,
+                EMPTY_CHUNK.get(),
+            )
+            .ok_or(AllocErr)?
+        };
 
         Ok(Bump {
             current_chunk_footer: Cell::new(chunk_footer),
+            allocation_limit: Cell::new(None),
+        })
+    }
+
+    /// The allocation limit for this arena in bytes.
+    ///
+    /// ## Example
+    ///
+    /// ```
+    /// let bump = bumpalo::Bump::with_capacity(0);
+    ///
+    /// assert_eq!(bump.allocation_limit(), None);
+    ///
+    /// bump.set_allocation_limit(Some(6));
+    ///
+    /// assert_eq!(bump.allocation_limit(), Some(6));
+    ///
+    /// bump.set_allocation_limit(None);
+    ///
+    /// assert_eq!(bump.allocation_limit(), None);
+    /// ```
+    pub fn allocation_limit(&self) -> Option<usize> {
+        self.allocation_limit.get()
+    }
+
+    /// Set the allocation limit in bytes for this arena.
+    ///
+    /// The allocation limit is only enforced when allocating new backing chunks for
+    /// a `Bump`. Updating the allocation limit will not affect existing allocations
+    /// or any future allocations within the `Bump`'s current chunk.
+    ///
+    /// ## Example
+    ///
+    /// ```
+    /// let bump = bumpalo::Bump::with_capacity(0);
+    ///
+    /// bump.set_allocation_limit(Some(0));
+    ///
+    /// assert!(bump.try_alloc(5).is_err());
+    /// ```
+    pub fn set_allocation_limit(&self, limit: Option<usize>) {
+        self.allocation_limit.set(limit)
+    }
+
+    /// How much headroom an arena has before it hits its allocation
+    /// limit.
+    fn allocation_limit_remaining(&self) -> Option<usize> {
+        self.allocation_limit.get().and_then(|allocation_limit| {
+            let allocated_bytes = self.allocated_bytes();
+            if allocated_bytes > allocation_limit {
+                None
+            } else {
+                Some(abs_diff(allocation_limit, allocated_bytes))
+            }
+        })
+    }
+
+    /// Whether a request to allocate a new chunk with a given size for a given
+    /// requested layout will fit under the allocation limit set on a `Bump`.
+    fn chunk_fits_under_limit(
+        allocation_limit_remaining: Option<usize>,
+        new_chunk_memory_details: NewChunkMemoryDetails,
+    ) -> bool {
+        allocation_limit_remaining
+            .map(|allocation_limit_left| {
+                allocation_limit_left >= new_chunk_memory_details.new_size_without_footer
+            })
+            .unwrap_or(true)
+    }
+
+    /// Determine the memory details including final size, alignment and
+    /// final size without footer for a new chunk that would be allocated
+    /// to fulfill an allocation request.
+    fn new_chunk_memory_details(
+        new_size_without_footer: Option<usize>,
+        requested_layout: Layout,
+    ) -> Option<NewChunkMemoryDetails> {
+        let mut new_size_without_footer =
+            new_size_without_footer.unwrap_or(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
+
+        // We want to have CHUNK_ALIGN or better alignment
+        let mut align = CHUNK_ALIGN;
+
+        // If we already know we need to fulfill some request,
+        // make sure we allocate at least enough to satisfy it
+        align = align.max(requested_layout.align());
+        let requested_size =
+            round_up_to(requested_layout.size(), align).unwrap_or_else(allocation_size_overflow);
+        new_size_without_footer = new_size_without_footer.max(requested_size);
+
+        // We want our allocations to play nice with the memory allocator,
+        // and waste as little memory as possible.
+        // For small allocations, this means that the entire allocation
+        // including the chunk footer and mallocs internal overhead is
+        // as close to a power of two as we can go without going over.
+        // For larger allocations, we only need to get close to a page
+        // boundary without going over.
+        if new_size_without_footer < PAGE_STRATEGY_CUTOFF {
+            new_size_without_footer =
+                (new_size_without_footer + OVERHEAD).next_power_of_two() - OVERHEAD;
+        } else {
+            new_size_without_footer =
+                round_up_to(new_size_without_footer + OVERHEAD, 0x1000)? - OVERHEAD;
+        }
+
+        debug_assert_eq!(align % CHUNK_ALIGN, 0);
+        debug_assert_eq!(new_size_without_footer % CHUNK_ALIGN, 0);
+        let size = new_size_without_footer
+            .checked_add(FOOTER_SIZE)
+            .unwrap_or_else(allocation_size_overflow);
+
+        Some(NewChunkMemoryDetails {
+            new_size_without_footer,
+            size,
+            align,
         })
     }
 
@@ -491,74 +671,50 @@ impl Bump {
     /// If given, `layouts` is a tuple of the current chunk size and the
     /// layout of the allocation request that triggered us to fall back to
     /// allocating a new chunk of memory.
-    fn new_chunk(
-        new_size_without_footer: Option<usize>,
+    unsafe fn new_chunk(
+        new_chunk_memory_details: NewChunkMemoryDetails,
         requested_layout: Layout,
         prev: NonNull<ChunkFooter>,
     ) -> Option<NonNull<ChunkFooter>> {
-        unsafe {
-            let mut new_size_without_footer =
-                new_size_without_footer.unwrap_or(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
-
-            // We want to have CHUNK_ALIGN or better alignment
-            let mut align = CHUNK_ALIGN;
-
-            // If we already know we need to fulfill some request,
-            // make sure we allocate at least enough to satisfy it
-            align = align.max(requested_layout.align());
-            let requested_size = round_up_to(requested_layout.size(), align)
-                .unwrap_or_else(allocation_size_overflow);
-            new_size_without_footer = new_size_without_footer.max(requested_size);
-
-            // We want our allocations to play nice with the memory allocator,
-            // and waste as little memory as possible.
-            // For small allocations, this means that the entire allocation
-            // including the chunk footer and mallocs internal overhead is
-            // as close to a power of two as we can go without going over.
-            // For larger allocations, we only need to get close to a page
-            // boundary without going over.
-            if new_size_without_footer < PAGE_STRATEGY_CUTOFF {
-                new_size_without_footer =
-                    (new_size_without_footer + OVERHEAD).next_power_of_two() - OVERHEAD;
-            } else {
-                new_size_without_footer =
-                    round_up_to(new_size_without_footer + OVERHEAD, 0x1000)? - OVERHEAD;
-            }
-
-            debug_assert_eq!(align % CHUNK_ALIGN, 0);
-            debug_assert_eq!(new_size_without_footer % CHUNK_ALIGN, 0);
-            let size = new_size_without_footer
-                .checked_add(FOOTER_SIZE)
-                .unwrap_or_else(allocation_size_overflow);
-            let layout = layout_from_size_align(size, align);
-
-            debug_assert!(size >= requested_layout.size());
-
-            let data = alloc(layout);
-            let data = NonNull::new(data)?;
-
-            // The `ChunkFooter` is at the end of the chunk.
-            let footer_ptr = data.as_ptr().add(new_size_without_footer);
-            debug_assert_eq!((data.as_ptr() as usize) % align, 0);
-            debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0);
-            let footer_ptr = footer_ptr as *mut ChunkFooter;
-
-            // The bump pointer is initialized to the end of the range we will
-            // bump out of.
-            let ptr = Cell::new(NonNull::new_unchecked(footer_ptr as *mut u8));
-
-            ptr::write(
-                footer_ptr,
-                ChunkFooter {
-                    data,
-                    layout,
-                    prev: Cell::new(prev),
-                    ptr,
-                },
-            );
+        let NewChunkMemoryDetails {
+            new_size_without_footer,
+            align,
+            size,
+        } = new_chunk_memory_details;
+
+        let layout = layout_from_size_align(size, align);
+
+        debug_assert!(size >= requested_layout.size());
+
+        let data = alloc(layout);
+        let data = NonNull::new(data)?;
+
+        // The `ChunkFooter` is at the end of the chunk.
+        let footer_ptr = data.as_ptr().add(new_size_without_footer);
+        debug_assert_eq!((data.as_ptr() as usize) % align, 0);
+        debug_assert_eq!(footer_ptr as usize % CHUNK_ALIGN, 0);
+        let footer_ptr = footer_ptr as *mut ChunkFooter;
+
+        // The bump pointer is initialized to the end of the range we will
+        // bump out of.
+        let ptr = Cell::new(NonNull::new_unchecked(footer_ptr as *mut u8));
+
+        // The `allocated_bytes` of a new chunk counts the total size
+        // of the chunks, not how much of the chunks are used.
+        let allocated_bytes = prev.as_ref().allocated_bytes + new_size_without_footer;
+
+        ptr::write(
+            footer_ptr,
+            ChunkFooter {
+                data,
+                layout,
+                prev: Cell::new(prev),
+                ptr,
+                allocated_bytes,
+            },
+        );
 
-            Some(NonNull::new_unchecked(footer_ptr))
-        }
+        Some(NonNull::new_unchecked(footer_ptr))
     }
 
     /// Reset this bump allocator.
@@ -600,7 +756,7 @@ impl Bump {
                 return;
             }
 
-            let cur_chunk = self.current_chunk_footer.get();
+            let mut cur_chunk = self.current_chunk_footer.get();
 
             // Deallocate all chunks except the current one
             let prev_chunk = cur_chunk.as_ref().prev.replace(EMPTY_CHUNK.get());
@@ -609,6 +765,9 @@ impl Bump {
             // Reset the bump finger to the end of the chunk.
             cur_chunk.as_ref().ptr.set(cur_chunk.cast());
 
+            // Reset the allocated size of the chunk.
+            cur_chunk.as_mut().allocated_bytes = cur_chunk.as_ref().layout.size();
+
             debug_assert!(
                 self.current_chunk_footer
                     .get()
@@ -820,7 +979,6 @@ impl Bump {
         let rewind_footer = self.current_chunk_footer.get();
         let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
         let mut inner_result_ptr = NonNull::from(self.alloc_with(f));
-        let inner_result_address = inner_result_ptr.as_ptr() as usize;
         match unsafe { inner_result_ptr.as_mut() } {
             Ok(t) => Ok(unsafe {
                 //SAFETY:
@@ -842,7 +1000,7 @@ impl Bump {
                 // reclaim any alignment padding we might have added (which
                 // `dealloc` cannot do) if we didn't allocate a new chunk for
                 // this result.
-                if self.is_last_allocation(NonNull::new_unchecked(inner_result_address as *mut _)) {
+                if self.is_last_allocation(inner_result_ptr.cast()) {
                     let current_footer_p = self.current_chunk_footer.get();
                     let current_ptr = &current_footer_p.as_ref().ptr;
                     if current_footer_p == rewind_footer {
@@ -930,7 +1088,6 @@ impl Bump {
         let rewind_footer = self.current_chunk_footer.get();
         let rewind_ptr = unsafe { rewind_footer.as_ref() }.ptr.get();
         let mut inner_result_ptr = NonNull::from(self.try_alloc_with(f)?);
-        let inner_result_address = inner_result_ptr.as_ptr() as usize;
         match unsafe { inner_result_ptr.as_mut() } {
             Ok(t) => Ok(unsafe {
                 //SAFETY:
@@ -952,7 +1109,7 @@ impl Bump {
                 // reclaim any alignment padding we might have added (which
                 // `dealloc` cannot do) if we didn't allocate a new chunk for
                 // this result.
-                if self.is_last_allocation(NonNull::new_unchecked(inner_result_address as *mut _)) {
+                if self.is_last_allocation(inner_result_ptr.cast()) {
                     let current_footer_p = self.current_chunk_footer.get();
                     let current_ptr = &current_footer_p.as_ref().ptr;
                     if current_footer_p == rewind_footer {
@@ -1316,6 +1473,7 @@ impl Bump {
     fn alloc_layout_slow(&self, layout: Layout) -> Option<NonNull<u8>> {
         unsafe {
             let size = layout.size();
+            let allocation_limit_remaining = self.allocation_limit_remaining();
 
             // Get a new chunk from the global allocator.
             let current_footer = self.current_chunk_footer.get();
@@ -1329,18 +1487,39 @@ impl Bump {
             let mut base_size = (current_layout.size() - FOOTER_SIZE)
                 .checked_mul(2)?
                 .max(min_new_chunk_size);
-            let sizes = iter::from_fn(|| {
-                if base_size >= min_new_chunk_size {
+            let chunk_memory_details = iter::from_fn(|| {
+                let bypass_min_chunk_size_for_small_limits = match self.allocation_limit() {
+                    Some(limit)
+                        if layout.size() < limit
+                            && base_size >= layout.size()
+                            && limit < DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER
+                            && self.allocated_bytes() == 0 =>
+                    {
+                        true
+                    }
+                    _ => false,
+                };
+
+                if base_size >= min_new_chunk_size || bypass_min_chunk_size_for_small_limits {
                     let size = base_size;
                     base_size = base_size / 2;
-                    Some(size)
+                    Bump::new_chunk_memory_details(Some(size), layout)
                 } else {
                     None
                 }
             });
 
-            let new_footer = sizes
-                .filter_map(|size| Bump::new_chunk(Some(size), layout, current_footer))
+            let new_footer = chunk_memory_details
+                .filter_map(|chunk_memory_details| {
+                    if Bump::chunk_fits_under_limit(
+                        allocation_limit_remaining,
+                        chunk_memory_details,
+                    ) {
+                        Bump::new_chunk(chunk_memory_details, layout, current_footer)
+                    } else {
+                        None
+                    }
+                })
                 .next()?;
 
             debug_assert_eq!(
@@ -1499,6 +1678,10 @@ impl Bump {
     /// on it only counting the sum of the sizes of the things
     /// you've allocated in the arena.
     ///
+    /// The allocated bytes do not include the size of bumpalo's metadata,
+    /// so the amount of memory requested from the Rust allocator is higher
+    /// than the returned value.
+    ///
     /// ## Example
     ///
     /// ```
@@ -1508,24 +1691,9 @@ impl Bump {
     /// assert!(bytes >= core::mem::size_of::<u32>() * 5);
     /// ```
     pub fn allocated_bytes(&self) -> usize {
-        let mut footer = self.current_chunk_footer.get();
-
-        let mut bytes = 0;
-
-        unsafe {
-            while !footer.as_ref().is_empty() {
-                let foot = footer.as_ref();
-
-                let ptr = foot.ptr.get().as_ptr() as usize;
-                debug_assert!(ptr <= foot as *const _ as usize);
-
-                bytes += foot as *const _ as usize - ptr;
-
-                footer = foot.prev.get();
-            }
-        }
+        let footer = self.current_chunk_footer.get();
 
-        bytes
+        unsafe { footer.as_ref().allocated_bytes }
     }
 
     #[inline]
@@ -1770,15 +1938,20 @@ unsafe impl<'a> Allocator for &'a Bump {
     }
 }
 
+// NB: Only tests which require private types, fields, or methods should be in
+// here. Anything that can just be tested via public API surface should be in
+// `bumpalo/tests/all/*`.
 #[cfg(test)]
 mod tests {
     use super::*;
 
+    // Uses private type `ChunkFooter`.
     #[test]
     fn chunk_footer_is_five_words() {
-        assert_eq!(mem::size_of::<ChunkFooter>(), mem::size_of::<usize>() * 5);
+        assert_eq!(mem::size_of::<ChunkFooter>(), mem::size_of::<usize>() * 6);
     }
 
+    // Uses private `alloc` module.
     #[test]
     #[allow(clippy::cognitive_complexity)]
     fn test_realloc() {
@@ -1828,6 +2001,7 @@ mod tests {
         }
     }
 
+    // Uses our private `alloc` module.
     #[test]
     fn invalid_read() {
         use alloc::Alloc;