Skip to content

Commit

Permalink
feat(allocator): add Vec::into_boxed_slice
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac committed Sep 30, 2024
1 parent 0af64c6 commit 1156adc
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
12 changes: 12 additions & 0 deletions crates/oxc_allocator/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ impl<'alloc, T> Box<'alloc, T> {
}
}

impl<'alloc, T: ?Sized> Box<'alloc, T> {
/// Create a [`Box`] from a raw pointer to a value in the arena.
///
/// # SAFETY
/// It is only safe to create a `Box` this way with pointers taken out of
/// another `Box` in the same arena.
#[inline]
pub(crate) const unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
Self(ptr, PhantomData)
}
}

impl<'alloc, T: ?Sized> ops::Deref for Box<'alloc, T> {
type Target = T;

Expand Down
41 changes: 40 additions & 1 deletion crates/oxc_allocator/src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use bumpalo::Bump;
#[cfg(any(feature = "serialize", test))]
use serde::{ser::SerializeSeq, Serialize, Serializer};

use crate::Allocator;
use crate::{Allocator, Box};

/// Bumpalo Vec
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -101,6 +101,33 @@ impl<'alloc, T> Vec<'alloc, T> {
vec.extend(iter);
Self(vec)
}

/// Converts the vector into [`Box<[T]>`][owned slice].
///
/// If the vector has excess capacity, its items will be moved into a
/// newly-allocated buffer with exactly the right capacity. That is, any
/// excess capacity will be removed.
///
/// [owned slice]: Box
///
/// # Examples
///
/// ```
/// use oxc_allocator::{Allocator, Vec};
///
/// let allocator = Allocator::default();
/// let v = Vec::from_iter_in([1, 2, 3], &allocator);
/// let b = v.into_boxed_slice();
///
/// assert_eq!(&*b, &[1, 2, 3]);
/// ```
pub fn into_boxed_slice(self) -> Box<'alloc, [T]> {
let b = self.0.into_boxed_slice();
let (ptr, _) = allocator_api2::boxed::Box::into_non_null(b);
// SAFETY: this is effectively a transmute from allocator_api2's box to
// our own representation. Ptr is non-null and points to initialized, well-aligned memory.
unsafe { Box::from_non_null(ptr) }
}
}

impl<'alloc, T> ops::Deref for Vec<'alloc, T> {
Expand Down Expand Up @@ -219,4 +246,16 @@ mod test {
program
}
}

#[test]
fn test_vec_to_boxed_slice() {
// file: oxc_allocator/src/vec.rs
use crate::boxed::Box;

let allocator = Allocator::default();
let v = Vec::from_iter_in([1, 2, 3], &allocator);
let b: Box<[i32]> = v.into_boxed_slice(); // <- compiler error

assert_eq!(&*b, &[1, 2, 3]);
}
}

0 comments on commit 1156adc

Please sign in to comment.