oxc_allocator/vec.rs
1//! Arena Vec.
2//!
3//! Originally based on [jsparagus](https://github.com/mozilla-spidermonkey/jsparagus/blob/24004745a8ed4939fc0dc7332bfd1268ac52285f/crates/ast/src/arena.rs)
4
5// All methods which just delegate to `allocator_api2::vec::Vec` methods marked `#[inline(always)]`
6#![expect(clippy::inline_always)]
7
8use std::{
9 self,
10 fmt::{self, Debug},
11 hash::{Hash, Hasher},
12 ops,
13 ptr::NonNull,
14 slice::SliceIndex,
15};
16
17#[cfg(feature = "serialize")]
18use serde::{Serialize, Serializer as SerdeSerializer};
19
20#[cfg(feature = "serialize")]
21use oxc_estree::{ConcatElement, ESTree, SequenceSerializer, Serializer as ESTreeSerializer};
22
23use crate::{Box, GetAllocator, arena::Arena, vec2::Vec as InnerVecGeneric};
24
25type InnerVec<'a, T> = InnerVecGeneric<'a, T, Arena>;
26
27/// A `Vec` without [`Drop`], which stores its data in the arena allocator.
28///
29/// # No `Drop`s
30///
31/// Objects allocated into Oxc memory arenas are never [`Dropped`](Drop). Memory is released in bulk
32/// when the allocator is dropped, without dropping the individual objects in the arena.
33///
34/// Therefore, it would produce a memory leak if you allocated [`Drop`] types into the arena
35/// which own memory allocations outside the arena.
36///
37/// Static checks make this impossible to do. [`Vec::new_in`] and all other methods which create
38/// a [`Vec`] will refuse to compile if called with a [`Drop`] type.
39#[derive(Eq)]
40#[repr(transparent)]
41pub struct Vec<'alloc, T>(InnerVec<'alloc, T>);
42
43/// SAFETY: Even though `Arena` is not `Sync`, we can make `Vec<T>` `Sync` if `T` is `Sync` because:
44///
45/// 1. No public methods allow access to the `&Arena` that `Vec` contains (in `RawVec`),
46/// so user cannot illegally obtain 2 `&Arena`s on different threads via `Vec`.
47///
48/// 2. All internal methods which access the `&Arena` take a `&mut self`.
49/// `&mut Vec` cannot be transferred across threads, and nor can an owned `Vec` (`Vec` is not `Send`).
50/// Therefore these methods taking `&mut self` can be sure they're not operating on a `Vec`
51/// which has been moved across threads.
52///
53/// Note: `Vec` CANNOT be `Send`, even if `T` is `Send`, because that would allow 2 `Vec`s on different
54/// threads to both allocate into same arena simultaneously. `Arena` is not thread-safe, and this would
55/// be undefined behavior.
56unsafe impl<T: Sync> Sync for Vec<'_, T> {}
57
58impl<'alloc, T> Vec<'alloc, T> {
59 /// Const assertion that `T` is not `Drop`.
60 /// Must be referenced in all methods which create a `Vec`.
61 const ASSERT_T_IS_NOT_DROP: () =
62 assert!(!std::mem::needs_drop::<T>(), "Cannot create a Vec<T> where T is a Drop type");
63
64 /// Constructs a new, empty `Vec<T>`.
65 ///
66 /// The vector will not allocate until elements are pushed onto it.
67 ///
68 /// # Examples
69 /// ```
70 /// use oxc_allocator::{Allocator, Vec};
71 ///
72 /// let allocator = Allocator::default();
73 /// let allocator = &allocator;
74 ///
75 /// let mut vec: Vec<i32> = Vec::new_in(&allocator);
76 /// assert!(vec.is_empty());
77 /// ```
78 #[inline(always)]
79 pub fn new_in<A: GetAllocator<'alloc>>(allocator: &A) -> Self {
80 const { Self::ASSERT_T_IS_NOT_DROP };
81
82 Self(InnerVec::new_in(allocator.allocator().arena()))
83 }
84
85 /// Constructs a new, empty `Vec<T>` with at least the specified capacity
86 /// with the provided allocator.
87 ///
88 /// The vector will be able to hold at least `capacity` elements without
89 /// reallocating. This method is allowed to allocate for more elements than
90 /// `capacity`. If `capacity` is 0, the vector will not allocate.
91 ///
92 /// It is important to note that although the returned vector has the
93 /// minimum *capacity* specified, the vector will have a zero *length*.
94 ///
95 /// For `Vec<T>` where `T` is a zero-sized type, there will be no allocation
96 /// and the capacity will always be `u32::MAX`.
97 ///
98 /// # Panics
99 ///
100 /// Panics if the new capacity exceeds `isize::MAX` bytes.
101 ///
102 /// # Examples
103 /// ```
104 /// use oxc_allocator::{Allocator, Vec};
105 ///
106 /// let allocator = Allocator::default();
107 /// let allocator = &allocator;
108 ///
109 /// let mut vec = Vec::with_capacity_in(10, &allocator);
110 ///
111 /// // The vector contains no items, even though it has capacity for more
112 /// assert_eq!(vec.len(), 0);
113 /// assert_eq!(vec.capacity(), 10);
114 ///
115 /// // These are all done without reallocating...
116 /// for i in 0..10 {
117 /// vec.push(i);
118 /// }
119 /// assert_eq!(vec.len(), 10);
120 /// assert_eq!(vec.capacity(), 10);
121 ///
122 /// // ...but this may make the vector reallocate
123 /// vec.push(11);
124 /// assert_eq!(vec.len(), 11);
125 /// assert!(vec.capacity() >= 11);
126 ///
127 /// // A vector of a zero-sized type will always over-allocate, since no
128 /// // allocation is necessary
129 /// let vec_units = Vec::<()>::with_capacity_in(10, &allocator);
130 /// assert_eq!(vec_units.capacity(), usize::MAX);
131 /// ```
132 #[inline(always)]
133 pub fn with_capacity_in<A: GetAllocator<'alloc>>(capacity: usize, allocator: &A) -> Self {
134 const { Self::ASSERT_T_IS_NOT_DROP };
135
136 Self(InnerVec::with_capacity_in(capacity, allocator.allocator().arena()))
137 }
138
139 /// Create a new [`Vec`] whose elements are taken from an iterator and
140 /// allocated in the given `allocator`.
141 ///
142 /// This is behaviorially identical to [`FromIterator::from_iter`].
143 #[inline]
144 pub fn from_iter_in<I: IntoIterator<Item = T>, A: GetAllocator<'alloc>>(
145 iter: I,
146 allocator: &A,
147 ) -> Self {
148 const { Self::ASSERT_T_IS_NOT_DROP };
149
150 let iter = iter.into_iter();
151 let hint = iter.size_hint();
152 let capacity = hint.1.unwrap_or(hint.0);
153 let mut vec = InnerVec::with_capacity_in(capacity, allocator.allocator().arena());
154 vec.extend(iter);
155 Self(vec)
156 }
157
158 /// Create a new [`Vec`] containing only a single value, allocated in the given `allocator`.
159 ///
160 /// # Examples
161 /// ```
162 /// use oxc_allocator::{Allocator, Vec};
163 ///
164 /// let allocator = Allocator::default();
165 /// let allocator = &allocator;
166 ///
167 /// let value = 123u32;
168 /// let vec = Vec::from_value_in(value, &allocator);
169 /// assert_eq!(vec, [123]);
170 /// ```
171 #[inline]
172 pub fn from_value_in<A: GetAllocator<'alloc>>(value: T, allocator: &A) -> Self {
173 const { Self::ASSERT_T_IS_NOT_DROP };
174
175 let allocator = allocator.allocator();
176 let boxed = Box::new_in(value, &allocator);
177 let ptr = Box::into_non_null(boxed).as_ptr();
178 // SAFETY: `ptr` contains a valid `T`.
179 // A `Vec` with length 1, capacity 1 can own the same allocation.
180 let vec = unsafe { InnerVec::from_raw_parts_in(ptr, 1, 1, allocator.arena()) };
181 Self(vec)
182 }
183
184 /// Create a new [`Vec`] from a fixed-size array, allocated in the given `allocator`.
185 ///
186 /// This is preferable to `from_iter_in` where source is an array, as size is statically known,
187 /// and compiler is more likely to construct the values directly in arena, rather than constructing
188 /// on stack and then copying to arena.
189 ///
190 /// # Examples
191 /// ```
192 /// use oxc_allocator::{Allocator, Vec};
193 ///
194 /// let allocator = Allocator::default();
195 /// let allocator = &allocator;
196 ///
197 /// let array: [u32; 4] = [1, 2, 3, 4];
198 /// let vec = Vec::from_array_in(array, &allocator);
199 /// ```
200 #[inline]
201 pub fn from_array_in<const N: usize, A: GetAllocator<'alloc>>(
202 array: [T; N],
203 allocator: &A,
204 ) -> Self {
205 const { Self::ASSERT_T_IS_NOT_DROP };
206
207 let allocator = allocator.allocator();
208 let boxed = Box::new_in(array, &allocator);
209 let ptr = Box::into_non_null(boxed).as_ptr().cast::<T>();
210 // SAFETY: `ptr` has correct alignment - it was just allocated as `[T; N]`.
211 // `ptr` was allocated with correct size for `[T; N]`.
212 // `len` and `capacity` are both `N`.
213 // Allocated size cannot be larger than `isize::MAX`, or `Box::new_in` would have failed.
214 let vec = unsafe { InnerVec::from_raw_parts_in(ptr, N, N, allocator.arena()) };
215 Self(vec)
216 }
217
218 /// Convert [`Vec<T>`] into [`Box<[T]>`].
219 ///
220 /// Any spare capacity in the `Vec` is lost.
221 ///
222 /// [`Box<[T]>`]: Box
223 #[inline]
224 pub fn into_boxed_slice(self) -> Box<'alloc, [T]> {
225 let slice = self.0.into_arena_slice_mut();
226 let ptr = NonNull::from(slice);
227 // SAFETY: `ptr` points to a valid `[T]`.
228 // Contents of the `Vec` are in an arena.
229 // The returned `Box` has same lifetime as the `Vec`.
230 // `Vec` is not `Drop`, so we don't need to free any unused capacity in the `Vec`.
231 unsafe { Box::from_non_null(ptr) }
232 }
233
234 /// Converts [`Vec<T>`] into [`&'alloc [T]`].
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use oxc_allocator::{Allocator, Vec};
240 ///
241 /// let allocator = Allocator::default();
242 /// let allocator = &allocator;
243 ///
244 /// let mut vec = Vec::from_iter_in([1, 2, 3], &allocator);
245 /// let slice = vec.into_arena_slice();
246 /// assert_eq!(slice, [1, 2, 3]);
247 /// ```
248 #[inline]
249 pub fn into_arena_slice(self) -> &'alloc [T] {
250 self.0.into_arena_slice()
251 }
252
253 /// Converts [`Vec<T>`] into [`&'alloc mut [T]`].
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// use oxc_allocator::{Allocator, Vec};
259 ///
260 /// let allocator = Allocator::default();
261 /// let allocator = &allocator;
262 ///
263 /// let vec = Vec::from_iter_in([1, 2, 3], &allocator);
264 /// let slice = vec.into_arena_slice_mut();
265 /// slice[0] = 4;
266 /// assert_eq!(slice, [4, 2, 3]);
267 /// ```
268 #[inline]
269 pub fn into_arena_slice_mut(self) -> &'alloc mut [T] {
270 self.0.into_arena_slice_mut()
271 }
272}
273
274impl<'alloc, T> ops::Deref for Vec<'alloc, T> {
275 type Target = InnerVec<'alloc, T>;
276
277 #[inline]
278 fn deref(&self) -> &Self::Target {
279 &self.0
280 }
281}
282
283impl<'alloc, T> ops::DerefMut for Vec<'alloc, T> {
284 #[inline]
285 fn deref_mut(&mut self) -> &mut InnerVec<'alloc, T> {
286 &mut self.0
287 }
288}
289
290// Forward all `PartialEq` comparisons to the inner `Vec`, mirroring the set of impls it provides
291// (against another `Vec`, slices, and arrays). These are implemented on the wrapper directly because
292// trait resolution does not look through `Deref`.
293//
294// The `Vec`-vs-`Vec` impl takes the place of `#[derive(PartialEq)]`. The derive would only allow
295// comparing two `Vec`s with the same element type `T`, whereas this allows comparing `Vec`s with
296// different (but comparable) element types, matching the inner `Vec` and `std::vec::Vec`.
297impl<T: PartialEq<U>, U> PartialEq<Vec<'_, U>> for Vec<'_, T> {
298 #[inline]
299 fn eq(&self, other: &Vec<'_, U>) -> bool {
300 self.0 == other.0
301 }
302}
303
304macro_rules! impl_slice_partial_eq {
305 ($rhs:ty) => {
306 impl<T: PartialEq<U>, U> PartialEq<$rhs> for Vec<'_, T> {
307 #[inline]
308 fn eq(&self, other: &$rhs) -> bool {
309 self.0 == *other
310 }
311 }
312 };
313}
314
315impl_slice_partial_eq!([U]);
316impl_slice_partial_eq!(&[U]);
317impl_slice_partial_eq!(&mut [U]);
318
319macro_rules! impl_array_partial_eq {
320 ($rhs:ty) => {
321 impl<T: PartialEq<U>, U, const N: usize> PartialEq<$rhs> for Vec<'_, T> {
322 #[inline]
323 fn eq(&self, other: &$rhs) -> bool {
324 self.0 == *other
325 }
326 }
327 };
328}
329
330impl_array_partial_eq!([U; N]);
331impl_array_partial_eq!(&[U; N]);
332impl_array_partial_eq!(&mut [U; N]);
333
334// Reverse direction: slice on the left, `Vec` on the right (e.g. `&[T] == vec`), forwarding to the
335// inner `Vec`'s reverse impls. `std::vec::Vec` provides these, so mirror them here.
336macro_rules! impl_slice_partial_eq_reverse {
337 ($lhs:ty) => {
338 impl<T: PartialEq<U>, U> PartialEq<Vec<'_, U>> for $lhs {
339 #[inline]
340 fn eq(&self, other: &Vec<'_, U>) -> bool {
341 *self == other.0
342 }
343 }
344 };
345}
346
347impl_slice_partial_eq_reverse!([T]);
348impl_slice_partial_eq_reverse!(&[T]);
349impl_slice_partial_eq_reverse!(&mut [T]);
350
351impl<'alloc, T> IntoIterator for Vec<'alloc, T> {
352 type IntoIter = <InnerVec<'alloc, T> as IntoIterator>::IntoIter;
353 type Item = T;
354
355 #[inline(always)]
356 fn into_iter(self) -> Self::IntoIter {
357 self.0.into_iter()
358 }
359}
360
361impl<'i, T> IntoIterator for &'i Vec<'_, T> {
362 type IntoIter = std::slice::Iter<'i, T>;
363 type Item = &'i T;
364
365 #[inline(always)]
366 fn into_iter(self) -> Self::IntoIter {
367 self.0.iter()
368 }
369}
370
371impl<'i, T> IntoIterator for &'i mut Vec<'_, T> {
372 type IntoIter = std::slice::IterMut<'i, T>;
373 type Item = &'i mut T;
374
375 #[inline(always)]
376 fn into_iter(self) -> Self::IntoIter {
377 self.0.iter_mut()
378 }
379}
380
381impl<T, I> ops::Index<I> for Vec<'_, T>
382where
383 I: SliceIndex<[T]>,
384{
385 type Output = I::Output;
386
387 #[inline(always)]
388 fn index(&self, index: I) -> &Self::Output {
389 self.0.index(index)
390 }
391}
392
393impl<T, I> ops::IndexMut<I> for Vec<'_, T>
394where
395 I: SliceIndex<[T]>,
396{
397 #[inline(always)]
398 fn index_mut(&mut self, index: I) -> &mut Self::Output {
399 self.0.index_mut(index)
400 }
401}
402
403impl<'a, T: 'a> From<Vec<'a, T>> for Box<'a, [T]> {
404 #[inline(always)]
405 fn from(v: Vec<'a, T>) -> Box<'a, [T]> {
406 v.into_boxed_slice()
407 }
408}
409
410#[cfg(feature = "serialize")]
411impl<T: Serialize> Serialize for Vec<'_, T> {
412 fn serialize<S: SerdeSerializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
413 self.as_slice().serialize(serializer)
414 }
415}
416
417#[cfg(feature = "serialize")]
418impl<T: ESTree> ESTree for Vec<'_, T> {
419 fn serialize<S: ESTreeSerializer>(&self, serializer: S) {
420 self.as_slice().serialize(serializer);
421 }
422}
423
424#[cfg(feature = "serialize")]
425impl<T: ESTree> ConcatElement for Vec<'_, T> {
426 fn push_to_sequence<S: SequenceSerializer>(&self, seq: &mut S) {
427 for element in self {
428 seq.serialize_element(element);
429 }
430 }
431}
432
433impl<T: Hash> Hash for Vec<'_, T> {
434 #[inline(always)]
435 fn hash<H: Hasher>(&self, state: &mut H) {
436 self.0.hash(state);
437 }
438}
439
440impl<T: Debug> Debug for Vec<'_, T> {
441 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
442 f.debug_tuple("Vec").field(&self.0).finish()
443 }
444}
445
446#[cfg(test)]
447mod test {
448 use crate::Allocator;
449
450 use super::Vec;
451
452 #[test]
453 fn vec_with_capacity() {
454 let allocator = Allocator::default();
455 let allocator = &allocator;
456 let v: Vec<i32> = Vec::with_capacity_in(10, &allocator);
457 assert!(v.is_empty());
458 }
459
460 #[test]
461 fn vec_debug() {
462 let allocator = Allocator::default();
463 let allocator = &allocator;
464 let mut v = Vec::new_in(&allocator);
465 v.push("x");
466 let v = format!("{v:?}");
467 assert_eq!(v, "Vec([\"x\"])");
468 }
469
470 #[test]
471 fn vec_into_boxed_slice() {
472 let allocator = Allocator::default();
473 let allocator = &allocator;
474 let mut v = Vec::with_capacity_in(4, &allocator);
475 v.push("x");
476 v.push("y");
477 let boxed_slice = v.into_boxed_slice();
478 assert_eq!(boxed_slice.as_ref(), &["x", "y"]);
479 }
480
481 #[cfg(feature = "serialize")]
482 #[test]
483 fn vec_serialize() {
484 let allocator = Allocator::default();
485 let allocator = &allocator;
486 let mut v = Vec::new_in(&allocator);
487 v.push("x");
488 let s = serde_json::to_string(&v).unwrap();
489 assert_eq!(s, r#"["x"]"#);
490 }
491
492 #[cfg(feature = "serialize")]
493 #[test]
494 fn vec_serialize_estree() {
495 use oxc_estree::{CompactSerializer, ESTree};
496
497 let allocator = Allocator::default();
498 let allocator = &allocator;
499 let mut v = Vec::new_in(&allocator);
500 v.push("x");
501
502 let mut serializer = CompactSerializer::default();
503 v.serialize(&mut serializer);
504 let s = serializer.into_string();
505 assert_eq!(s, r#"["x"]"#);
506 }
507
508 #[test]
509 #[expect(clippy::op_ref)]
510 fn vec_partial_eq() {
511 let allocator = Allocator::default();
512 let allocator = &allocator;
513
514 let v = Vec::from_array_in([1, 2, 3], &allocator);
515 let same = Vec::from_array_in([1, 2, 3], &allocator);
516
517 // `Vec` vs `Vec` (same element type), by value and by reference.
518 assert!(v == same);
519 assert_eq!(v, same);
520 assert!(&v == &same);
521
522 // `Vec` vs owned array `[U; N]`, and references to it.
523 assert!(v == [1, 2, 3]);
524 assert_eq!(v, [1, 2, 3]);
525 assert!(v == &[1, 2, 3]);
526 assert!(v == &mut [1, 2, 3]);
527
528 // `Vec` vs slice `&[U]` / `&mut [U]`.
529 let slice: &[i32] = &[1, 2, 3];
530 assert!(v == slice);
531 let mut_slice: &mut [i32] = &mut [1, 2, 3];
532 assert!(v == mut_slice);
533
534 // `Vec` vs unsized slice `[U]` (reached by dereferencing a slice reference).
535 assert!(v == *slice);
536
537 // Reverse direction: slice on the left, `Vec` on the right (std parity).
538 // Note: arrays on the left (`[1, 2, 3] == v`) are not supported - `std` doesn't provide
539 // `[T; N]: PartialEq<Vec>` either, only the slice forms below.
540 assert!(&[1, 2, 3][..] == v);
541 assert!(slice == v);
542 assert!(mut_slice == v);
543 assert!(*slice == v);
544
545 // Method-call form (no auto-ref). `v.eq(slice)` resolves through the unsized `[U]` impl.
546 assert!(v.eq(slice));
547 assert!(v.eq(&same));
548 assert!(v.eq(&[1, 2, 3]));
549 assert!(slice.eq(&v));
550
551 // Inequality still works.
552 assert!(v != [1, 2, 4]);
553 assert!(v != Vec::from_array_in([1, 2], &allocator));
554
555 // Cross element type: `T: PartialEq<U>` where `T != U`.
556 #[expect(clippy::items_after_statements)]
557 #[derive(Clone, Copy)]
558 struct Foo(u8);
559
560 #[derive(Clone, Copy)]
561 struct Bar(u8);
562
563 impl PartialEq<Bar> for Foo {
564 fn eq(&self, other: &Bar) -> bool {
565 self.0 == other.0
566 }
567 }
568
569 let foos = Vec::from_array_in([Foo(1), Foo(2)], &allocator);
570 let bars = Vec::from_array_in([Bar(1), Bar(2)], &allocator);
571 assert!(foos == bars);
572 assert!(foos == [Bar(1), Bar(2)]);
573 let bars_slice: &[Bar] = &[Bar(1), Bar(2)];
574 assert!(foos == bars_slice);
575 }
576
577 #[test]
578 fn vec_from_value_in() {
579 let allocator = Allocator::default();
580 let allocator = &allocator;
581 let mut v = Vec::from_value_in(123u32, &allocator);
582 assert_eq!(v, [123]);
583 assert_eq!(v.len(), 1);
584 assert_eq!(v.capacity(), 1);
585
586 // Growing the `Vec` reallocates into the allocator, preserving the original value
587 v.push(456);
588 assert_eq!(v, [123, 456]);
589 }
590
591 #[test]
592 fn lifetime_variance() {
593 fn _assert_vec_variant_lifetime<'a: 'b, 'b, T>(program: Vec<'a, T>) -> Vec<'b, T> {
594 program
595 }
596 }
597}