#![expect(clippy::inline_always)]
use std::{
self,
fmt::{self, Debug},
hash::{Hash, Hasher},
ops,
ptr::NonNull,
slice::SliceIndex,
};
#[cfg(feature = "serialize")]
use serde::{Serialize, Serializer as SerdeSerializer};
#[cfg(feature = "serialize")]
use oxc_estree::{ConcatElement, ESTree, SequenceSerializer, Serializer as ESTreeSerializer};
use crate::{Box, GetAllocator, arena::Arena, vec2::Vec as InnerVecGeneric};
type InnerVec<'a, T> = InnerVecGeneric<'a, T, Arena>;
#[derive(Eq)]
#[repr(transparent)]
pub struct Vec<'alloc, T>(InnerVec<'alloc, T>);
unsafe impl<T: Sync> Sync for Vec<'_, T> {}
impl<'alloc, T> Vec<'alloc, T> {
const ASSERT_T_IS_NOT_DROP: () =
assert!(!std::mem::needs_drop::<T>(), "Cannot create a Vec<T> where T is a Drop type");
#[inline(always)]
pub fn new_in<A: GetAllocator<'alloc>>(allocator: &A) -> Self {
const { Self::ASSERT_T_IS_NOT_DROP };
Self(InnerVec::new_in(allocator.allocator().arena()))
}
#[inline(always)]
pub fn with_capacity_in<A: GetAllocator<'alloc>>(capacity: usize, allocator: &A) -> Self {
const { Self::ASSERT_T_IS_NOT_DROP };
Self(InnerVec::with_capacity_in(capacity, allocator.allocator().arena()))
}
#[inline]
pub fn from_iter_in<I: IntoIterator<Item = T>, A: GetAllocator<'alloc>>(
iter: I,
allocator: &A,
) -> Self {
const { Self::ASSERT_T_IS_NOT_DROP };
let iter = iter.into_iter();
let hint = iter.size_hint();
let capacity = hint.1.unwrap_or(hint.0);
let mut vec = InnerVec::with_capacity_in(capacity, allocator.allocator().arena());
vec.extend(iter);
Self(vec)
}
#[inline]
pub fn from_value_in<A: GetAllocator<'alloc>>(value: T, allocator: &A) -> Self {
const { Self::ASSERT_T_IS_NOT_DROP };
let allocator = allocator.allocator();
let boxed = Box::new_in(value, &allocator);
let ptr = Box::into_non_null(boxed).as_ptr();
let vec = unsafe { InnerVec::from_raw_parts_in(ptr, 1, 1, allocator.arena()) };
Self(vec)
}
#[inline]
pub fn from_array_in<const N: usize, A: GetAllocator<'alloc>>(
array: [T; N],
allocator: &A,
) -> Self {
const { Self::ASSERT_T_IS_NOT_DROP };
let allocator = allocator.allocator();
let boxed = Box::new_in(array, &allocator);
let ptr = Box::into_non_null(boxed).as_ptr().cast::<T>();
let vec = unsafe { InnerVec::from_raw_parts_in(ptr, N, N, allocator.arena()) };
Self(vec)
}
#[inline]
pub fn into_boxed_slice(self) -> Box<'alloc, [T]> {
let slice = self.0.into_arena_slice_mut();
let ptr = NonNull::from(slice);
unsafe { Box::from_non_null(ptr) }
}
#[inline]
pub fn into_arena_slice(self) -> &'alloc [T] {
self.0.into_arena_slice()
}
#[inline]
pub fn into_arena_slice_mut(self) -> &'alloc mut [T] {
self.0.into_arena_slice_mut()
}
}
impl<'alloc, T> ops::Deref for Vec<'alloc, T> {
type Target = InnerVec<'alloc, T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'alloc, T> ops::DerefMut for Vec<'alloc, T> {
#[inline]
fn deref_mut(&mut self) -> &mut InnerVec<'alloc, T> {
&mut self.0
}
}
impl<T: PartialEq<U>, U> PartialEq<Vec<'_, U>> for Vec<'_, T> {
#[inline]
fn eq(&self, other: &Vec<'_, U>) -> bool {
self.0 == other.0
}
}
macro_rules! impl_slice_partial_eq {
($rhs:ty) => {
impl<T: PartialEq<U>, U> PartialEq<$rhs> for Vec<'_, T> {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
self.0 == *other
}
}
};
}
impl_slice_partial_eq!([U]);
impl_slice_partial_eq!(&[U]);
impl_slice_partial_eq!(&mut [U]);
macro_rules! impl_array_partial_eq {
($rhs:ty) => {
impl<T: PartialEq<U>, U, const N: usize> PartialEq<$rhs> for Vec<'_, T> {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
self.0 == *other
}
}
};
}
impl_array_partial_eq!([U; N]);
impl_array_partial_eq!(&[U; N]);
impl_array_partial_eq!(&mut [U; N]);
macro_rules! impl_slice_partial_eq_reverse {
($lhs:ty) => {
impl<T: PartialEq<U>, U> PartialEq<Vec<'_, U>> for $lhs {
#[inline]
fn eq(&self, other: &Vec<'_, U>) -> bool {
*self == other.0
}
}
};
}
impl_slice_partial_eq_reverse!([T]);
impl_slice_partial_eq_reverse!(&[T]);
impl_slice_partial_eq_reverse!(&mut [T]);
impl<'alloc, T> IntoIterator for Vec<'alloc, T> {
type IntoIter = <InnerVec<'alloc, T> as IntoIterator>::IntoIter;
type Item = T;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'i, T> IntoIterator for &'i Vec<'_, T> {
type IntoIter = std::slice::Iter<'i, T>;
type Item = &'i T;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'i, T> IntoIterator for &'i mut Vec<'_, T> {
type IntoIter = std::slice::IterMut<'i, T>;
type Item = &'i mut T;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T, I> ops::Index<I> for Vec<'_, T>
where
I: SliceIndex<[T]>,
{
type Output = I::Output;
#[inline(always)]
fn index(&self, index: I) -> &Self::Output {
self.0.index(index)
}
}
impl<T, I> ops::IndexMut<I> for Vec<'_, T>
where
I: SliceIndex<[T]>,
{
#[inline(always)]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.0.index_mut(index)
}
}
impl<'a, T: 'a> From<Vec<'a, T>> for Box<'a, [T]> {
#[inline(always)]
fn from(v: Vec<'a, T>) -> Box<'a, [T]> {
v.into_boxed_slice()
}
}
#[cfg(feature = "serialize")]
impl<T: Serialize> Serialize for Vec<'_, T> {
fn serialize<S: SerdeSerializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.as_slice().serialize(serializer)
}
}
#[cfg(feature = "serialize")]
impl<T: ESTree> ESTree for Vec<'_, T> {
fn serialize<S: ESTreeSerializer>(&self, serializer: S) {
self.as_slice().serialize(serializer);
}
}
#[cfg(feature = "serialize")]
impl<T: ESTree> ConcatElement for Vec<'_, T> {
fn push_to_sequence<S: SequenceSerializer>(&self, seq: &mut S) {
for element in self {
seq.serialize_element(element);
}
}
}
impl<T: Hash> Hash for Vec<'_, T> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: Debug> Debug for Vec<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Vec").field(&self.0).finish()
}
}
#[cfg(test)]
mod test {
use crate::Allocator;
use super::Vec;
#[test]
fn vec_with_capacity() {
let allocator = Allocator::default();
let allocator = &allocator;
let v: Vec<i32> = Vec::with_capacity_in(10, &allocator);
assert!(v.is_empty());
}
#[test]
fn vec_debug() {
let allocator = Allocator::default();
let allocator = &allocator;
let mut v = Vec::new_in(&allocator);
v.push("x");
let v = format!("{v:?}");
assert_eq!(v, "Vec([\"x\"])");
}
#[test]
fn vec_into_boxed_slice() {
let allocator = Allocator::default();
let allocator = &allocator;
let mut v = Vec::with_capacity_in(4, &allocator);
v.push("x");
v.push("y");
let boxed_slice = v.into_boxed_slice();
assert_eq!(boxed_slice.as_ref(), &["x", "y"]);
}
#[cfg(feature = "serialize")]
#[test]
fn vec_serialize() {
let allocator = Allocator::default();
let allocator = &allocator;
let mut v = Vec::new_in(&allocator);
v.push("x");
let s = serde_json::to_string(&v).unwrap();
assert_eq!(s, r#"["x"]"#);
}
#[cfg(feature = "serialize")]
#[test]
fn vec_serialize_estree() {
use oxc_estree::{CompactSerializer, ESTree};
let allocator = Allocator::default();
let allocator = &allocator;
let mut v = Vec::new_in(&allocator);
v.push("x");
let mut serializer = CompactSerializer::default();
v.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(s, r#"["x"]"#);
}
#[test]
#[expect(clippy::manual_assert_eq, clippy::op_ref)]
fn vec_partial_eq() {
let allocator = Allocator::default();
let allocator = &allocator;
let v = Vec::from_array_in([1, 2, 3], &allocator);
let same = Vec::from_array_in([1, 2, 3], &allocator);
assert!(v == same);
assert_eq!(v, same);
assert!(&v == &same);
assert!(v == [1, 2, 3]);
assert_eq!(v, [1, 2, 3]);
assert!(v == &[1, 2, 3]);
assert!(v == &mut [1, 2, 3]);
let slice: &[i32] = &[1, 2, 3];
assert!(v == slice);
let mut_slice: &mut [i32] = &mut [1, 2, 3];
assert!(v == mut_slice);
assert!(v == *slice);
assert!(&[1, 2, 3][..] == v);
assert!(slice == v);
assert!(mut_slice == v);
assert!(*slice == v);
assert!(v.eq(slice));
assert!(v.eq(&same));
assert!(v.eq(&[1, 2, 3]));
assert!(slice.eq(&v));
assert!(v != [1, 2, 4]);
assert!(v != Vec::from_array_in([1, 2], &allocator));
#[expect(clippy::items_after_statements)]
#[derive(Clone, Copy)]
struct Foo(u8);
#[derive(Clone, Copy)]
struct Bar(u8);
impl PartialEq<Bar> for Foo {
fn eq(&self, other: &Bar) -> bool {
self.0 == other.0
}
}
let foos = Vec::from_array_in([Foo(1), Foo(2)], &allocator);
let bars = Vec::from_array_in([Bar(1), Bar(2)], &allocator);
assert!(foos == bars);
assert!(foos == [Bar(1), Bar(2)]);
let bars_slice: &[Bar] = &[Bar(1), Bar(2)];
assert!(foos == bars_slice);
}
#[test]
fn vec_from_value_in() {
let allocator = Allocator::default();
let allocator = &allocator;
let mut v = Vec::from_value_in(123u32, &allocator);
assert_eq!(v, [123]);
assert_eq!(v.len(), 1);
assert_eq!(v.capacity(), 1);
v.push(456);
assert_eq!(v, [123, 456]);
}
#[test]
fn lifetime_variance() {
fn _assert_vec_variant_lifetime<'a: 'b, 'b, T>(program: Vec<'a, T>) -> Vec<'b, T> {
program
}
}
}