diff --git a/crates/oxc_ast/src/ast_builder_impl.rs b/crates/oxc_ast/src/ast_builder_impl.rs index 8cbefde5f77a5..70b94627f9147 100644 --- a/crates/oxc_ast/src/ast_builder_impl.rs +++ b/crates/oxc_ast/src/ast_builder_impl.rs @@ -75,6 +75,26 @@ impl<'a> AstBuilder<'a> { Vec::from_array_in(array, self.allocator) } + /// Convert a [`Vec`] of one type to a [`Vec`] of another type. + /// + /// This method is useful where the `Src` is inherited from `Dst` or vice versa, so that you can it + /// without any runtime overhead. For example, you can convert a `Vec<'a, Expression>` to a + /// `Vec<'a, Argument>` + #[inline] + pub fn vec_convert<Src, Dst>(&self, vec: Vec<'a, Src>) -> Vec<'a, Dst> + where + Src: 'a, + Dst: 'a, + { + // Verify types are layout-compatible + debug_assert!(std::mem::size_of::<Src>() == std::mem::size_of::<Dst>()); + debug_assert!(std::mem::align_of::<Src>() == std::mem::align_of::<Dst>()); + + // SAFETY: Vec<Src> and Vec<Dst> have the same layout when Src and Dst have + // the same size and alignment. The lifetimes and allocator remain the same. + unsafe { std::mem::transmute(vec) } + } + /// Move a string slice into the memory arena, returning a reference to the slice /// in the heap. #[inline]