1use std::{
2 any::TypeId,
3 borrow::Cow,
4 cell::Cell,
5 collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
6 hash::{BuildHasher, Hash},
7 marker::PhantomData,
8 num::{
9 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
10 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
11 },
12 path::{Path, PathBuf},
13 rc::Rc,
14 sync::atomic,
15};
16
17use boa_gc::{Ephemeron, Finalize, Gc, GcRefCell, Trace, WeakGc, WeakMap};
18
19use super::internal_methods::{InternalObjectMethods, ORDINARY_INTERNAL_METHODS};
20
21pub trait JsData {
42 #[doc(hidden)]
43 fn internal_methods(&self) -> &'static InternalObjectMethods
44 where
45 Self: Sized, {
47 &ORDINARY_INTERNAL_METHODS
48 }
49}
50
51macro_rules! default_impls {
52 ($($T:ty),*$(,)?) => {
53 $(
54 impl JsData for $T {}
55 )*
56 }
57}
58
59default_impls![
60 (),
61 bool,
62 isize,
63 usize,
64 i8,
65 u8,
66 i16,
67 u16,
68 i32,
69 u32,
70 i64,
71 u64,
72 i128,
73 u128,
74 f32,
75 f64,
76 char,
77 TypeId,
78 String,
79 Path,
80 PathBuf,
81 NonZeroIsize,
82 NonZeroUsize,
83 NonZeroI8,
84 NonZeroU8,
85 NonZeroI16,
86 NonZeroU16,
87 NonZeroI32,
88 NonZeroU32,
89 NonZeroI64,
90 NonZeroU64,
91 NonZeroI128,
92 NonZeroU128,
93];
94
95#[cfg(target_has_atomic = "8")]
96default_impls![atomic::AtomicBool, atomic::AtomicI8, atomic::AtomicU8];
97
98#[cfg(target_has_atomic = "16")]
99default_impls![atomic::AtomicI16, atomic::AtomicU16];
100
101#[cfg(target_has_atomic = "32")]
102default_impls![atomic::AtomicI32, atomic::AtomicU32];
103
104#[cfg(target_has_atomic = "64")]
105default_impls![atomic::AtomicI64, atomic::AtomicU64];
106
107#[cfg(target_has_atomic = "ptr")]
108default_impls![atomic::AtomicIsize, atomic::AtomicUsize];
109
110impl<T, const N: usize> JsData for [T; N] {}
111
112macro_rules! fn_one {
113 ($ty:ty $(,$args:ident)*) => {
114 impl<Ret $(,$args)*> JsData for $ty {}
115 }
116}
117
118macro_rules! fn_impls {
119 () => {
120 fn_one!(extern "Rust" fn () -> Ret);
121 fn_one!(extern "C" fn () -> Ret);
122 fn_one!(unsafe extern "Rust" fn () -> Ret);
123 fn_one!(unsafe extern "C" fn () -> Ret);
124 };
125 ($($args:ident),*) => {
126 fn_one!(extern "Rust" fn ($($args),*) -> Ret, $($args),*);
127 fn_one!(extern "C" fn ($($args),*) -> Ret, $($args),*);
128 fn_one!(extern "C" fn ($($args),*, ...) -> Ret, $($args),*);
129 fn_one!(unsafe extern "Rust" fn ($($args),*) -> Ret, $($args),*);
130 fn_one!(unsafe extern "C" fn ($($args),*) -> Ret, $($args),*);
131 fn_one!(unsafe extern "C" fn ($($args),*, ...) -> Ret, $($args),*);
132 }
133}
134
135macro_rules! tuple_impls {
136 () => {}; ($($args:ident),*) => {
138 impl<$($args),*> JsData for ($($args,)*) {}
139 }
140}
141
142macro_rules! type_arg_tuple_based_impls {
143 ($(($($args:ident),*);)*) => {
144 $(
145 fn_impls!($($args),*);
146 tuple_impls!($($args),*);
147 )*
148 }
149}
150
151type_arg_tuple_based_impls![
152 ();
153 (A);
154 (A, B);
155 (A, B, C);
156 (A, B, C, D);
157 (A, B, C, D, E);
158 (A, B, C, D, E, F);
159 (A, B, C, D, E, F, G);
160 (A, B, C, D, E, F, G, H);
161 (A, B, C, D, E, F, G, H, I);
162 (A, B, C, D, E, F, G, H, I, J);
163 (A, B, C, D, E, F, G, H, I, J, K);
164 (A, B, C, D, E, F, G, H, I, J, K, L);
165];
166
167impl<T: ?Sized> JsData for Box<T> {}
168
169impl<T: ?Sized> JsData for Rc<T> {}
170
171impl<T> JsData for Vec<T> {}
172
173impl<T> JsData for thin_vec::ThinVec<T> {}
174
175impl<T> JsData for Option<T> {}
176
177impl<T, E> JsData for Result<T, E> {}
178
179impl<T: Ord> JsData for BinaryHeap<T> {}
180
181impl<K, V> JsData for BTreeMap<K, V> {}
182
183impl<T> JsData for BTreeSet<T> {}
184
185impl<K: Eq + Hash, V, S: BuildHasher> JsData for hashbrown::hash_map::HashMap<K, V, S> {}
186
187impl<K: Eq + Hash, V, S: BuildHasher> JsData for HashMap<K, V, S> {}
188
189impl<T: Eq + Hash, S: BuildHasher> JsData for HashSet<T, S> {}
190
191impl<T: Eq + Hash> JsData for LinkedList<T> {}
192
193impl<T> JsData for PhantomData<T> {}
194
195impl<T> JsData for VecDeque<T> {}
196
197impl<T: ToOwned + ?Sized> JsData for Cow<'static, T> {}
198
199impl<T> JsData for Cell<Option<T>> {}
200
201#[cfg(feature = "intl")]
202default_impls!(icu_locale::Locale);
203
204impl<T: Trace + ?Sized> JsData for Gc<T> {}
205
206impl<T: Trace + ?Sized> JsData for WeakGc<T> {}
207
208impl<T: Trace + ?Sized, V: Trace> JsData for Ephemeron<T, V> {}
209
210impl<T: Trace + ?Sized> JsData for GcRefCell<T> {}
211
212impl<K: Trace + ?Sized, V: Trace> JsData for WeakMap<K, V> {}
213
214#[derive(Debug, Finalize, Trace)]
223#[boa_gc(unsafe_no_drop)]
225#[repr(C, align(8))]
226#[non_exhaustive]
227pub(crate) struct ObjectData<T: ?Sized> {
228 data: T,
233}
234
235impl<T: Default> Default for ObjectData<T> {
236 #[inline]
237 fn default() -> Self {
238 Self::new(T::default())
239 }
240}
241
242static_assertions::const_assert!(align_of::<Box<()>>() <= 8);
243
244impl<T> ObjectData<T> {
245 const OBJECT_DATA_ALIGNMENT_REQUIREMENT: () = assert!(
246 align_of::<T>() <= 8,
247 "Alignment of JsData must be <= 8, consider wrapping the data in a Box<T>."
248 );
249
250 pub(crate) fn new(value: T) -> Self {
251 let () = Self::OBJECT_DATA_ALIGNMENT_REQUIREMENT;
253
254 Self { data: value }
255 }
256}
257
258impl<T: ?Sized> AsRef<T> for ObjectData<T> {
259 #[inline]
260 fn as_ref(&self) -> &T {
261 &self.data
262 }
263}
264
265impl<T: ?Sized> AsMut<T> for ObjectData<T> {
266 #[inline]
267 fn as_mut(&mut self) -> &mut T {
268 &mut self.data
269 }
270}