boa_engine/object/builtins/
jsset.rs1use std::ops::Deref;
3
4use boa_gc::{Finalize, Trace};
5
6use crate::{
7 Context, JsResult, JsValue,
8 builtins::{
9 Set, canonicalize_keyed_collection_key, iterable::IteratorHint,
10 set::ordered_set::OrderedSet,
11 },
12 error::JsNativeError,
13 object::{JsFunction, JsObject, JsSetIterator},
14 value::TryFromJs,
15};
16
17#[derive(Debug, Clone, Trace, Finalize)]
19pub struct JsSet {
20 inner: JsObject<OrderedSet>,
21}
22
23impl JsSet {
24 #[inline]
29 pub fn new(context: &mut Context) -> Self {
30 Self {
31 inner: JsObject::from_proto_and_data_with_shared_shape(
32 context.root_shape(),
33 context.intrinsics().constructors().set().prototype(),
34 OrderedSet::new(),
35 ),
36 }
37 }
38
39 #[inline]
43 #[must_use]
44 pub fn size(&self) -> usize {
45 self.inner.borrow().data().len()
46 }
47
48 pub fn add<T>(&self, value: T, context: &mut Context) -> JsResult<JsValue>
53 where
54 T: Into<JsValue>,
55 {
56 self.add_items(&[value.into()], context)
57 }
58
59 #[inline]
64 pub fn add_items(&self, items: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
65 Set::add(&self.inner.clone().into(), items, context)
66 }
67
68 #[inline]
72 pub fn clear(&self) {
73 self.inner.borrow_mut().data_mut().clear();
74 }
75
76 pub fn delete<T>(&self, value: T) -> bool
82 where
83 T: Into<JsValue>,
84 {
85 self.borrow_mut()
86 .data_mut()
87 .delete(&canonicalize_keyed_collection_key(value.into()))
88 }
89
90 #[must_use]
95 pub fn has<T>(&self, value: T) -> bool
96 where
97 T: Into<JsValue>,
98 {
99 self.borrow()
100 .data()
101 .contains(&canonicalize_keyed_collection_key(value.into()))
102 }
103
104 #[inline]
109 pub fn values(&self, context: &mut Context) -> JsResult<JsSetIterator> {
110 let iterator_object = Set::values(&self.inner.clone().into(), &[JsValue::null()], context)?
111 .get_iterator(IteratorHint::Sync, context)?;
112
113 JsSetIterator::from_object(iterator_object.iterator().clone())
114 }
115
116 #[inline]
122 pub fn keys(&self, context: &mut Context) -> JsResult<JsSetIterator> {
123 let iterator_object = Set::values(&self.inner.clone().into(), &[JsValue::null()], context)?
124 .get_iterator(IteratorHint::Sync, context)?;
125
126 JsSetIterator::from_object(iterator_object.iterator().clone())
127 }
128
129 #[inline]
135 pub fn for_each(
136 &self,
137 callback: JsFunction,
138 this_arg: JsValue,
139 context: &mut Context,
140 ) -> JsResult<JsValue> {
141 Set::for_each(
142 &self.inner.clone().into(),
143 &[callback.into(), this_arg],
144 context,
145 )
146 }
147
148 #[inline]
150 pub fn for_each_native<F>(&self, f: F) -> JsResult<()>
151 where
152 F: FnMut(JsValue) -> JsResult<()>,
153 {
154 let this = self.inner.clone().into();
155 Set::for_each_native(&this, f)
156 }
157
158 #[inline]
160 pub fn from_object(object: JsObject) -> Result<Self, JsObject> {
161 object.downcast::<OrderedSet>().map(|o| Self { inner: o })
162 }
163
164 pub fn from_iter<I>(elements: I, context: &mut Context) -> Self
166 where
167 I: IntoIterator<Item = JsValue>,
168 {
169 let elements = elements.into_iter();
170
171 let mut set = OrderedSet::with_capacity(elements.size_hint().0);
173
174 for elem in elements {
176 let elem = canonicalize_keyed_collection_key(elem);
177 set.add(elem);
178 }
179
180 Self {
181 inner: JsObject::from_proto_and_data_with_shared_shape(
182 context.root_shape(),
183 context.intrinsics().constructors().set().prototype(),
184 set,
185 ),
186 }
187 }
188}
189
190impl From<JsObject<OrderedSet>> for JsSet {
191 fn from(value: JsObject<OrderedSet>) -> Self {
192 Self { inner: value }
193 }
194}
195
196impl From<JsSet> for JsObject {
197 #[inline]
198 fn from(o: JsSet) -> Self {
199 o.inner.clone().upcast()
200 }
201}
202
203impl From<JsSet> for JsValue {
204 #[inline]
205 fn from(o: JsSet) -> Self {
206 o.inner.clone().into()
207 }
208}
209
210impl Deref for JsSet {
211 type Target = JsObject<OrderedSet>;
212 #[inline]
213 fn deref(&self) -> &Self::Target {
214 &self.inner
215 }
216}
217
218impl TryFromJs for JsSet {
219 fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
220 if let Some(o) = value.as_object()
221 && let Ok(set) = Self::from_object(o.clone())
222 {
223 Ok(set)
224 } else {
225 Err(JsNativeError::typ()
226 .with_message("value is not a Set object")
227 .into())
228 }
229 }
230}