1use std::cell::{Cell, RefCell};
15use std::ops::{Deref, DerefMut};
16use std::ptr;
17use std::rc::Rc;
18
19use dom_struct::dom_struct;
20use js::context::JSContext;
21use js::conversions::{ConversionResult, FromJSValConvertibleRc, ToJSValConvertible};
22use js::gc::MutableHandleValue;
23use js::jsapi::{
24 CallArgs, GetFunctionNativeReserved, Heap, JS_GetFunctionObject, JSContext as RawJSContext,
25 JSObject, PromiseState, PromiseUserInputEventHandlingState, RemoveRawValueRoot,
26 SetFunctionNativeReserved,
27};
28use js::jsval::{Int32Value, JSVal, NullValue, ObjectValue, UndefinedValue};
29use js::realm::CurrentRealm;
30use js::rust::wrappers2::{
31 AddPromiseReactions, AddRawValueRoot, CallOriginalPromiseReject, CallOriginalPromiseResolve,
32 GetPromiseIsHandled, GetPromiseState, IsPromiseObject, JS_ClearPendingException,
33 JS_NewFunction, NewFunctionWithReserved, NewPromiseObject, RejectPromise, ResolvePromise,
34 SetAnyPromiseIsHandled, SetPromiseUserInputEventHandlingState,
35};
36use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
37use script_bindings::interfaces::{
38 HeapTracedPromiseHelpers, PromiseHelpers, StackRootPromiseHelpers,
39};
40use script_bindings::reflector::{DomObject, MutDomObject, Reflector};
41use script_bindings::settings_stack::run_a_script;
42
43use crate::DomTypeHolder;
44use crate::dom::bindings::conversions::root_from_object;
45use crate::dom::bindings::error::{Error, ErrorToJsval};
46use crate::dom::bindings::refcounted::TrustedPromise;
47use crate::dom::bindings::reflector::DomGlobal;
48use crate::dom::bindings::root::{AsHandleValue, Dom};
49use crate::dom::globalscope::GlobalScope;
50use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
51use crate::event_loop::script_thread::ScriptThread;
52use crate::realms::enter_auto_realm;
53use crate::runtime::job_queue::MicrotaskRunnable;
54
55#[derive(Clone)]
61#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
62pub(crate) struct RootedPromise(Rc<(Promise, PermanentRoot)>);
63
64impl StackRootPromiseHelpers<crate::DomTypeHolder> for RootedPromise {
65 type HeapTraced = TracedPromise;
66 fn to_traced(&self) -> TracedPromise {
67 RootedPromise::to_traced(self)
68 }
69}
70
71impl Deref for RootedPromise {
72 type Target = Promise;
73 fn deref(&self) -> &Self::Target {
74 &self.0.0
75 }
76}
77
78impl RootedPromise {
79 pub(crate) fn to_traced(&self) -> TracedPromise {
81 TracedPromise(self.duplicate_unrooted())
82 }
83}
84
85impl From<&'_ RootedPromise> for TrustedPromise {
86 fn from(promise: &'_ RootedPromise) -> Self {
87 TrustedPromise::new(promise.duplicate_unrooted())
88 }
89}
90
91impl js::conversions::FromJSValConvertible for RootedPromise {
92 type Config = ();
93
94 fn from_jsval(
95 cx: &mut JSContext,
96 value: HandleValue,
97 _option: Self::Config,
98 ) -> Result<ConversionResult<Self>, ()> {
99 if value.get().is_null() {
100 return Ok(ConversionResult::Failure(c"null not allowed".into()));
101 }
102
103 let mut realm = CurrentRealm::assert(cx);
104 let global_scope = GlobalScope::from_current_realm(&mut realm);
105
106 let promise = Promise::new_resolved_rooted(cx, &global_scope, value);
107 Ok(ConversionResult::Success(promise))
108 }
109}
110
111impl ToJSValConvertible for RootedPromise {
112 fn to_jsval(&self, cx: &mut JSContext, rval: MutableHandleValue<'_>) {
113 self.0.0.to_jsval(cx, rval)
114 }
115}
116
117#[derive(Clone, MallocSizeOf, JSTraceable)]
122#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
123pub(crate) struct TracedPromise(#[conditional_malloc_size_of] Rc<Promise>);
124
125impl std::cmp::PartialEq for TracedPromise {
126 fn eq(&self, other: &Self) -> bool {
127 *self.0 == **other
128 }
129}
130
131impl HeapTracedPromiseHelpers<crate::DomTypeHolder> for TracedPromise {
132 type StackRoot = RootedPromise;
133 fn root(&self, cx: &JSContext) -> RootedPromise {
134 TracedPromise::root(self, cx)
135 }
136}
137
138impl js::rust::Rootable for TracedPromise {}
139
140impl TracedPromise {
141 pub(crate) fn root(&self, cx: &JSContext) -> RootedPromise {
143 self.duplicate(cx)
144 }
145}
146
147impl Deref for TracedPromise {
148 type Target = Promise;
149 fn deref(&self) -> &Self::Target {
150 &self.0
151 }
152}
153
154#[derive(JSTraceable)] #[derive(Default, MallocSizeOf)]
157#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
158struct PermanentRoot(#[ignore_malloc_size_of = "mozjs value"] Heap<JSVal>);
165
166impl PermanentRoot {
167 #[expect(unsafe_code)]
174 unsafe fn init(&self, cx: &JSContext, object: HandleObject) {
175 self.0.set(ObjectValue(*object));
176 unsafe {
177 assert!(AddRawValueRoot(
178 cx,
179 self.0.get_unsafe(),
180 c"Promise::root".as_ptr(),
181 ));
182 }
183 }
184}
185
186impl Drop for PermanentRoot {
187 #[expect(unsafe_code)]
188 fn drop(&mut self) {
189 let js_root = self.0.get();
190 if js_root.is_undefined() {
191 return;
192 }
193 let object = js_root.to_object();
194 assert!(!object.is_null());
195 if let Some(cx) = Runtime::get() {
196 unsafe {
197 RemoveRawValueRoot(cx.as_ptr(), self.0.get_unsafe());
198 }
199 }
200 }
201}
202
203#[dom_struct]
204#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_in_rc)]
205pub(crate) struct Promise {
206 reflector: Reflector,
207 permanent_js_root: Option<PermanentRoot>,
213}
214
215impl Promise {
216 pub(crate) fn new_rooted(cx: &mut JSContext, global: &GlobalScope) -> RootedPromise {
218 let mut realm = enter_auto_realm(cx, global);
219 let cx = &mut realm.current_realm();
220 Promise::new_in_realm_rooted(cx)
221 }
222
223 pub(crate) fn new(cx: &mut JSContext, global: &GlobalScope) -> Rc<Promise> {
227 let mut realm = enter_auto_realm(cx, global);
228 let cx = &mut realm.current_realm();
229 Promise::new_in_realm(cx)
230 }
231
232 pub(crate) fn new_in_realm(current_realm: &mut CurrentRealm) -> Rc<Promise> {
234 let cx = current_realm.deref_mut();
235 rooted!(&in(cx) let mut obj = ptr::null_mut::<JSObject>());
236 Promise::create_js_promise(cx, obj.handle_mut());
237 Promise::new_with_js_promise(cx, obj.handle())
238 }
239
240 pub(crate) fn new_in_realm_rooted(current_realm: &mut CurrentRealm) -> RootedPromise {
244 let cx = current_realm.deref_mut();
245 rooted!(&in(cx) let mut obj = ptr::null_mut::<JSObject>());
246 Promise::create_js_promise(cx, obj.handle_mut());
247 Promise::new_with_js_promise_rooted(cx, obj.handle())
248 }
249
250 pub(crate) fn duplicate(&self, cx: &JSContext) -> RootedPromise {
252 Promise::new_with_js_promise_rooted(cx, self.reflector().get_jsobject())
253 }
254
255 #[expect(unsafe_code)]
256 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
257 fn duplicate_unrooted(&self) -> Rc<Promise> {
258 let promise = Promise {
259 reflector: Reflector::new(),
260 permanent_js_root: None,
261 };
262 let promise = Rc::new(promise);
263 unsafe {
264 promise.init_reflector_without_associated_memory(self.reflector().get_jsobject().get());
265 }
266 promise
267 }
268
269 #[expect(unsafe_code)]
274 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
275 pub(crate) fn new_with_js_promise(cx: &JSContext, obj: HandleObject) -> Rc<Promise> {
276 unsafe {
277 assert!(IsPromiseObject(obj));
278 }
279 let promise = Promise {
280 reflector: Reflector::new(),
281 permanent_js_root: Some(PermanentRoot::default()),
282 };
283 let promise = Rc::new(promise);
284 unsafe {
285 promise.init_reflector_without_associated_memory(obj.get());
286 promise.permanent_js_root.as_ref().unwrap().init(cx, obj);
287 }
288 promise
289 }
290
291 #[expect(unsafe_code)]
294 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
295 pub(crate) fn new_with_js_promise_rooted(cx: &JSContext, obj: HandleObject) -> RootedPromise {
296 unsafe {
297 assert!(IsPromiseObject(obj));
298 }
299 let promise = Promise {
300 reflector: Reflector::new(),
301 permanent_js_root: None,
302 };
303 let promise = Rc::new((promise, PermanentRoot::default()));
304 unsafe {
305 promise
306 .0
307 .init_reflector_without_associated_memory(obj.get());
308 promise.1.init(cx, obj);
309 }
310 RootedPromise(promise)
311 }
312
313 #[expect(unsafe_code)]
314 fn create_js_promise(cx: &mut JSContext, mut obj: MutableHandleObject) {
315 unsafe {
316 let do_nothing_func = JS_NewFunction(
317 cx,
318 Some(do_nothing_promise_executor),
319 2,
320 0,
321 ptr::null(),
322 );
323 assert!(!do_nothing_func.is_null());
324 rooted!(&in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
325 assert!(!do_nothing_obj.is_null());
326 obj.set(NewPromiseObject(cx, do_nothing_obj.handle()));
327 assert!(!obj.is_null());
328 let is_user_interacting = if ScriptThread::is_user_interacting() {
329 PromiseUserInputEventHandlingState::HadUserInteractionAtCreation
330 } else {
331 PromiseUserInputEventHandlingState::DidntHaveUserInteractionAtCreation
332 };
333 SetPromiseUserInputEventHandlingState(obj.handle(), is_user_interacting);
334 }
335 }
336
337 #[expect(unsafe_code)]
338 fn new_resolved_shared<F, T>(
339 cx: &mut JSContext,
340 global: &GlobalScope,
341 value: impl ToJSValConvertible,
342 constructor: F,
343 ) -> T
344 where
345 F: for<'a, 'b> Fn(&'a JSContext, HandleObject<'b>) -> T,
346 {
347 let mut realm = enter_auto_realm(cx, global);
348 let cx = &mut realm.current_realm();
349 rooted!(&in(cx) let mut rval = UndefinedValue());
350 value.to_jsval(cx, rval.handle_mut());
351 rooted!(&in(cx) let p = unsafe { CallOriginalPromiseResolve(cx, rval.handle()) });
352 assert!(!p.handle().is_null());
353 constructor(cx, p.handle())
354 }
355
356 pub(crate) fn new_resolved(
361 cx: &mut JSContext,
362 global: &GlobalScope,
363 value: impl ToJSValConvertible,
364 ) -> Rc<Promise> {
365 Self::new_resolved_shared(cx, global, value, Promise::new_with_js_promise)
366 }
367
368 pub(crate) fn new_resolved_rooted(
371 cx: &mut JSContext,
372 global: &GlobalScope,
373 value: impl ToJSValConvertible,
374 ) -> RootedPromise {
375 Self::new_resolved_shared(cx, global, value, Promise::new_with_js_promise_rooted)
376 }
377
378 #[expect(unsafe_code)]
379 fn new_rejected_shared<F, T>(
380 cx: &mut JSContext,
381 global: &GlobalScope,
382 value: impl ToJSValConvertible,
383 constructor: F,
384 ) -> T
385 where
386 F: for<'a, 'b> Fn(&'a JSContext, HandleObject<'b>) -> T,
387 {
388 let mut realm = enter_auto_realm(cx, global);
389 let cx = &mut realm.current_realm();
390 rooted!(&in(cx) let mut rval = UndefinedValue());
391 value.to_jsval(cx, rval.handle_mut());
392 rooted!(&in(cx) let p = unsafe { CallOriginalPromiseReject(cx, rval.handle()) });
393 assert!(!p.handle().is_null());
394 constructor(cx, p.handle())
395 }
396
397 pub(crate) fn new_rejected_rooted(
400 cx: &mut JSContext,
401 global: &GlobalScope,
402 value: impl ToJSValConvertible,
403 ) -> RootedPromise {
404 Self::new_rejected_shared(cx, global, value, Promise::new_with_js_promise_rooted)
405 }
406
407 pub(crate) fn resolve_native<T>(&self, cx: &mut JSContext, val: &T)
408 where
409 T: ToJSValConvertible,
410 {
411 let mut realm = enter_auto_realm(cx, self);
412 let cx = &mut realm.current_realm();
413 rooted!(&in(cx) let mut v = UndefinedValue());
414 val.to_jsval(cx, v.handle_mut());
415 self.resolve(cx, v.handle());
416 }
417
418 #[expect(unsafe_code)]
419 pub(crate) fn resolve(&self, cx: &mut JSContext, value: HandleValue) {
420 unsafe {
421 if !ResolvePromise(cx, self.promise_obj(), value) {
422 JS_ClearPendingException(cx);
423 }
424 }
425 }
426
427 pub(crate) fn reject_native<T>(&self, cx: &mut JSContext, val: &T)
428 where
429 T: ToJSValConvertible,
430 {
431 let mut realm = enter_auto_realm(cx, self);
432 let cx = &mut realm.current_realm();
433 rooted!(&in(cx) let mut v = UndefinedValue());
434 val.to_jsval(cx, v.handle_mut());
435 self.reject(cx, v.handle());
436 }
437
438 pub(crate) fn reject_error(&self, cx: &mut JSContext, error: Error) {
439 let mut realm = enter_auto_realm(cx, self);
440 let cx = &mut realm.current_realm();
441 rooted!(&in(cx) let mut v = UndefinedValue());
442 error.to_jsval(cx, &self.global(), v.handle_mut());
443 self.reject(cx, v.handle());
444 }
445
446 #[expect(unsafe_code)]
447 pub(crate) fn reject(&self, cx: &mut JSContext, value: HandleValue) {
448 unsafe {
449 if !RejectPromise(cx, self.promise_obj(), value) {
450 JS_ClearPendingException(cx);
451 }
452 }
453 }
454
455 #[expect(unsafe_code)]
456 pub(crate) fn is_fulfilled(&self) -> bool {
457 let state = unsafe { GetPromiseState(self.promise_obj()) };
458 matches!(state, PromiseState::Rejected | PromiseState::Fulfilled)
459 }
460
461 #[expect(unsafe_code)]
462 pub(crate) fn is_rejected(&self) -> bool {
463 let state = unsafe { GetPromiseState(self.promise_obj()) };
464 matches!(state, PromiseState::Rejected)
465 }
466
467 #[expect(unsafe_code)]
468 pub(crate) fn is_pending(&self) -> bool {
469 let state = unsafe { GetPromiseState(self.promise_obj()) };
470 matches!(state, PromiseState::Pending)
471 }
472
473 #[expect(unsafe_code)]
474 pub(crate) fn promise_obj(&self) -> HandleObject<'_> {
475 let obj = self.reflector().get_jsobject();
476 unsafe {
477 assert!(IsPromiseObject(obj));
478 }
479 obj
480 }
481
482 #[expect(unsafe_code)]
483 pub(crate) fn append_native_handler(
484 &self,
485 cx: &mut CurrentRealm,
486 handler: &PromiseNativeHandler,
487 ) {
488 let global = GlobalScope::from_current_realm(cx);
489 run_a_script::<DomTypeHolder, _, _>(cx, &global, |cx| {
490 rooted!(&in(cx) let resolve_func =
491 create_native_handler_function(cx,
492 handler.reflector().get_jsobject(),
493 NativeHandlerTask::Resolve));
494
495 rooted!(&in(cx) let reject_func =
496 create_native_handler_function(cx,
497 handler.reflector().get_jsobject(),
498 NativeHandlerTask::Reject));
499
500 unsafe {
501 let ok = AddPromiseReactions(
502 cx,
503 self.promise_obj(),
504 resolve_func.handle(),
505 reject_func.handle(),
506 );
507 assert!(ok);
508 }
509 })
510 }
511
512 #[expect(unsafe_code)]
513 pub(crate) fn get_promise_is_handled(&self) -> bool {
514 unsafe { GetPromiseIsHandled(self.reflector().get_jsobject()) }
515 }
516
517 #[expect(unsafe_code)]
518 pub(crate) fn set_promise_is_handled(&self, cx: &mut JSContext) -> bool {
519 unsafe { SetAnyPromiseIsHandled(cx, self.reflector().get_jsobject()) }
520 }
521}
522
523#[expect(unsafe_code)]
524unsafe extern "C" fn do_nothing_promise_executor(
525 _cx: *mut RawJSContext,
526 argc: u32,
527 vp: *mut JSVal,
528) -> bool {
529 let args = unsafe { CallArgs::from_vp(vp, argc) };
530 args.rval().set(UndefinedValue());
531 true
532}
533
534const SLOT_NATIVEHANDLER: usize = 0;
535const SLOT_NATIVEHANDLER_TASK: usize = 1;
536
537#[derive(PartialEq)]
538enum NativeHandlerTask {
539 Resolve = 0,
540 Reject = 1,
541}
542
543#[expect(unsafe_code)]
544unsafe extern "C" fn native_handler_callback(
545 cx: *mut RawJSContext,
546 argc: u32,
547 vp: *mut JSVal,
548) -> bool {
549 let mut cx = unsafe { JSContext::from_ptr(ptr::NonNull::new(cx).unwrap()) };
551 let mut cx = CurrentRealm::assert(&mut cx);
552 let cx = &mut cx;
553
554 let args = unsafe { CallArgs::from_vp(vp, argc) };
555 let native_handler_value =
556 unsafe { *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER) };
557 rooted!(&in(cx) let native_handler_value = native_handler_value);
558 assert!(native_handler_value.get().is_object());
559
560 let handler =
561 unsafe { root_from_object::<PromiseNativeHandler>(cx, native_handler_value.to_object()) }
562 .expect("unexpected value for native handler in promise native handler callback");
563
564 let native_handler_task_value =
565 unsafe { *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK) };
566 rooted!(&in(cx) let native_handler_task_value = native_handler_task_value);
567 match native_handler_task_value.to_int32() {
568 native_handler_task_value
569 if native_handler_task_value == NativeHandlerTask::Resolve as i32 =>
570 {
571 handler.resolved_callback(cx, unsafe { HandleValue::from_raw(args.get(0)) })
572 },
573 native_handler_task_value
574 if native_handler_task_value == NativeHandlerTask::Reject as i32 =>
575 {
576 handler.rejected_callback(cx, unsafe { HandleValue::from_raw(args.get(0)) })
577 },
578 _ => panic!("unexpected native handler task value"),
579 };
580
581 true
582}
583
584#[expect(unsafe_code)]
585fn create_native_handler_function(
586 cx: &mut JSContext,
587 holder: HandleObject,
588 task: NativeHandlerTask,
589) -> *mut JSObject {
590 unsafe {
591 let func = NewFunctionWithReserved(cx, Some(native_handler_callback), 1, 0, ptr::null());
592 assert!(!func.is_null());
593
594 rooted!(&in(cx) let obj = JS_GetFunctionObject(func));
595 assert!(!obj.is_null());
596 SetFunctionNativeReserved(obj.get(), SLOT_NATIVEHANDLER, &ObjectValue(*holder));
597 SetFunctionNativeReserved(obj.get(), SLOT_NATIVEHANDLER_TASK, &Int32Value(task as i32));
598 obj.get()
599 }
600}
601
602impl FromJSValConvertibleRc for Promise {
603 fn from_jsval(
604 cx: &mut JSContext,
605 value: HandleValue,
606 ) -> Result<ConversionResult<Rc<Promise>>, ()> {
607 if value.get().is_null() {
608 return Ok(ConversionResult::Failure(c"null not allowed".into()));
609 }
610
611 let mut realm = CurrentRealm::assert(cx);
612 let global_scope = GlobalScope::from_current_realm(&mut realm);
613
614 let promise = Promise::new_resolved(cx, &global_scope, value);
615 Ok(ConversionResult::Success(promise))
616 }
617}
618
619type WaitForAllSuccessSteps = Rc<dyn Fn(&mut JSContext, Vec<HandleValue>)>;
621
622type WaitForAllFailureSteps = Rc<dyn Fn(&mut JSContext, HandleValue)>;
624
625#[derive(JSTraceable, MallocSizeOf)]
628#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
629struct WaitForAllFulfillmentHandler {
630 #[ignore_malloc_size_of = "callbacks are hard"]
632 #[no_trace]
633 success_steps: WaitForAllSuccessSteps,
634
635 #[ignore_malloc_size_of = "mozjs"]
637 #[expect(clippy::vec_box)]
638 result: Rc<RefCell<Vec<Box<Heap<JSVal>>>>>,
639
640 promise_index: usize,
642
643 #[conditional_malloc_size_of]
645 fulfilled_count: Rc<Cell<usize>>,
646}
647
648impl Callback for WaitForAllFulfillmentHandler {
649 fn callback(&self, cx: &mut CurrentRealm, v: HandleValue) {
650 let equals_total = {
653 let result = self.result.borrow_mut();
655 result[self.promise_index].set(v.get());
656
657 let mut fulfilled_count = self.fulfilled_count.get();
659 fulfilled_count += 1;
660 self.fulfilled_count.set(fulfilled_count);
661
662 fulfilled_count == result.len()
663 };
664
665 if equals_total {
667 let result_ref = self.result.borrow();
668 let result_handles: Vec<HandleValue> =
669 result_ref.iter().map(|v| v.as_handle_value()).collect();
670
671 (self.success_steps)(cx, result_handles);
672 }
673 }
674}
675
676#[derive(Clone, JSTraceable, MallocSizeOf)]
679struct WaitForAllRejectionHandler {
680 #[ignore_malloc_size_of = "callbacks are hard"]
682 #[no_trace]
683 failure_steps: WaitForAllFailureSteps,
684
685 rejected: Cell<bool>,
687}
688
689impl Callback for WaitForAllRejectionHandler {
690 fn callback(&self, cx: &mut CurrentRealm, v: HandleValue) {
691 if self.rejected.replace(true) {
694 return;
696 }
697
698 (self.failure_steps)(cx, v);
701 }
702}
703
704#[derive(JSTraceable, MallocSizeOf)]
707#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
708pub(crate) struct WaitForAllSuccessStepsMicrotask {
709 global: Dom<GlobalScope>,
710
711 #[ignore_malloc_size_of = "Closure is hard"]
712 #[no_trace]
713 success_steps: WaitForAllSuccessSteps,
714}
715
716impl MicrotaskRunnable for WaitForAllSuccessStepsMicrotask {
717 fn handler(&self, cx: &mut JSContext) {
718 let mut realm = enter_auto_realm(cx, &*self.global);
719 (self.success_steps)(&mut realm, vec![]);
720 }
721}
722
723#[cfg_attr(crown, expect(crown::unrooted_must_root))]
725fn wait_for_all(
726 cx: &mut CurrentRealm,
727 global: &GlobalScope,
728 promises: Vec<RootedPromise>,
729 success_steps: WaitForAllSuccessSteps,
730 failure_steps: WaitForAllFailureSteps,
731) {
732 let fulfilled_count: Rc<Cell<usize>> = Default::default();
734
735 let rejection_handler = WaitForAllRejectionHandler {
744 failure_steps,
745 rejected: Default::default(),
746 };
747
748 if promises.is_empty() {
753 global.enqueue_microtask(
755 cx,
756 Box::new(WaitForAllSuccessStepsMicrotask {
757 global: Dom::from_ref(global),
758 success_steps,
759 }),
760 );
761
762 return;
764 }
765
766 let result: Rc<RefCell<Vec<Box<Heap<JSVal>>>>> = Default::default();
771
772 for (promise_index, promise) in promises.into_iter().enumerate() {
774 let result = result.clone();
775
776 {
777 let mut result_list = result.borrow_mut();
779 rooted!(&in(cx) let null_value = NullValue());
780 result_list.push(Heap::boxed(null_value.get()));
781 }
782
783 let handler = PromiseNativeHandler::new(
794 cx,
795 global,
796 Some(Box::new(WaitForAllFulfillmentHandler {
797 success_steps: success_steps.clone(),
798 result,
799 promise_index,
800 fulfilled_count: fulfilled_count.clone(),
801 })),
802 Some(Box::new(rejection_handler.clone())),
803 );
804 promise.append_native_handler(cx, &handler);
805
806 }
809}
810
811pub(crate) fn wait_for_all_promise(
813 cx: &mut CurrentRealm,
814 global: &GlobalScope,
815 promises: Vec<RootedPromise>,
816) -> RootedPromise {
817 let promise = Promise::new_rooted(cx, global);
819 let success_promise = promise.clone();
820 let failure_promise = promise.clone();
821
822 let success_steps = Rc::new(move |cx: &mut JSContext, results: Vec<HandleValue>| {
824 success_promise.resolve_native(cx, &results);
826 });
827
828 let failure_steps = Rc::new(move |cx: &mut JSContext, reason: HandleValue| {
830 failure_promise.reject_native(cx, &reason);
832 });
833
834 wait_for_all(cx, global, promises, success_steps, failure_steps);
836
837 promise
839}
840
841impl PromiseHelpers<crate::DomTypeHolder> for Promise {
842 type StackRoot = RootedPromise;
843 type HeapTraced = TracedPromise;
844
845 fn new_in_realm(
846 cx: &mut CurrentRealm,
847 ) -> Rc<<crate::DomTypeHolder as script_bindings::DomTypes>::Promise> {
848 Promise::new_in_realm(cx)
849 }
850
851 fn new_in_realm_rooted(cx: &mut CurrentRealm) -> RootedPromise {
852 Promise::new_in_realm_rooted(cx)
853 }
854
855 fn reject_error(&self, cx: &mut js::context::JSContext, error: script_bindings::error::Error) {
856 Promise::reject_error(self, cx, error);
857 }
858
859 fn is_rejected(&self) -> bool {
860 self.is_rejected()
861 }
862
863 fn is_pending(&self) -> bool {
864 self.is_pending()
865 }
866
867 fn resolve_native<T: ToJSValConvertible>(&self, cx: &mut JSContext, val: &T) {
868 self.resolve_native(cx, val);
869 }
870}