From 23b0040c1677b19e8be21a092a220c36fe02e64c Mon Sep 17 00:00:00 2001 From: rzvxa <3788964+rzvxa@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:28:54 +0000 Subject: [PATCH] feat(allocator): introduce `CloneIn` trait. (#4726) Introduce the trait discussed in #4284. --- crates/oxc_allocator/src/clone_in.rs | 91 ++++++++++++++++++++++++++++ crates/oxc_allocator/src/lib.rs | 2 + 2 files changed, 93 insertions(+) create mode 100644 crates/oxc_allocator/src/clone_in.rs diff --git a/crates/oxc_allocator/src/clone_in.rs b/crates/oxc_allocator/src/clone_in.rs new file mode 100644 index 0000000000000..6ec31c239d125 --- /dev/null +++ b/crates/oxc_allocator/src/clone_in.rs @@ -0,0 +1,91 @@ +use std::cell::Cell; + +use crate::{Allocator, Box, Vec}; + +/// A trait to explicitly clone an object into an arena allocator. +/// +/// As a convention `Cloned` associated type should always be the same as `Self`, +/// It'd only differ in the lifetime, Here's an example: +/// +/// ``` +/// impl<'old_alloc, 'new_alloc> CloneIn<'new_alloc> for Struct<'old_alloc> { +/// type Cloned = Struct<'new_alloc>; +/// fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned { +/// Struct { a: self.a.clone_in(alloc), b: self.b.clone_in(alloc) } +/// } +/// } +/// ``` +/// +/// Implementations of this trait on non-allocated items usually short-circuit to `Clone::clone`; +/// However, it **isn't** guaranteed. +/// +pub trait CloneIn<'new_alloc>: Sized { + type Cloned; + + fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned; +} + +impl<'alloc, T, C> CloneIn<'alloc> for Option +where + T: CloneIn<'alloc, Cloned = C>, +{ + type Cloned = Option; + fn clone_in(&self, alloc: &'alloc Allocator) -> Self::Cloned { + self.as_ref().map(|it| it.clone_in(alloc)) + } +} + +impl<'old_alloc, 'new_alloc, T, C> CloneIn<'new_alloc> for Box<'old_alloc, T> +where + T: CloneIn<'new_alloc, Cloned = C>, +{ + type Cloned = Box<'new_alloc, C>; + fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned { + Box::new_in(self.as_ref().clone_in(alloc), alloc) + } +} + +impl<'old_alloc, 'new_alloc, T, C> CloneIn<'new_alloc> for Vec<'old_alloc, T> +where + T: CloneIn<'new_alloc, Cloned = C>, +{ + type Cloned = Vec<'new_alloc, C>; + fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned { + Vec::from_iter_in(self.iter().map(|it| it.clone_in(alloc)), alloc) + } +} + +impl<'alloc, T: Copy> CloneIn<'alloc> for Cell { + type Cloned = Cell; + fn clone_in(&self, _: &'alloc Allocator) -> Self::Cloned { + Cell::new(self.get()) + } +} + +impl<'old_alloc, 'new_alloc> CloneIn<'new_alloc> for &'old_alloc str { + type Cloned = &'new_alloc str; + fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned { + alloc.alloc_str(self) + } +} + +macro_rules! impl_clone_in { + ($($t:ty)*) => { + $( + impl<'alloc> CloneIn<'alloc> for $t { + type Cloned = Self; + #[inline(always)] + fn clone_in(&self, _: &'alloc Allocator) -> Self { + *self + } + } + )* + } +} + +impl_clone_in! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char +} diff --git a/crates/oxc_allocator/src/lib.rs b/crates/oxc_allocator/src/lib.rs index a8707326c0c57..7ab4c8ff6d00e 100644 --- a/crates/oxc_allocator/src/lib.rs +++ b/crates/oxc_allocator/src/lib.rs @@ -4,11 +4,13 @@ use std::{ }; mod arena; +mod clone_in; mod convert; use bumpalo::Bump; pub use arena::{Box, String, Vec}; +pub use clone_in::CloneIn; pub use convert::{FromIn, IntoIn}; #[derive(Default)]