1use crate::host::HostFunction;
2use crate::object::function::JSFunction;
3use crate::object::object::JSObject;
4use crate::runtime::context::JSContext;
5use crate::value::JSValue;
6
7fn create_builtin_function(ctx: &mut JSContext, name: &str) -> JSValue {
8 let mut func = JSFunction::new_builtin(ctx.intern(name), 1);
9 func.set_builtin_marker(ctx, name);
10 let ptr = Box::into_raw(Box::new(func)) as usize;
11 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
12 JSValue::new_function(ptr)
13}
14
15fn map_size(ctx: &mut JSContext, obj: &JSObject) -> usize {
16 let size_atom = ctx.intern("__map_size__");
17 obj.get(size_atom)
18 .map(|v| if v.is_int() { v.get_int() as usize } else { 0 })
19 .unwrap_or(0)
20}
21
22fn map_key_atom(ctx: &mut JSContext, i: usize) -> crate::runtime::atom::Atom {
23 ctx.intern(&format!("__mk_{}__", i))
24}
25
26fn map_val_atom(ctx: &mut JSContext, i: usize) -> crate::runtime::atom::Atom {
27 ctx.intern(&format!("__mv_{}__", i))
28}
29
30fn map_find(ctx: &mut JSContext, obj: &JSObject, search_key: &JSValue) -> Option<usize> {
31 let size = map_size(ctx, obj);
32 for i in 0..size {
33 let k_atom = map_key_atom(ctx, i);
34 if let Some(k) = obj.get(k_atom) {
35 if k.strict_eq(search_key) {
36 return Some(i);
37 }
38 }
39 }
40 None
41}
42
43fn set_size(ctx: &mut JSContext, obj: &JSObject) -> usize {
44 let size_atom = ctx.intern("__set_size__");
45 obj.get(size_atom)
46 .map(|v| if v.is_int() { v.get_int() as usize } else { 0 })
47 .unwrap_or(0)
48}
49
50fn set_val_atom(ctx: &mut JSContext, i: usize) -> crate::runtime::atom::Atom {
51 ctx.intern(&format!("__sv_{}__", i))
52}
53
54fn set_find(ctx: &mut JSContext, obj: &JSObject, search: &JSValue) -> Option<usize> {
55 let size = set_size(ctx, obj);
56 for i in 0..size {
57 let v_atom = set_val_atom(ctx, i);
58 if let Some(v) = obj.get(v_atom) {
59 if v.strict_eq(search) {
60 return Some(i);
61 }
62 }
63 }
64 None
65}
66
67fn call_callback(
68 ctx: &mut JSContext,
69 callback: JSValue,
70 args: &[JSValue],
71) -> Result<JSValue, String> {
72 if let Some(ptr) = ctx.get_register_vm_ptr() {
73 let vm = unsafe { &mut *(ptr as *mut crate::runtime::vm::VM) };
74 vm.call_function(ctx, callback, args)
75 } else {
76 Err("call_callback: VM not available".to_string())
77 }
78}
79
80fn make_array(ctx: &mut JSContext, items: Vec<JSValue>) -> JSValue {
81 let mut arr = JSObject::new_array();
82 if let Some(proto_ptr) = ctx.get_array_prototype() {
83 arr.prototype = Some(proto_ptr);
84 }
85 let len = items.len();
86 for (i, v) in items.into_iter().enumerate() {
87 let key = ctx.intern(&i.to_string());
88 arr.set(key, v);
89 }
90 arr.set(ctx.common_atoms.length, JSValue::new_int(len as i64));
91 JSValue::new_object(Box::into_raw(Box::new(arr)) as usize)
92}
93
94pub fn map_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
95 let mut obj = JSObject::new();
96
97 if let Some(proto_ptr) = ctx.get_map_prototype() {
98 obj.prototype = Some(proto_ptr);
99 }
100
101 let size_atom = ctx.intern("__map_size__");
102 obj.set(size_atom, JSValue::new_int(0));
103
104 if let Some(iterable) = args.first() {
105 if iterable.is_object() {
106 let iter_obj = iterable.as_object();
107 let len_atom = ctx.common_atoms.length;
108 let len = iter_obj
109 .get(len_atom)
110 .map(|v| if v.is_int() { v.get_int() as usize } else { 0 })
111 .unwrap_or(0);
112
113 for i in 0..len {
114 let idx_atom = ctx.intern(&i.to_string());
115 if let Some(pair) = iter_obj.get(idx_atom) {
116 if pair.is_object() {
117 let pair_obj = pair.as_object();
118
119 let k_atom = ctx.intern("0");
120 let v_atom = ctx.intern("1");
121 let k = pair_obj.get(k_atom).unwrap_or_else(JSValue::undefined);
122 let v = pair_obj.get(v_atom).unwrap_or_else(JSValue::undefined);
123
124 let cur_size = map_size(ctx, &obj);
125
126 if let Some(idx) = map_find(ctx, &obj, &k) {
127 let mv_atom = map_val_atom(ctx, idx);
128 obj.set(mv_atom, v);
129 } else {
130 let mk_atom = map_key_atom(ctx, cur_size);
131 let mv_atom = map_val_atom(ctx, cur_size);
132 obj.set(mk_atom, k);
133 obj.set(mv_atom, v);
134 obj.set(size_atom, JSValue::new_int((cur_size + 1) as i64));
135 }
136 }
137 }
138 }
139 }
140 }
141
142 let size_val = obj.get(size_atom).unwrap_or(JSValue::new_int(0));
143 let size_prop_atom = ctx.intern("size");
144 obj.set(size_prop_atom, size_val);
145
146 JSValue::new_object(Box::into_raw(Box::new(obj)) as usize)
147}
148
149fn sync_map_size(ctx: &mut JSContext, obj: &mut JSObject) {
150 let size_atom = ctx.intern("__map_size__");
151 let size_prop_atom = ctx.intern("size");
152 let size_val = obj.get(size_atom).unwrap_or(JSValue::new_int(0));
153 obj.set(size_prop_atom, size_val);
154}
155
156fn map_set(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
157 if args.len() < 3 {
158 return if args.is_empty() {
159 JSValue::undefined()
160 } else {
161 args[0]
162 };
163 }
164 let this = args[0];
165 if !this.is_object() {
166 return this;
167 }
168 let key = args[1];
169 let value = args[2];
170
171 let obj = this.as_object_mut();
172
173 let size_atom = ctx.intern("__map_size__");
174
175 if let Some(idx) = map_find(ctx, obj, &key) {
176 let mv_atom = map_val_atom(ctx, idx);
177 obj.set(mv_atom, value);
178 } else {
179 let cur_size = map_size(ctx, obj);
180 let mk_atom = map_key_atom(ctx, cur_size);
181 let mv_atom = map_val_atom(ctx, cur_size);
182 obj.set(mk_atom, key);
183 obj.set(mv_atom, value);
184 obj.set(size_atom, JSValue::new_int((cur_size + 1) as i64));
185 }
186
187 sync_map_size(ctx, obj);
188 this
189}
190
191fn map_get(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
192 if args.len() < 2 {
193 return JSValue::undefined();
194 }
195 let this = args[0];
196 if !this.is_object() {
197 return JSValue::undefined();
198 }
199 let key = args[1];
200 let obj = this.as_object();
201
202 if let Some(idx) = map_find(ctx, obj, &key) {
203 let mv_atom = map_val_atom(ctx, idx);
204 obj.get(mv_atom).unwrap_or_else(JSValue::undefined)
205 } else {
206 JSValue::undefined()
207 }
208}
209
210fn map_has(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
211 if args.len() < 2 {
212 return JSValue::bool(false);
213 }
214 let this = args[0];
215 if !this.is_object() {
216 return JSValue::bool(false);
217 }
218 let key = args[1];
219 let obj = this.as_object();
220 JSValue::bool(map_find(ctx, obj, &key).is_some())
221}
222
223fn map_delete(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
224 if args.len() < 2 {
225 return JSValue::bool(false);
226 }
227 let this = args[0];
228 if !this.is_object() {
229 return JSValue::bool(false);
230 }
231 let key = args[1];
232 let obj = this.as_object_mut();
233
234 let size = map_size(ctx, obj);
235 let idx = match map_find(ctx, obj, &key) {
236 Some(i) => i,
237 None => return JSValue::bool(false),
238 };
239
240 for i in idx..(size - 1) {
241 let mk_next = map_key_atom(ctx, i + 1);
242 let mv_next = map_val_atom(ctx, i + 1);
243 let mk_cur = map_key_atom(ctx, i);
244 let mv_cur = map_val_atom(ctx, i);
245 let k = obj.get(mk_next).unwrap_or_else(JSValue::undefined);
246 let v = obj.get(mv_next).unwrap_or_else(JSValue::undefined);
247 obj.set(mk_cur, k);
248 obj.set(mv_cur, v);
249 }
250
251 let mk_last = map_key_atom(ctx, size - 1);
252 let mv_last = map_val_atom(ctx, size - 1);
253 obj.delete(mk_last);
254 obj.delete(mv_last);
255
256 let size_atom = ctx.intern("__map_size__");
257 obj.set(size_atom, JSValue::new_int((size - 1) as i64));
258 sync_map_size(ctx, obj);
259 JSValue::bool(true)
260}
261
262fn map_clear(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
263 if args.is_empty() {
264 return JSValue::undefined();
265 }
266 let this = args[0];
267 if !this.is_object() {
268 return JSValue::undefined();
269 }
270 let obj = this.as_object_mut();
271
272 let size = map_size(ctx, obj);
273 for i in 0..size {
274 let mk = map_key_atom(ctx, i);
275 let mv = map_val_atom(ctx, i);
276 obj.delete(mk);
277 obj.delete(mv);
278 }
279 let size_atom = ctx.intern("__map_size__");
280 obj.set(size_atom, JSValue::new_int(0));
281 sync_map_size(ctx, obj);
282 JSValue::undefined()
283}
284
285fn map_for_each(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
286 if args.len() < 2 {
287 return JSValue::undefined();
288 }
289 let this = args[0];
290 let callback = args[1];
291 if !this.is_object() || !callback.is_function() {
292 return JSValue::undefined();
293 }
294
295 let obj = this.as_object();
296 let size = map_size(ctx, obj);
297
298 for i in 0..size {
299 let mk_atom = map_key_atom(ctx, i);
300 let mv_atom = map_val_atom(ctx, i);
301 let k = obj.get(mk_atom).unwrap_or_else(JSValue::undefined);
302 let v = obj.get(mv_atom).unwrap_or_else(JSValue::undefined);
303 let _ = call_callback(ctx, callback, &[v, k, this]);
304 }
305
306 JSValue::undefined()
307}
308
309fn map_keys(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
310 if args.is_empty() {
311 return make_array(ctx, vec![]);
312 }
313 let this = args[0];
314 if !this.is_object() {
315 return make_array(ctx, vec![]);
316 }
317 let obj = this.as_object();
318 let size = map_size(ctx, obj);
319
320 let mut keys = Vec::with_capacity(size);
321 for i in 0..size {
322 let mk_atom = map_key_atom(ctx, i);
323 keys.push(obj.get(mk_atom).unwrap_or_else(JSValue::undefined));
324 }
325 make_array(ctx, keys)
326}
327
328fn map_values(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
329 if args.is_empty() {
330 return make_array(ctx, vec![]);
331 }
332 let this = args[0];
333 if !this.is_object() {
334 return make_array(ctx, vec![]);
335 }
336 let obj = this.as_object();
337 let size = map_size(ctx, obj);
338
339 let mut vals = Vec::with_capacity(size);
340 for i in 0..size {
341 let mv_atom = map_val_atom(ctx, i);
342 vals.push(obj.get(mv_atom).unwrap_or_else(JSValue::undefined));
343 }
344 make_array(ctx, vals)
345}
346
347fn map_entries(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
348 if args.is_empty() {
349 return make_array(ctx, vec![]);
350 }
351 let this = args[0];
352 if !this.is_object() {
353 return make_array(ctx, vec![]);
354 }
355 let obj = this.as_object();
356 let size = map_size(ctx, obj);
357
358 let mut entries = Vec::with_capacity(size);
359 for i in 0..size {
360 let mk_atom = map_key_atom(ctx, i);
361 let mv_atom = map_val_atom(ctx, i);
362 let k = obj.get(mk_atom).unwrap_or_else(JSValue::undefined);
363 let v = obj.get(mv_atom).unwrap_or_else(JSValue::undefined);
364 let pair = make_array(ctx, vec![k, v]);
365 entries.push(pair);
366 }
367 make_array(ctx, entries)
368}
369
370fn map_symbol_iterator(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
371 map_entries(ctx, args)
372}
373
374fn set_symbol_iterator(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
375 set_values(ctx, args)
376}
377
378fn weakmap_constructor(ctx: &mut JSContext, _args: &[JSValue]) -> JSValue {
379 let mut obj = JSObject::new();
380 if let Some(proto_ptr) = ctx.get_weakmap_prototype() {
381 obj.prototype = Some(proto_ptr);
382 }
383 let size_atom = ctx.intern("__weakmap_size__");
384 obj.set(size_atom, JSValue::new_int(0));
385 let ptr = Box::into_raw(Box::new(obj)) as usize;
386 JSValue::new_object(ptr)
387}
388
389fn weakmap_size(ctx: &mut JSContext, obj: &JSObject) -> usize {
390 let size_atom = ctx.intern("__weakmap_size__");
391 obj.get(size_atom)
392 .map(|v| if v.is_int() { v.get_int() as usize } else { 0 })
393 .unwrap_or(0)
394}
395
396fn weakmap_key_atom(ctx: &mut JSContext, i: usize) -> crate::runtime::atom::Atom {
397 ctx.intern(&format!("__wmk_{}__", i))
398}
399
400fn weakmap_val_atom(ctx: &mut JSContext, i: usize) -> crate::runtime::atom::Atom {
401 ctx.intern(&format!("__wmv_{}__", i))
402}
403
404fn weakmap_find(ctx: &mut JSContext, obj: &JSObject, search_key: &JSValue) -> Option<usize> {
405 let size = weakmap_size(ctx, obj);
406 for i in 0..size {
407 let k_atom = weakmap_key_atom(ctx, i);
408 if let Some(k) = obj.get(k_atom) {
409 if k.strict_eq(search_key) {
410 return Some(i);
411 }
412 }
413 }
414 None
415}
416
417fn weakmap_set(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
418 if args.len() < 3 {
419 return JSValue::undefined();
420 }
421 let this = &args[0];
422 let key = &args[1];
423 let value = &args[2];
424
425 if !key.is_object() && !key.is_symbol() {
426 return JSValue::undefined();
427 }
428
429 let obj = this.as_object_mut();
430
431 if let Some(idx) = weakmap_find(ctx, obj, key) {
432 let v_atom = weakmap_val_atom(ctx, idx);
433 obj.set(v_atom, value.clone());
434 } else {
435 let size_atom = ctx.intern("__weakmap_size__");
436 let size = weakmap_size(ctx, obj);
437 let k_atom = weakmap_key_atom(ctx, size);
438 let v_atom = weakmap_val_atom(ctx, size);
439 obj.set(k_atom, key.clone());
440 obj.set(v_atom, value.clone());
441 obj.set(size_atom, JSValue::new_int((size + 1) as i64));
442 }
443 this.clone()
444}
445
446fn weakmap_get(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
447 if args.len() < 2 {
448 return JSValue::undefined();
449 }
450 let this = &args[0];
451 let key = &args[1];
452
453 if !this.is_object() {
454 return JSValue::undefined();
455 }
456 let obj = this.as_object();
457
458 if let Some(idx) = weakmap_find(ctx, obj, key) {
459 let v_atom = weakmap_val_atom(ctx, idx);
460 obj.get(v_atom).unwrap_or_else(JSValue::undefined)
461 } else {
462 JSValue::undefined()
463 }
464}
465
466fn weakmap_has(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
467 if args.len() < 2 {
468 return JSValue::bool(false);
469 }
470 let this = &args[0];
471 let key = &args[1];
472
473 if !this.is_object() {
474 return JSValue::bool(false);
475 }
476 let obj = this.as_object();
477
478 JSValue::bool(weakmap_find(ctx, obj, key).is_some())
479}
480
481fn weakmap_delete(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
482 if args.len() < 2 {
483 return JSValue::bool(false);
484 }
485 let this = &args[0];
486 let key = &args[1];
487
488 if !this.is_object() {
489 return JSValue::bool(false);
490 }
491 let obj = this.as_object_mut();
492
493 if let Some(idx) = weakmap_find(ctx, obj, key) {
494 let k_atom = weakmap_key_atom(ctx, idx);
495 let v_atom = weakmap_val_atom(ctx, idx);
496 obj.delete(k_atom);
497 obj.delete(v_atom);
498 JSValue::bool(true)
499 } else {
500 JSValue::bool(false)
501 }
502}
503
504fn weakset_constructor(ctx: &mut JSContext, _args: &[JSValue]) -> JSValue {
505 let mut obj = JSObject::new();
506 if let Some(proto_ptr) = ctx.get_weakset_prototype() {
507 obj.prototype = Some(proto_ptr);
508 }
509 let size_atom = ctx.intern("__weakset_size__");
510 obj.set(size_atom, JSValue::new_int(0));
511 let ptr = Box::into_raw(Box::new(obj)) as usize;
512 JSValue::new_object(ptr)
513}
514
515fn weakset_size(ctx: &mut JSContext, obj: &JSObject) -> usize {
516 let size_atom = ctx.intern("__weakset_size__");
517 obj.get(size_atom)
518 .map(|v| if v.is_int() { v.get_int() as usize } else { 0 })
519 .unwrap_or(0)
520}
521
522fn weakset_val_atom(ctx: &mut JSContext, i: usize) -> crate::runtime::atom::Atom {
523 ctx.intern(&format!("__wsv_{}__", i))
524}
525
526fn weakset_find(ctx: &mut JSContext, obj: &JSObject, search: &JSValue) -> Option<usize> {
527 let size = weakset_size(ctx, obj);
528 for i in 0..size {
529 let v_atom = weakset_val_atom(ctx, i);
530 if let Some(v) = obj.get(v_atom) {
531 if v.strict_eq(search) {
532 return Some(i);
533 }
534 }
535 }
536 None
537}
538
539fn weakset_add(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
540 if args.len() < 2 {
541 return JSValue::undefined();
542 }
543 let this = &args[0];
544 let value = &args[1];
545
546 if !value.is_object() && !value.is_symbol() {
547 return JSValue::undefined();
548 }
549
550 let obj = this.as_object_mut();
551
552 if weakset_find(ctx, obj, value).is_none() {
553 let size_atom = ctx.intern("__weakset_size__");
554 let size = weakset_size(ctx, obj);
555 let v_atom = weakset_val_atom(ctx, size);
556 obj.set(v_atom, value.clone());
557 obj.set(size_atom, JSValue::new_int((size + 1) as i64));
558 }
559 this.clone()
560}
561
562fn weakset_has(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
563 if args.len() < 2 {
564 return JSValue::bool(false);
565 }
566 let this = &args[0];
567 let value = &args[1];
568
569 if !this.is_object() {
570 return JSValue::bool(false);
571 }
572 let obj = this.as_object();
573
574 JSValue::bool(weakset_find(ctx, obj, value).is_some())
575}
576
577fn weakset_delete(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
578 if args.len() < 2 {
579 return JSValue::bool(false);
580 }
581 let this = &args[0];
582 let value = &args[1];
583
584 if !this.is_object() {
585 return JSValue::bool(false);
586 }
587 let obj = this.as_object_mut();
588
589 if let Some(idx) = weakset_find(ctx, obj, value) {
590 let v_atom = weakset_val_atom(ctx, idx);
591 obj.delete(v_atom);
592 JSValue::bool(true)
593 } else {
594 JSValue::bool(false)
595 }
596}
597
598pub fn set_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
599 let mut obj = JSObject::new();
600
601 if let Some(proto_ptr) = ctx.get_set_prototype() {
602 obj.prototype = Some(proto_ptr);
603 }
604
605 let size_atom = ctx.intern("__set_size__");
606 obj.set(size_atom, JSValue::new_int(0));
607
608 if let Some(iterable) = args.first() {
609 if iterable.is_object() {
610 let iter_obj = iterable.as_object();
611 let len_atom = ctx.common_atoms.length;
612 let len = iter_obj
613 .get(len_atom)
614 .map(|v| if v.is_int() { v.get_int() as usize } else { 0 })
615 .unwrap_or(0);
616
617 for i in 0..len {
618 let idx_atom = ctx.intern(&i.to_string());
619 if let Some(val) = iter_obj.get(idx_atom) {
620 let cur_size = set_size(ctx, &obj);
621 if set_find(ctx, &obj, &val).is_none() {
622 let sv_atom = set_val_atom(ctx, cur_size);
623 obj.set(sv_atom, val);
624 obj.set(size_atom, JSValue::new_int((cur_size + 1) as i64));
625 }
626 }
627 }
628 }
629 }
630
631 let size_val = obj.get(size_atom).unwrap_or(JSValue::new_int(0));
632 let size_prop_atom = ctx.intern("size");
633 obj.set(size_prop_atom, size_val);
634
635 JSValue::new_object(Box::into_raw(Box::new(obj)) as usize)
636}
637
638fn sync_set_size(ctx: &mut JSContext, obj: &mut JSObject) {
639 let size_atom = ctx.intern("__set_size__");
640 let size_prop_atom = ctx.intern("size");
641 let size_val = obj.get(size_atom).unwrap_or(JSValue::new_int(0));
642 obj.set(size_prop_atom, size_val);
643}
644
645fn set_add(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
646 if args.len() < 2 {
647 return if args.is_empty() {
648 JSValue::undefined()
649 } else {
650 args[0]
651 };
652 }
653 let this = args[0];
654 if !this.is_object() {
655 return this;
656 }
657 let value = args[1];
658
659 let obj = this.as_object_mut();
660
661 if set_find(ctx, obj, &value).is_none() {
662 let size_atom = ctx.intern("__set_size__");
663 let cur_size = set_size(ctx, obj);
664 let sv_atom = set_val_atom(ctx, cur_size);
665 obj.set(sv_atom, value);
666 obj.set(size_atom, JSValue::new_int((cur_size + 1) as i64));
667 sync_set_size(ctx, obj);
668 }
669
670 this
671}
672
673fn set_has(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
674 if args.len() < 2 {
675 return JSValue::bool(false);
676 }
677 let this = args[0];
678 if !this.is_object() {
679 return JSValue::bool(false);
680 }
681 let value = args[1];
682 let obj = this.as_object();
683 JSValue::bool(set_find(ctx, obj, &value).is_some())
684}
685
686fn set_delete(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
687 if args.len() < 2 {
688 return JSValue::bool(false);
689 }
690 let this = args[0];
691 if !this.is_object() {
692 return JSValue::bool(false);
693 }
694 let value = args[1];
695 let obj = this.as_object_mut();
696
697 let size = set_size(ctx, obj);
698 let idx = match set_find(ctx, obj, &value) {
699 Some(i) => i,
700 None => return JSValue::bool(false),
701 };
702
703 for i in idx..(size - 1) {
704 let sv_next = set_val_atom(ctx, i + 1);
705 let sv_cur = set_val_atom(ctx, i);
706 let v = obj.get(sv_next).unwrap_or_else(JSValue::undefined);
707 obj.set(sv_cur, v);
708 }
709
710 let sv_last = set_val_atom(ctx, size - 1);
711 obj.delete(sv_last);
712
713 let size_atom = ctx.intern("__set_size__");
714 obj.set(size_atom, JSValue::new_int((size - 1) as i64));
715 sync_set_size(ctx, obj);
716 JSValue::bool(true)
717}
718
719fn set_clear(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
720 if args.is_empty() {
721 return JSValue::undefined();
722 }
723 let this = args[0];
724 if !this.is_object() {
725 return JSValue::undefined();
726 }
727 let obj = this.as_object_mut();
728
729 let size = set_size(ctx, obj);
730 for i in 0..size {
731 let sv = set_val_atom(ctx, i);
732 obj.delete(sv);
733 }
734 let size_atom = ctx.intern("__set_size__");
735 obj.set(size_atom, JSValue::new_int(0));
736 sync_set_size(ctx, obj);
737 JSValue::undefined()
738}
739
740fn set_for_each(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
741 if args.len() < 2 {
742 return JSValue::undefined();
743 }
744 let this = args[0];
745 let callback = args[1];
746 if !this.is_object() || !callback.is_function() {
747 return JSValue::undefined();
748 }
749
750 let obj = this.as_object();
751 let size = set_size(ctx, obj);
752
753 for i in 0..size {
754 let sv_atom = set_val_atom(ctx, i);
755 let v = obj.get(sv_atom).unwrap_or_else(JSValue::undefined);
756
757 let _ = call_callback(ctx, callback, &[v, v, this]);
758 }
759
760 JSValue::undefined()
761}
762
763fn set_values(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
764 if args.is_empty() {
765 return make_array(ctx, vec![]);
766 }
767 let this = args[0];
768 if !this.is_object() {
769 return make_array(ctx, vec![]);
770 }
771 let obj = this.as_object();
772 let size = set_size(ctx, obj);
773
774 let mut vals = Vec::with_capacity(size);
775 for i in 0..size {
776 let sv_atom = set_val_atom(ctx, i);
777 vals.push(obj.get(sv_atom).unwrap_or_else(JSValue::undefined));
778 }
779 make_array(ctx, vals)
780}
781
782fn set_keys(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
783 set_values(ctx, args)
784}
785
786fn set_entries(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
787 if args.is_empty() {
788 return make_array(ctx, vec![]);
789 }
790 let this = args[0];
791 if !this.is_object() {
792 return make_array(ctx, vec![]);
793 }
794 let obj = this.as_object();
795 let size = set_size(ctx, obj);
796
797 let mut entries = Vec::with_capacity(size);
798 for i in 0..size {
799 let sv_atom = set_val_atom(ctx, i);
800 let v = obj.get(sv_atom).unwrap_or_else(JSValue::undefined);
801 let pair = make_array(ctx, vec![v, v]);
802 entries.push(pair);
803 }
804 make_array(ctx, entries)
805}
806
807pub fn init_map_set(ctx: &mut JSContext) {
808 let mut map_proto = JSObject::new();
809 map_proto.set(ctx.intern("set"), create_builtin_function(ctx, "map_set"));
810 map_proto.set(ctx.intern("get"), create_builtin_function(ctx, "map_get"));
811 map_proto.set(ctx.intern("has"), create_builtin_function(ctx, "map_has"));
812 map_proto.set(
813 ctx.intern("delete"),
814 create_builtin_function(ctx, "map_delete"),
815 );
816 map_proto.set(
817 ctx.intern("clear"),
818 create_builtin_function(ctx, "map_clear"),
819 );
820 map_proto.set(
821 ctx.intern("forEach"),
822 create_builtin_function(ctx, "map_forEach"),
823 );
824 map_proto.set(ctx.intern("keys"), create_builtin_function(ctx, "map_keys"));
825 map_proto.set(
826 ctx.intern("values"),
827 create_builtin_function(ctx, "map_values"),
828 );
829 map_proto.set(
830 ctx.intern("entries"),
831 create_builtin_function(ctx, "map_entries"),
832 );
833
834 let sym_iter_atom = crate::builtins::symbol::get_symbol_iterator_atom(ctx);
835 map_proto.set(
836 sym_iter_atom,
837 create_builtin_function(ctx, "map_symbol_iterator"),
838 );
839
840 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
841 map_proto.prototype = Some(obj_proto_ptr);
842 }
843
844 let map_proto_ptr = Box::into_raw(Box::new(map_proto)) as usize;
845 ctx.runtime_mut().gc_heap_mut().track(map_proto_ptr);
846 ctx.set_map_prototype(map_proto_ptr);
847
848 let map_ctor = create_builtin_function(ctx, "map_constructor");
849 let map_atom = ctx.intern("Map");
850 let global = ctx.global();
851 if global.is_object() {
852 let global_obj = global.as_object_mut();
853 global_obj.set(map_atom, map_ctor);
854 }
855
856 let mut set_proto = JSObject::new();
857 set_proto.set(ctx.intern("add"), create_builtin_function(ctx, "set_add"));
858 set_proto.set(ctx.intern("has"), create_builtin_function(ctx, "set_has"));
859 set_proto.set(
860 ctx.intern("delete"),
861 create_builtin_function(ctx, "set_delete"),
862 );
863 set_proto.set(
864 ctx.intern("clear"),
865 create_builtin_function(ctx, "set_clear"),
866 );
867 set_proto.set(
868 ctx.intern("forEach"),
869 create_builtin_function(ctx, "set_forEach"),
870 );
871 set_proto.set(
872 ctx.intern("values"),
873 create_builtin_function(ctx, "set_values"),
874 );
875 set_proto.set(ctx.intern("keys"), create_builtin_function(ctx, "set_keys"));
876 set_proto.set(
877 ctx.intern("entries"),
878 create_builtin_function(ctx, "set_entries"),
879 );
880
881 let sym_iter_atom = crate::builtins::symbol::get_symbol_iterator_atom(ctx);
882 set_proto.set(
883 sym_iter_atom,
884 create_builtin_function(ctx, "set_symbol_iterator"),
885 );
886
887 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
888 set_proto.prototype = Some(obj_proto_ptr);
889 }
890
891 let set_proto_ptr = Box::into_raw(Box::new(set_proto)) as usize;
892 ctx.runtime_mut().gc_heap_mut().track(set_proto_ptr);
893 ctx.set_set_prototype(set_proto_ptr);
894
895 let set_ctor = create_builtin_function(ctx, "set_constructor");
896 let set_atom = ctx.intern("Set");
897 let global = ctx.global();
898 if global.is_object() {
899 let global_obj = global.as_object_mut();
900 global_obj.set(set_atom, set_ctor);
901 }
902
903 let mut weakmap_proto = JSObject::new();
904 weakmap_proto.set(
905 ctx.intern("set"),
906 create_builtin_function(ctx, "weakmap_set"),
907 );
908 weakmap_proto.set(
909 ctx.intern("get"),
910 create_builtin_function(ctx, "weakmap_get"),
911 );
912 weakmap_proto.set(
913 ctx.intern("has"),
914 create_builtin_function(ctx, "weakmap_has"),
915 );
916 weakmap_proto.set(
917 ctx.intern("delete"),
918 create_builtin_function(ctx, "weakmap_delete"),
919 );
920
921 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
922 weakmap_proto.prototype = Some(obj_proto_ptr);
923 }
924
925 let weakmap_proto_ptr = Box::into_raw(Box::new(weakmap_proto)) as usize;
926 ctx.runtime_mut().gc_heap_mut().track(weakmap_proto_ptr);
927 ctx.set_weakmap_prototype(weakmap_proto_ptr);
928
929 let weakmap_ctor = create_builtin_function(ctx, "weakmap_constructor");
930 let weakmap_atom = ctx.intern("WeakMap");
931 if global.is_object() {
932 let global_obj = global.as_object_mut();
933 global_obj.set(weakmap_atom, weakmap_ctor);
934 }
935
936 let mut weakset_proto = JSObject::new();
937 weakset_proto.set(
938 ctx.intern("add"),
939 create_builtin_function(ctx, "weakset_add"),
940 );
941 weakset_proto.set(
942 ctx.intern("has"),
943 create_builtin_function(ctx, "weakset_has"),
944 );
945 weakset_proto.set(
946 ctx.intern("delete"),
947 create_builtin_function(ctx, "weakset_delete"),
948 );
949
950 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
951 weakset_proto.prototype = Some(obj_proto_ptr);
952 }
953
954 let weakset_proto_ptr = Box::into_raw(Box::new(weakset_proto)) as usize;
955 ctx.runtime_mut().gc_heap_mut().track(weakset_proto_ptr);
956 ctx.set_weakset_prototype(weakset_proto_ptr);
957
958 let weakset_ctor = create_builtin_function(ctx, "weakset_constructor");
959 let weakset_atom = ctx.intern("WeakSet");
960 if global.is_object() {
961 let global_obj = global.as_object_mut();
962 global_obj.set(weakset_atom, weakset_ctor);
963 }
964}
965
966pub fn register_builtins(ctx: &mut JSContext) {
967 ctx.register_builtin(
968 "map_constructor",
969 HostFunction::new("Map", 0, map_constructor),
970 );
971 ctx.register_builtin("map_set", HostFunction::new("set", 2, map_set));
972 ctx.register_builtin("map_get", HostFunction::new("get", 1, map_get));
973 ctx.register_builtin("map_has", HostFunction::new("has", 1, map_has));
974 ctx.register_builtin("map_delete", HostFunction::new("delete", 1, map_delete));
975 ctx.register_builtin("map_clear", HostFunction::new("clear", 0, map_clear));
976 ctx.register_builtin("map_forEach", HostFunction::new("forEach", 1, map_for_each));
977 ctx.register_builtin("map_keys", HostFunction::new("keys", 0, map_keys));
978 ctx.register_builtin("map_values", HostFunction::new("values", 0, map_values));
979 ctx.register_builtin("map_entries", HostFunction::new("entries", 0, map_entries));
980 ctx.register_builtin(
981 "map_symbol_iterator",
982 HostFunction::new("[Symbol.iterator]", 0, map_symbol_iterator),
983 );
984
985 ctx.register_builtin(
986 "set_constructor",
987 HostFunction::new("Set", 0, set_constructor),
988 );
989 ctx.register_builtin("set_add", HostFunction::new("add", 1, set_add));
990 ctx.register_builtin("set_has", HostFunction::new("has", 1, set_has));
991 ctx.register_builtin("set_delete", HostFunction::new("delete", 1, set_delete));
992 ctx.register_builtin("set_clear", HostFunction::new("clear", 0, set_clear));
993 ctx.register_builtin("set_forEach", HostFunction::new("forEach", 1, set_for_each));
994 ctx.register_builtin("set_values", HostFunction::new("values", 0, set_values));
995 ctx.register_builtin("set_keys", HostFunction::new("keys", 0, set_keys));
996 ctx.register_builtin("set_entries", HostFunction::new("entries", 0, set_entries));
997 ctx.register_builtin(
998 "set_symbol_iterator",
999 HostFunction::new("[Symbol.iterator]", 0, set_symbol_iterator),
1000 );
1001
1002 ctx.register_builtin(
1003 "weakmap_constructor",
1004 HostFunction::new("WeakMap", 0, weakmap_constructor),
1005 );
1006 ctx.register_builtin("weakmap_set", HostFunction::new("set", 2, weakmap_set));
1007 ctx.register_builtin("weakmap_get", HostFunction::new("get", 1, weakmap_get));
1008 ctx.register_builtin("weakmap_has", HostFunction::new("has", 1, weakmap_has));
1009 ctx.register_builtin(
1010 "weakmap_delete",
1011 HostFunction::new("delete", 1, weakmap_delete),
1012 );
1013
1014 ctx.register_builtin(
1015 "weakset_constructor",
1016 HostFunction::new("WeakSet", 0, weakset_constructor),
1017 );
1018 ctx.register_builtin("weakset_add", HostFunction::new("add", 1, weakset_add));
1019 ctx.register_builtin("weakset_has", HostFunction::new("has", 1, weakset_has));
1020 ctx.register_builtin(
1021 "weakset_delete",
1022 HostFunction::new("delete", 1, weakset_delete),
1023 );
1024}