1use std::any::{Any, TypeId};
2
3use boa_gc::{Finalize, Trace, custom_trace};
4use hashbrown::hash_map::HashMap;
5
6use crate::object::NativeObject;
7
8#[allow(missing_debug_implementations)]
12pub struct HostDefined<T: ?Sized = dyn NativeObject> {
13 types: HashMap<TypeId, Box<T>>,
17}
18
19impl<T: ?Sized> Default for HostDefined<T> {
20 fn default() -> Self {
21 Self {
22 types: HashMap::default(),
23 }
24 }
25}
26
27unsafe impl<T: ?Sized + Trace> Trace for HostDefined<T> {
30 custom_trace!(this, mark, {
31 for value in this.types.values() {
32 mark(value);
33 }
34 });
35}
36
37impl<T: ?Sized + Finalize> Finalize for HostDefined<T> {}
38
39impl HostDefined<dyn Any> {
40 #[track_caller]
42 pub fn insert_default<T: Any + Default>(&mut self) -> Option<Box<T>> {
43 self.types
44 .insert(TypeId::of::<T>(), Box::<T>::default())
45 .and_then(|t| t.downcast().ok())
46 }
47
48 #[track_caller]
50 pub fn insert<T: Any>(&mut self, value: T) -> Option<Box<T>> {
51 self.types
52 .insert(TypeId::of::<T>(), Box::new(value))
53 .and_then(|t| t.downcast().ok())
54 }
55
56 #[track_caller]
60 pub fn remove<T: Any>(&mut self) -> Option<Box<T>> {
61 self.types
62 .remove(&TypeId::of::<T>())
63 .and_then(|t| t.downcast().ok())
64 }
65
66 #[track_caller]
68 pub fn get<T: Any>(&self) -> Option<&T> {
69 self.types
70 .get(&TypeId::of::<T>())
71 .map(Box::as_ref)
72 .and_then(<dyn Any>::downcast_ref::<T>)
73 }
74
75 #[track_caller]
77 pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
78 self.types
79 .get_mut(&TypeId::of::<T>())
80 .map(Box::as_mut)
81 .and_then(<dyn Any>::downcast_mut::<T>)
82 }
83
84 #[track_caller]
86 pub fn get_many_mut<T, const SIZE: usize>(&mut self) -> T::NativeTupleMutRef<'_>
87 where
88 T: NativeTuple<SIZE>,
89 {
90 let ids = T::as_type_ids();
91 let refs: [&TypeId; SIZE] = std::array::from_fn(|i| &ids[i]);
92 let anys = self
93 .types
94 .get_disjoint_mut(refs)
95 .map(|o| o.map(|v| &mut **v));
96
97 T::mut_ref_from_anys(anys)
98 }
99}
100
101impl HostDefined<dyn NativeObject> {
102 #[track_caller]
104 pub fn insert_default<T: NativeObject + Default>(&mut self) -> Option<Box<T>> {
105 self.types
106 .insert(TypeId::of::<T>(), Box::<T>::default())
107 .and_then(|t| {
108 let t: Box<dyn Any> = t;
110 t.downcast().ok()
111 })
112 }
113
114 #[track_caller]
116 pub fn insert<T: NativeObject>(&mut self, value: T) -> Option<Box<T>> {
117 self.types
118 .insert(TypeId::of::<T>(), Box::new(value))
119 .and_then(|t| {
120 let t: Box<dyn Any> = t;
122 t.downcast().ok()
123 })
124 }
125
126 #[track_caller]
130 pub fn remove<T: NativeObject>(&mut self) -> Option<Box<T>> {
131 self.types.remove(&TypeId::of::<T>()).and_then(|t| {
132 let t: Box<dyn Any> = t;
134 t.downcast().ok()
135 })
136 }
137
138 #[track_caller]
140 pub fn get<T: NativeObject>(&self) -> Option<&T> {
141 self.types
142 .get(&TypeId::of::<T>())
143 .map(Box::as_ref)
144 .and_then(<dyn NativeObject>::downcast_ref::<T>)
145 }
146
147 #[track_caller]
149 pub fn get_mut<T: NativeObject>(&mut self) -> Option<&mut T> {
150 self.types
151 .get_mut(&TypeId::of::<T>())
152 .map(Box::as_mut)
153 .and_then(<dyn NativeObject>::downcast_mut::<T>)
154 }
155
156 #[track_caller]
158 pub fn get_many_mut<T, const SIZE: usize>(&mut self) -> T::NativeTupleMutRef<'_>
159 where
160 T: NativeTuple<SIZE>,
161 {
162 let ids = T::as_type_ids();
163 let refs: [&TypeId; SIZE] = std::array::from_fn(|i| &ids[i]);
164 let anys = self.types.get_disjoint_mut(refs).map(|o| {
165 o.map(|v| {
166 let v: &mut dyn Any = &mut **v;
167 v
168 })
169 });
170
171 T::mut_ref_from_anys(anys)
172 }
173}
174
175impl<T: ?Sized> HostDefined<T> {
176 #[must_use]
178 #[track_caller]
179 pub fn has<U: 'static>(&self) -> bool {
180 self.types.contains_key(&TypeId::of::<U>())
181 }
182
183 #[track_caller]
185 pub fn clear(&mut self) {
186 self.types.clear();
187 }
188}
189
190pub trait NativeTuple<const SIZE: usize> {
195 type NativeTupleMutRef<'a>;
196
197 fn as_type_ids() -> [TypeId; SIZE];
198
199 fn mut_ref_from_anys(anys: [Option<&'_ mut dyn Any>; SIZE]) -> Self::NativeTupleMutRef<'_>;
200}
201
202macro_rules! impl_native_tuple {
203 ($size:literal $(,$name:ident)* ) => {
204 impl<$($name: Any,)*> NativeTuple<$size> for ($($name,)*) {
205 type NativeTupleMutRef<'a> = ($(Option<&'a mut $name>,)*);
206
207 fn as_type_ids() -> [TypeId; $size] {
208 [$(TypeId::of::<$name>(),)*]
209 }
210
211 #[allow(unused_variables, unused_mut, clippy::unused_unit)]
212 fn mut_ref_from_anys(
213 anys: [Option<&'_ mut dyn Any>; $size],
214 ) -> Self::NativeTupleMutRef<'_> {
215 let mut anys = anys.into_iter();
216 ($(
217 anys.next().flatten().and_then(|v| v.downcast_mut::<$name>()),
218 )*)
219 }
220 }
221 }
222}
223
224impl_native_tuple!(0);
225impl_native_tuple!(1, A);
226impl_native_tuple!(2, A, B);
227impl_native_tuple!(3, A, B, C);
228impl_native_tuple!(4, A, B, C, D);
229impl_native_tuple!(5, A, B, C, D, E);
230impl_native_tuple!(6, A, B, C, D, E, F);
231impl_native_tuple!(7, A, B, C, D, E, F, G);
232impl_native_tuple!(8, A, B, C, D, E, F, G, H);
233impl_native_tuple!(9, A, B, C, D, E, F, G, H, I);
234impl_native_tuple!(10, A, B, C, D, E, F, G, H, I, J);
235impl_native_tuple!(11, A, B, C, D, E, F, G, H, I, J, K);
236impl_native_tuple!(12, A, B, C, D, E, F, G, H, I, J, K, L);