boa/builtins/iterable/
mod.rs1use crate::{
2 builtins::{
3 regexp::regexp_string_iterator::RegExpStringIterator,
4 string::string_iterator::StringIterator, ArrayIterator, ForInIterator, MapIterator,
5 SetIterator,
6 },
7 object::{JsObject, ObjectInitializer},
8 symbol::WellKnownSymbols,
9 BoaProfiler, Context, JsResult, JsValue,
10};
11
12#[derive(Debug, Default)]
13pub struct IteratorPrototypes {
14 iterator_prototype: JsObject,
15 array_iterator: JsObject,
16 set_iterator: JsObject,
17 string_iterator: JsObject,
18 regexp_string_iterator: JsObject,
19 map_iterator: JsObject,
20 for_in_iterator: JsObject,
21}
22
23impl IteratorPrototypes {
24 pub(crate) fn init(context: &mut Context) -> Self {
25 let iterator_prototype = create_iterator_prototype(context);
26 Self {
27 array_iterator: ArrayIterator::create_prototype(
28 iterator_prototype.clone().into(),
29 context,
30 ),
31 set_iterator: SetIterator::create_prototype(iterator_prototype.clone().into(), context),
32 string_iterator: StringIterator::create_prototype(
33 iterator_prototype.clone().into(),
34 context,
35 ),
36 regexp_string_iterator: RegExpStringIterator::create_prototype(
37 iterator_prototype.clone().into(),
38 context,
39 ),
40 map_iterator: MapIterator::create_prototype(iterator_prototype.clone().into(), context),
41 for_in_iterator: ForInIterator::create_prototype(
42 iterator_prototype.clone().into(),
43 context,
44 ),
45 iterator_prototype,
46 }
47 }
48
49 #[inline]
50 pub fn array_iterator(&self) -> JsObject {
51 self.array_iterator.clone()
52 }
53
54 #[inline]
55 pub fn iterator_prototype(&self) -> JsObject {
56 self.iterator_prototype.clone()
57 }
58
59 #[inline]
60 pub fn set_iterator(&self) -> JsObject {
61 self.set_iterator.clone()
62 }
63
64 #[inline]
65 pub fn string_iterator(&self) -> JsObject {
66 self.string_iterator.clone()
67 }
68
69 #[inline]
70 pub fn regexp_string_iterator(&self) -> JsObject {
71 self.regexp_string_iterator.clone()
72 }
73
74 #[inline]
75 pub fn map_iterator(&self) -> JsObject {
76 self.map_iterator.clone()
77 }
78
79 #[inline]
80 pub fn for_in_iterator(&self) -> JsObject {
81 self.for_in_iterator.clone()
82 }
83}
84
85pub fn create_iter_result_object(value: JsValue, done: bool, context: &mut Context) -> JsValue {
89 let obj = context.construct_object();
92
93 obj.create_data_property_or_throw("value", value, context)
95 .unwrap();
96 obj.create_data_property_or_throw("done", done, context)
98 .unwrap();
99 obj.into()
101}
102
103pub fn get_iterator(iterable: &JsValue, context: &mut Context) -> JsResult<IteratorRecord> {
105 let iterator_function = iterable.get_field(WellKnownSymbols::iterator(), context)?;
106 if iterator_function.is_null_or_undefined() {
107 return Err(context.construct_type_error("Not an iterable"));
108 }
109 let iterator_object = context.call(&iterator_function, iterable, &[])?;
110 let next_function = iterator_object.get_field("next", context)?;
111 if next_function.is_null_or_undefined() {
112 return Err(context.construct_type_error("Could not find property `next`"));
113 }
114 Ok(IteratorRecord::new(iterator_object, next_function))
115}
116
117fn create_iterator_prototype(context: &mut Context) -> JsObject {
124 let _timer = BoaProfiler::global().start_event("Iterator Prototype", "init");
125
126 let symbol_iterator = WellKnownSymbols::iterator();
127 let iterator_prototype = ObjectInitializer::new(context)
128 .function(
129 |v, _, _| Ok(v.clone()),
130 (symbol_iterator, "[Symbol.iterator]"),
131 0,
132 )
133 .build();
134 iterator_prototype
135}
136
137#[derive(Debug)]
138pub struct IteratorRecord {
139 iterator_object: JsValue,
140 next_function: JsValue,
141}
142
143impl IteratorRecord {
144 pub fn new(iterator_object: JsValue, next_function: JsValue) -> Self {
145 Self {
146 iterator_object,
147 next_function,
148 }
149 }
150
151 pub(crate) fn next(&self, context: &mut Context) -> JsResult<IteratorResult> {
158 let next = context.call(&self.next_function, &self.iterator_object, &[])?;
159 let done = next.get_field("done", context)?.to_boolean();
160
161 let value = next.get_field("value", context)?;
162 Ok(IteratorResult { value, done })
163 }
164
165 pub(crate) fn close(
172 &self,
173 completion: JsResult<JsValue>,
174 context: &mut Context,
175 ) -> JsResult<JsValue> {
176 let mut inner_result = self.iterator_object.get_field("return", context);
177
178 if let Ok(inner_value) = inner_result {
180 if inner_value.is_undefined() {
182 return completion;
183 }
184 inner_result = context.call(&inner_value, &self.iterator_object, &[]);
186 }
187
188 let completion = completion?;
190
191 let inner_result = inner_result?;
193
194 if !inner_result.is_object() {
196 return context.throw_type_error("`return` method of iterator didn't return an Object");
197 }
198
199 Ok(completion)
201 }
202}
203
204#[derive(Debug)]
205pub struct IteratorResult {
206 pub value: JsValue,
207 pub done: bool,
208}