boa_engine/object/builtins/
jsset.rs1use std::ops::Deref;
3
4use boa_gc::{Finalize, Trace};
5
6use crate::{
7 Context, JsResult, JsValue,
8 builtins::{Set, iterable::IteratorHint, set::ordered_set::OrderedSet},
9 error::JsNativeError,
10 object::{JsFunction, JsObject, JsSetIterator},
11 value::TryFromJs,
12};
13
14#[derive(Debug, Clone, Trace, Finalize)]
16pub struct JsSet {
17 inner: JsObject,
18}
19
20impl JsSet {
21 #[inline]
26 pub fn new(context: &mut Context) -> Self {
27 let inner = Set::set_create(None, context);
28
29 Self { inner }
30 }
31
32 #[inline]
36 pub fn size(&self) -> JsResult<usize> {
37 Set::get_size(&self.inner.clone().into())
38 }
39
40 pub fn add<T>(&self, value: T, context: &mut Context) -> JsResult<JsValue>
45 where
46 T: Into<JsValue>,
47 {
48 self.add_items(&[value.into()], context)
49 }
50
51 #[inline]
56 pub fn add_items(&self, items: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
57 Set::add(&self.inner.clone().into(), items, context)
58 }
59
60 #[inline]
65 pub fn clear(&self, context: &mut Context) -> JsResult<JsValue> {
66 Set::clear(&self.inner.clone().into(), &[JsValue::null()], context)
67 }
68
69 pub fn delete<T>(&self, value: T, context: &mut Context) -> JsResult<bool>
75 where
76 T: Into<JsValue>,
77 {
78 match Set::delete(&self.inner.clone().into(), &[value.into()], context)?.as_boolean() {
80 Some(bool) => Ok(bool),
81 _ => unreachable!("`delete` must always return a bool"),
82 }
83 }
84
85 pub fn has<T>(&self, value: T, context: &mut Context) -> JsResult<bool>
90 where
91 T: Into<JsValue>,
92 {
93 match Set::has(&self.inner.clone().into(), &[value.into()], context)?.as_boolean() {
95 Some(bool) => Ok(bool),
96 _ => unreachable!("`has` must always return a bool"),
97 }
98 }
99
100 #[inline]
105 pub fn values(&self, context: &mut Context) -> JsResult<JsSetIterator> {
106 let iterator_object = Set::values(&self.inner.clone().into(), &[JsValue::null()], context)?
107 .get_iterator(IteratorHint::Sync, context)?;
108
109 JsSetIterator::from_object(iterator_object.iterator().clone())
110 }
111
112 #[inline]
118 pub fn keys(&self, context: &mut Context) -> JsResult<JsSetIterator> {
119 let iterator_object = Set::values(&self.inner.clone().into(), &[JsValue::null()], context)?
120 .get_iterator(IteratorHint::Sync, context)?;
121
122 JsSetIterator::from_object(iterator_object.iterator().clone())
123 }
124
125 #[inline]
131 pub fn for_each(
132 &self,
133 callback: JsFunction,
134 this_arg: JsValue,
135 context: &mut Context,
136 ) -> JsResult<JsValue> {
137 Set::for_each(
138 &self.inner.clone().into(),
139 &[callback.into(), this_arg],
140 context,
141 )
142 }
143
144 #[inline]
146 pub fn for_each_native<F>(&self, f: F) -> JsResult<()>
147 where
148 F: FnMut(JsValue) -> JsResult<()>,
149 {
150 let this = self.inner.clone().into();
151 Set::for_each_native(&this, f)
152 }
153
154 #[inline]
156 pub fn from_object(object: JsObject) -> JsResult<Self> {
157 if object.is::<OrderedSet>() {
158 Ok(Self { inner: object })
159 } else {
160 Err(JsNativeError::typ()
161 .with_message("Object is not a Set")
162 .into())
163 }
164 }
165
166 pub fn from_iter<I>(elements: I, context: &mut Context) -> Self
168 where
169 I: IntoIterator<Item = JsValue>,
170 {
171 let inner = Set::create_set_from_list(elements, context);
172 Self { inner }
173 }
174}
175
176impl From<JsSet> for JsObject {
177 #[inline]
178 fn from(o: JsSet) -> Self {
179 o.inner.clone()
180 }
181}
182
183impl From<JsSet> for JsValue {
184 #[inline]
185 fn from(o: JsSet) -> Self {
186 o.inner.clone().into()
187 }
188}
189
190impl Deref for JsSet {
191 type Target = JsObject;
192 #[inline]
193 fn deref(&self) -> &Self::Target {
194 &self.inner
195 }
196}
197
198impl TryFromJs for JsSet {
199 fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
200 if let Some(o) = value.as_object() {
201 Self::from_object(o.clone())
202 } else {
203 Err(JsNativeError::typ()
204 .with_message("value is not a Set object")
205 .into())
206 }
207 }
208}