Skip to content

Commit 23b0040

Browse files
committed
feat(allocator): introduce CloneIn trait. (#4726)
Introduce the trait discussed in #4284.
1 parent e0832f8 commit 23b0040

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

crates/oxc_allocator/src/clone_in.rs

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::cell::Cell;
2+
3+
use crate::{Allocator, Box, Vec};
4+
5+
/// A trait to explicitly clone an object into an arena allocator.
6+
///
7+
/// As a convention `Cloned` associated type should always be the same as `Self`,
8+
/// It'd only differ in the lifetime, Here's an example:
9+
///
10+
/// ```
11+
/// impl<'old_alloc, 'new_alloc> CloneIn<'new_alloc> for Struct<'old_alloc> {
12+
/// type Cloned = Struct<'new_alloc>;
13+
/// fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned {
14+
/// Struct { a: self.a.clone_in(alloc), b: self.b.clone_in(alloc) }
15+
/// }
16+
/// }
17+
/// ```
18+
///
19+
/// Implementations of this trait on non-allocated items usually short-circuit to `Clone::clone`;
20+
/// However, it **isn't** guaranteed.
21+
///
22+
pub trait CloneIn<'new_alloc>: Sized {
23+
type Cloned;
24+
25+
fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned;
26+
}
27+
28+
impl<'alloc, T, C> CloneIn<'alloc> for Option<T>
29+
where
30+
T: CloneIn<'alloc, Cloned = C>,
31+
{
32+
type Cloned = Option<C>;
33+
fn clone_in(&self, alloc: &'alloc Allocator) -> Self::Cloned {
34+
self.as_ref().map(|it| it.clone_in(alloc))
35+
}
36+
}
37+
38+
impl<'old_alloc, 'new_alloc, T, C> CloneIn<'new_alloc> for Box<'old_alloc, T>
39+
where
40+
T: CloneIn<'new_alloc, Cloned = C>,
41+
{
42+
type Cloned = Box<'new_alloc, C>;
43+
fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned {
44+
Box::new_in(self.as_ref().clone_in(alloc), alloc)
45+
}
46+
}
47+
48+
impl<'old_alloc, 'new_alloc, T, C> CloneIn<'new_alloc> for Vec<'old_alloc, T>
49+
where
50+
T: CloneIn<'new_alloc, Cloned = C>,
51+
{
52+
type Cloned = Vec<'new_alloc, C>;
53+
fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned {
54+
Vec::from_iter_in(self.iter().map(|it| it.clone_in(alloc)), alloc)
55+
}
56+
}
57+
58+
impl<'alloc, T: Copy> CloneIn<'alloc> for Cell<T> {
59+
type Cloned = Cell<T>;
60+
fn clone_in(&self, _: &'alloc Allocator) -> Self::Cloned {
61+
Cell::new(self.get())
62+
}
63+
}
64+
65+
impl<'old_alloc, 'new_alloc> CloneIn<'new_alloc> for &'old_alloc str {
66+
type Cloned = &'new_alloc str;
67+
fn clone_in(&self, alloc: &'new_alloc Allocator) -> Self::Cloned {
68+
alloc.alloc_str(self)
69+
}
70+
}
71+
72+
macro_rules! impl_clone_in {
73+
($($t:ty)*) => {
74+
$(
75+
impl<'alloc> CloneIn<'alloc> for $t {
76+
type Cloned = Self;
77+
#[inline(always)]
78+
fn clone_in(&self, _: &'alloc Allocator) -> Self {
79+
*self
80+
}
81+
}
82+
)*
83+
}
84+
}
85+
86+
impl_clone_in! {
87+
usize u8 u16 u32 u64 u128
88+
isize i8 i16 i32 i64 i128
89+
f32 f64
90+
bool char
91+
}

crates/oxc_allocator/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ use std::{
44
};
55

66
mod arena;
7+
mod clone_in;
78
mod convert;
89

910
use bumpalo::Bump;
1011

1112
pub use arena::{Box, String, Vec};
13+
pub use clone_in::CloneIn;
1214
pub use convert::{FromIn, IntoIn};
1315

1416
#[derive(Default)]

0 commit comments

Comments
 (0)