@ -8,9 +8,8 @@ use crate::{
promise ::{ PromiseState , ResolvingFunctions } ,
promise ::{ PromiseState , ResolvingFunctions } ,
Promise ,
Promise ,
} ,
} ,
context ::intrinsics ::StandardConstructors ,
job ::NativeJob ,
job ::NativeJob ,
object ::{ FunctionObjectBuilder , JsObject , JsObjectType , ObjectData } ,
object ::{ JsObject , JsObjectType , ObjectData } ,
value ::TryFromJs ,
value ::TryFromJs ,
Context , JsArgs , JsError , JsNativeError , JsResult , JsValue , NativeFunction ,
Context , JsArgs , JsError , JsNativeError , JsResult , JsValue , NativeFunction ,
} ;
} ;
@ -52,56 +51,45 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace};
/// Ok(JsValue::undefined())
/// Ok(JsValue::undefined())
/// },
/// },
/// context,
/// context,
/// )? ;
/// );
///
///
/// let promise = promise
/// let promise = promise
/// .then(
/// .then(
/// Some(
/// Some(
/// FunctionObjectBuilder::new(
/// NativeFunction::from_fn_ptr(|_, args, _| {
/// context.realm(),
/// Err(JsError::from_opaque(args.get_or_undefined(0).clone())
/// NativeFunction::from_fn_ptr(|_, args, _| {
/// Err(JsError::from_opaque(
/// args.get_or_undefined(0).clone(),
/// )
/// .into())
/// .into())
/// }),
/// })
/// )
/// .to_js_function(context.realm()),
/// .build(),
/// ),
/// ),
/// None,
/// None,
/// context,
/// context,
/// )?
/// )
/// .catch(
/// .catch(
/// FunctionObjectBuilder::new(
/// NativeFunction::from_fn_ptr(|_, args, _| {
/// context.realm(),
/// Ok(args.get_or_undefined(0).clone())
/// NativeFunction::from_fn_ptr(|_, args, _| {
/// })
/// Ok(args.get_or_undefined(0).clone())
/// .to_js_function(context.realm()),
/// }),
/// )
/// .build(),
/// context,
/// context,
/// )?
/// )
/// .finally(
/// .finally(
/// FunctionObjectBuilder::new(
/// NativeFunction::from_fn_ptr(|_, _, context| {
/// context.realm(),
/// context.global_object().clone().set(
/// NativeFunction::from_fn_ptr(|_, _, context| {
/// js_string!("finally"),
/// context.global_object().clone().set(
/// JsValue::from(true),
/// js_string!("finally"),
/// true,
/// JsValue::from(true),
/// context,
/// true,
/// )?;
/// context,
/// Ok(JsValue::undefined())
/// )?;
/// })
/// Ok(JsValue::undefined())
/// .to_js_function(context.realm()),
/// }),
/// )
/// .build(),
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(js_string!("hello world!").into())
/// PromiseState::Fulfilled(js_string!("hello world!").into())
/// );
/// );
///
///
@ -160,12 +148,12 @@ impl JsPromise {
/// Ok(JsValue::undefined())
/// Ok(JsValue::undefined())
/// },
/// },
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(js_string!("hello world").into())
/// PromiseState::Fulfilled(js_string!("hello world").into())
/// );
/// );
/// # Ok(())
/// # Ok(())
@ -173,7 +161,7 @@ impl JsPromise {
/// ```
/// ```
///
///
/// [`Promise()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
/// [`Promise()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
pub fn new < F > ( executor : F , context : & mut Context < ' _ > ) -> JsResult < Self >
pub fn new < F > ( executor : F , context : & mut Context < ' _ > ) -> Self
where
where
F : FnOnce ( & ResolvingFunctions , & mut Context < ' _ > ) -> JsResult < JsValue > ,
F : FnOnce ( & ResolvingFunctions , & mut Context < ' _ > ) -> JsResult < JsValue > ,
{
{
@ -188,10 +176,11 @@ impl JsPromise {
let e = e . to_opaque ( context ) ;
let e = e . to_opaque ( context ) ;
resolvers
resolvers
. reject
. reject
. call ( & JsValue ::undefined ( ) , & [ e ] , context ) ? ;
. call ( & JsValue ::undefined ( ) , & [ e ] , context )
. expect ( "default `reject` function cannot throw" ) ;
}
}
Ok ( Self { inner : promise } )
Self { inner : promise }
}
}
/// Creates a new pending promise and returns it and its associated `ResolvingFunctions`.
/// Creates a new pending promise and returns it and its associated `ResolvingFunctions`.
@ -214,13 +203,13 @@ impl JsPromise {
///
///
/// let (promise, resolvers) = JsPromise::new_pending(context);
/// let (promise, resolvers) = JsPromise::new_pending(context);
///
///
/// assert_eq!(promise.state()? , PromiseState::Pending);
/// assert_eq!(promise.state(), PromiseState::Pending);
///
///
/// resolvers
/// resolvers
/// .reject
/// .reject
/// .call(&JsValue::undefined(), &[5.into()], context)?;
/// .call(&JsValue::undefined(), &[5.into()], context)?;
///
///
/// assert_eq!(promise.state()? , PromiseState::Rejected(5.into()));
/// assert_eq!(promise.state(), PromiseState::Rejected(5.into()));
///
///
/// # Ok(())
/// # Ok(())
/// # }
/// # }
@ -262,7 +251,7 @@ impl JsPromise {
/// let promise = JsPromise::from_object(promise)?;
/// let promise = JsPromise::from_object(promise)?;
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(JsValue::undefined())
/// PromiseState::Fulfilled(JsValue::undefined())
/// );
/// );
///
///
@ -295,7 +284,6 @@ impl JsPromise {
/// # builtins::promise::PromiseState,
/// # builtins::promise::PromiseState,
/// # Context, JsResult, JsValue
/// # Context, JsResult, JsValue
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// async fn f() -> JsResult<JsValue> {
/// async fn f() -> JsResult<JsValue> {
/// Ok(JsValue::null())
/// Ok(JsValue::null())
/// }
/// }
@ -305,9 +293,7 @@ impl JsPromise {
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(promise.state()?, PromiseState::Fulfilled(JsValue::null()));
/// assert_eq!(promise.state(), PromiseState::Fulfilled(JsValue::null()));
/// # Ok(())
/// # }
/// ```
/// ```
///
///
/// [async_fn]: crate::native_function::NativeFunction::from_async_fn
/// [async_fn]: crate::native_function::NativeFunction::from_async_fn
@ -353,29 +339,26 @@ impl JsPromise {
/// # builtins::promise::PromiseState,
/// # builtins::promise::PromiseState,
/// # Context, js_string
/// # Context, js_string
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let promise = JsPromise::resolve(js_string!("resolved!"), context)? ;
/// let promise = JsPromise::resolve(js_string!("resolved!"), context);
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(js_string!("resolved!").into())
/// PromiseState::Fulfilled(js_string!("resolved!").into())
/// );
/// );
///
/// # Ok(())
/// # }
/// ```
/// ```
///
///
/// [`Promise.resolve()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
/// [`Promise.resolve()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
/// [thenables]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
/// [thenables]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
pub fn resolve < V : Into < JsValue > > ( value : V , context : & mut Context < ' _ > ) -> JsResult < Self > {
pub fn resolve < V : Into < JsValue > > ( value : V , context : & mut Context < ' _ > ) -> Self {
Promise ::promise_resolve (
Promise ::promise_resolve (
& context . intrinsics ( ) . constructors ( ) . promise ( ) . constructor ( ) ,
& context . intrinsics ( ) . constructors ( ) . promise ( ) . constructor ( ) ,
value . into ( ) ,
value . into ( ) ,
context ,
context ,
)
)
. and_then ( Self ::from_object )
. and_then ( Self ::from_object )
. expect ( "default resolving functions cannot throw and must return a promise" )
}
}
/// Creates a `JsPromise` that is rejected with the reason `error`.
/// Creates a `JsPromise` that is rejected with the reason `error`.
@ -394,32 +377,29 @@ impl JsPromise {
/// # builtins::promise::PromiseState,
/// # builtins::promise::PromiseState,
/// # Context, js_string, JsError
/// # Context, js_string, JsError
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let promise = JsPromise::reject(
/// let promise = JsPromise::reject(
/// JsError::from_opaque(js_string!("oops!").into()),
/// JsError::from_opaque(js_string!("oops!").into()),
/// context,
/// context,
/// )? ;
/// );
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Rejected(js_string!("oops!").into())
/// PromiseState::Rejected(js_string!("oops!").into())
/// );
/// );
///
/// # Ok(())
/// # }
/// ```
/// ```
///
///
/// [`Promise.reject`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
/// [`Promise.reject`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
/// [thenable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
/// [thenable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
pub fn reject < E : Into < JsError > > ( error : E , context : & mut Context < ' _ > ) -> JsResult < Self > {
pub fn reject < E : Into < JsError > > ( error : E , context : & mut Context < ' _ > ) -> Self {
Promise ::promise_reject (
Promise ::promise_reject (
& context . intrinsics ( ) . constructors ( ) . promise ( ) . constructor ( ) ,
& context . intrinsics ( ) . constructors ( ) . promise ( ) . constructor ( ) ,
& error . into ( ) ,
& error . into ( ) ,
context ,
context ,
)
)
. and_then ( Self ::from_object )
. and_then ( Self ::from_object )
. expect ( "default resolving functions cannot throw and must return a promise" )
}
}
/// Gets the current state of the promise.
/// Gets the current state of the promise.
@ -433,26 +413,21 @@ impl JsPromise {
/// # builtins::promise::PromiseState,
/// # builtins::promise::PromiseState,
/// # Context
/// # Context
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let promise = JsPromise::new_pending(context).0;
/// let promise = JsPromise::new_pending(context).0;
///
///
/// assert_eq!(promise.state()?, PromiseState::Pending);
/// assert_eq!(promise.state(), PromiseState::Pending);
///
/// # Ok(())
/// # }
/// ```
/// ```
#[ inline ]
#[ inline ]
pub fn state ( & self ) -> JsResult < PromiseState > {
#[ must_use ]
// TODO: if we can guarantee that objects cannot change type after creation,
pub fn state ( & self ) -> PromiseState {
// we can remove this throw.
self . inner
let promise = self . inner . borrow ( ) ;
. borrow ( )
let promise = promise
. as_promise ( )
. as_promise ( )
. ok_or_else ( | | JsNativeError ::typ ( ) . with_message ( "object is not a Promise" ) ) ? ;
. expect ( "objects cannot change type after creation" )
. state ( )
Ok ( promise . state ( ) . clone ( ) )
. clone ( )
}
}
/// Schedules callback functions to run when the promise settles.
/// Schedules callback functions to run when the promise settles.
@ -489,7 +464,6 @@ impl JsPromise {
/// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # Context, JsArgs, JsError, JsValue, NativeFunction,
/// # Context, JsArgs, JsError, JsValue, NativeFunction,
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let promise = JsPromise::new(
/// let promise = JsPromise::new(
@ -502,44 +476,40 @@ impl JsPromise {
/// Ok(JsValue::undefined())
/// Ok(JsValue::undefined())
/// },
/// },
/// context,
/// context,
/// )?
/// )
/// .then(
/// .then(
/// Some(
/// Some(
/// FunctionObjectBuilder::new(
/// NativeFunction::from_fn_ptr(|_, args, context| {
/// context.realm(),
/// args.get_or_undefined(0)
/// NativeFunction::from_fn_ptr(|_, args, context| {
/// .to_string(context)
/// args.get_or_undefined(0)
/// .map(JsValue::from)
/// .to_string(context)
/// })
/// .map(JsValue::from)
/// .to_js_function(context.realm()),
/// }),
/// )
/// .build(),
/// ),
/// ),
/// None,
/// None,
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(js_string!("255.255").into())
/// PromiseState::Fulfilled(js_string!("255.255").into())
/// );
/// );
///
/// # Ok(())
/// # }
/// ```
/// ```
///
///
/// [`Promise.prototype.then`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
/// [`Promise.prototype.then`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
#[ inline ]
#[ inline ]
#[ allow(clippy::return_self_not_must_use) ] // Could just be used to add handlers on an existing promise
pub fn then (
pub fn then (
& self ,
& self ,
on_fulfilled : Option < JsFunction > ,
on_fulfilled : Option < JsFunction > ,
on_rejected : Option < JsFunction > ,
on_rejected : Option < JsFunction > ,
context : & mut Context < ' _ > ,
context : & mut Context < ' _ > ,
) -> JsResult < Self > {
) -> Self {
let result_promise = Promise ::inner_then ( self , on_fulfilled , on_rejected , context ) ? ;
Promise ::inner_then ( self , on_fulfilled , on_rejected , context )
Self ::from_object ( result_promise )
. and_then ( Self ::from_object )
. expect ( "`inner_then` cannot fail for native `JsPromise`" )
}
}
/// Schedules a callback to run when the promise is rejected.
/// Schedules a callback to run when the promise is rejected.
@ -559,7 +529,6 @@ impl JsPromise {
/// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # Context, JsArgs, JsNativeError, JsValue, NativeFunction,
/// # Context, JsArgs, JsNativeError, JsValue, NativeFunction,
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let promise = JsPromise::new(
/// let promise = JsPromise::new(
@ -574,35 +543,30 @@ impl JsPromise {
/// Ok(JsValue::undefined())
/// Ok(JsValue::undefined())
/// },
/// },
/// context,
/// context,
/// )?
/// )
/// .catch(
/// .catch(
/// FunctionObjectBuilder::new(
/// NativeFunction::from_fn_ptr(|_, args, context| {
/// context.realm(),
/// args.get_or_undefined(0)
/// NativeFunction::from_fn_ptr(|_, args, context| {
/// .to_string(context)
/// args.get_or_undefined(0)
/// .map(JsValue::from)
/// .to_string(context)
/// })
/// .map(JsValue::from)
/// .to_js_function(context.realm()),
/// }),
/// )
/// .build(),
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(js_string!("TypeError: thrown").into())
/// PromiseState::Fulfilled(js_string!("TypeError: thrown").into())
/// );
/// );
///
/// # Ok(())
/// # }
/// ```
/// ```
///
///
/// [`Promise.prototype.catch`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
/// [`Promise.prototype.catch`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
/// [then]: JsPromise::then
/// [then]: JsPromise::then
#[ inline ]
#[ inline ]
pub fn catch ( & self , on_rejected : JsFunction , context : & mut Context < ' _ > ) -> JsResult < Self > {
#[ allow(clippy::return_self_not_must_use) ] // Could just be used to add a handler on an existing promise
pub fn catch ( & self , on_rejected : JsFunction , context : & mut Context < ' _ > ) -> Self {
self . then ( None , Some ( on_rejected ) , context )
self . then ( None , Some ( on_rejected ) , context )
}
}
@ -633,7 +597,7 @@ impl JsPromise {
/// js_string!("finally"),
/// js_string!("finally"),
/// false,
/// false,
/// Attribute::all(),
/// Attribute::all(),
/// );
/// )? ;
///
///
/// let promise = JsPromise::new(
/// let promise = JsPromise::new(
/// |resolvers, context| {
/// |resolvers, context| {
@ -647,23 +611,20 @@ impl JsPromise {
/// Ok(JsValue::undefined())
/// Ok(JsValue::undefined())
/// },
/// },
/// context,
/// context,
/// )?
/// )
/// .finally(
/// .finally(
/// FunctionObjectBuilder::new(
/// NativeFunction::from_fn_ptr(|_, _, context| {
/// context.realm(),
/// context.global_object().clone().set(
/// NativeFunction::from_fn_ptr(|_, _, context| {
/// js_string!("finally"),
/// context.global_object().clone().set(
/// JsValue::from(true),
/// js_string!("finally"),
/// true,
/// JsValue::from(true),
/// context,
/// true,
/// )?;
/// context,
/// Ok(JsValue::undefined())
/// )?;
/// })
/// Ok(JsValue::undefined())
/// .to_js_function(context.realm()),
/// }),
/// )
/// .build(),
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
@ -682,10 +643,16 @@ impl JsPromise {
/// [`Promise.prototype.finally()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally
/// [`Promise.prototype.finally()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally
/// [then]: JsPromise::then
/// [then]: JsPromise::then
#[ inline ]
#[ inline ]
pub fn finally ( & self , on_finally : JsFunction , context : & mut Context < ' _ > ) -> JsResult < Self > {
#[ allow(clippy::return_self_not_must_use) ] // Could just be used to add a handler on an existing promise
let c = self . species_constructor ( StandardConstructors ::promise , context ) ? ;
pub fn finally ( & self , on_finally : JsFunction , context : & mut Context < ' _ > ) -> Self {
let ( then , catch ) = Promise ::then_catch_finally_closures ( c , on_finally , context ) ;
let ( then , catch ) = Promise ::then_catch_finally_closures (
self . then ( Some ( then ) , Some ( catch ) , context )
context . intrinsics ( ) . constructors ( ) . promise ( ) . constructor ( ) ,
on_finally ,
context ,
) ;
Promise ::inner_then ( self , Some ( then ) , Some ( catch ) , context )
. and_then ( Self ::from_object )
. expect ( "`inner_then` cannot fail for native `JsPromise`" )
}
}
/// Waits for a list of promises to settle with fulfilled values, rejecting the aggregate promise
/// Waits for a list of promises to settle with fulfilled values, rejecting the aggregate promise
@ -707,26 +674,26 @@ impl JsPromise {
///
///
/// let promise1 = JsPromise::all(
/// let promise1 = JsPromise::all(
/// [
/// [
/// JsPromise::resolve(0, context)? ,
/// JsPromise::resolve(0, context),
/// JsPromise::resolve(2, context)? ,
/// JsPromise::resolve(2, context),
/// JsPromise::resolve(4, context)? ,
/// JsPromise::resolve(4, context),
/// ],
/// ],
/// context,
/// context,
/// )? ;
/// );
///
///
/// let promise2 = JsPromise::all(
/// let promise2 = JsPromise::all(
/// [
/// [
/// JsPromise::resolve(1, context)? ,
/// JsPromise::resolve(1, context),
/// JsPromise::reject(JsNativeError::typ(), context)? ,
/// JsPromise::reject(JsNativeError::typ(), context),
/// JsPromise::resolve(3, context)? ,
/// JsPromise::resolve(3, context),
/// ],
/// ],
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// let array = promise1
/// let array = promise1
/// .state()?
/// .state()
/// .as_fulfilled()
/// .as_fulfilled()
/// .and_then(JsValue::as_object)
/// .and_then(JsValue::as_object)
/// .unwrap()
/// .unwrap()
@ -736,7 +703,7 @@ impl JsPromise {
/// assert_eq!(array.at(1, context)?, 2.into());
/// assert_eq!(array.at(1, context)?, 2.into());
/// assert_eq!(array.at(2, context)?, 4.into());
/// assert_eq!(array.at(2, context)?, 4.into());
///
///
/// let error = promise2.state()? .as_rejected().unwrap().clone();
/// let error = promise2.state().as_rejected().unwrap().clone();
/// assert_eq!(error.to_string(context)?, js_string!("TypeError"));
/// assert_eq!(error.to_string(context)?, js_string!("TypeError"));
///
///
/// # Ok(())
/// # Ok(())
@ -744,7 +711,7 @@ impl JsPromise {
/// ```
/// ```
///
///
/// [`Promise.all`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
/// [`Promise.all`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
pub fn all < I > ( promises : I , context : & mut Context < ' _ > ) -> JsResult < Self >
pub fn all < I > ( promises : I , context : & mut Context < ' _ > ) -> Self
where
where
I : IntoIterator < Item = Self > ,
I : IntoIterator < Item = Self > ,
{
{
@ -757,12 +724,15 @@ impl JsPromise {
. constructor ( )
. constructor ( )
. into ( ) ;
. into ( ) ;
let value = Promise ::all ( c , & [ promises . into ( ) ] , context ) ? ;
let value = Promise ::all ( c , & [ promises . into ( ) ] , context )
let value = value
. expect ( "Promise.all cannot fail with the default `%Promise%` constructor" ) ;
let object = value
. as_object ( )
. as_object ( )
. expect ( "Promise.all always returns an object on success" ) ;
. expect ( "` Promise.all` always returns an object on success" ) ;
Self ::from_object ( value . clone ( ) )
Self ::from_object ( object . clone ( ) )
. expect ( "`Promise::all` with the default `%Promise%` constructor always returns a native `JsPromise`" )
}
}
/// Waits for a list of promises to settle, fulfilling with an array of the outcomes of every
/// Waits for a list of promises to settle, fulfilling with an array of the outcomes of every
@ -784,17 +754,17 @@ impl JsPromise {
///
///
/// let promise = JsPromise::all_settled(
/// let promise = JsPromise::all_settled(
/// [
/// [
/// JsPromise::resolve(1, context)? ,
/// JsPromise::resolve(1, context),
/// JsPromise::reject(JsNativeError::typ(), context)? ,
/// JsPromise::reject(JsNativeError::typ(), context),
/// JsPromise::resolve(3, context)? ,
/// JsPromise::resolve(3, context),
/// ],
/// ],
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// let array = promise
/// let array = promise
/// .state()?
/// .state()
/// .as_fulfilled()
/// .as_fulfilled()
/// .and_then(JsValue::as_object)
/// .and_then(JsValue::as_object)
/// .unwrap()
/// .unwrap()
@ -830,7 +800,7 @@ impl JsPromise {
/// ```
/// ```
///
///
/// [`Promise.allSettled`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
/// [`Promise.allSettled`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
pub fn all_settled < I > ( promises : I , context : & mut Context < ' _ > ) -> JsResult < Self >
pub fn all_settled < I > ( promises : I , context : & mut Context < ' _ > ) -> Self
where
where
I : IntoIterator < Item = Self > ,
I : IntoIterator < Item = Self > ,
{
{
@ -843,12 +813,15 @@ impl JsPromise {
. constructor ( )
. constructor ( )
. into ( ) ;
. into ( ) ;
let value = Promise ::all_settled ( c , & [ promises . into ( ) ] , context ) ? ;
let value = Promise ::all_settled ( c , & [ promises . into ( ) ] , context )
let value = value
. expect ( "`Promise.all_settled` cannot fail with the default `%Promise%` constructor" ) ;
let object = value
. as_object ( )
. as_object ( )
. expect ( "Promise.allSettled always returns an object on success" ) ;
. expect ( "`Promise.all_settled` always returns an object on success" ) ;
Self ::from_object ( value . clone ( ) )
Self ::from_object ( object . clone ( ) )
. expect ( "`Promise::all_settled` with the default `%Promise%` constructor always returns a native `JsPromise`" )
}
}
/// Returns the first promise that fulfills from a list of promises.
/// Returns the first promise that fulfills from a list of promises.
@ -869,32 +842,28 @@ impl JsPromise {
/// # object::builtins::JsPromise,
/// # object::builtins::JsPromise,
/// # Context, JsNativeError,
/// # Context, JsNativeError,
/// # };
/// # };
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let promise = JsPromise::any(
/// let promise = JsPromise::any(
/// [
/// [
/// JsPromise::reject(JsNativeError::syntax(), context)? ,
/// JsPromise::reject(JsNativeError::syntax(), context),
/// JsPromise::reject(JsNativeError::typ(), context)? ,
/// JsPromise::reject(JsNativeError::typ(), context),
/// JsPromise::resolve(js_string!("fulfilled"), context)? ,
/// JsPromise::resolve(js_string!("fulfilled"), context),
/// JsPromise::reject(JsNativeError::range(), context)? ,
/// JsPromise::reject(JsNativeError::range(), context),
/// ],
/// ],
/// context,
/// context,
/// )? ;
/// );
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Fulfilled(js_string!("fulfilled").into())
/// PromiseState::Fulfilled(js_string!("fulfilled").into())
/// );
/// );
///
/// # Ok(())
/// # }
/// ```
/// ```
///
///
/// [`Promise.any`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any
/// [`Promise.any`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any
pub fn any < I > ( promises : I , context : & mut Context < ' _ > ) -> JsResult < Self >
pub fn any < I > ( promises : I , context : & mut Context < ' _ > ) -> Self
where
where
I : IntoIterator < Item = Self > ,
I : IntoIterator < Item = Self > ,
{
{
@ -907,12 +876,15 @@ impl JsPromise {
. constructor ( )
. constructor ( )
. into ( ) ;
. into ( ) ;
let value = Promise ::any ( c , & [ promises . into ( ) ] , context ) ? ;
let value = Promise ::any ( c , & [ promises . into ( ) ] , context )
let value = value
. expect ( "`Promise.any` cannot fail with the default `%Promise%` constructor" ) ;
let object = value
. as_object ( )
. as_object ( )
. expect ( "Promise.any always returns an object on success" ) ;
. expect ( "` Promise.any` always returns an object on success" ) ;
Self ::from_object ( value . clone ( ) )
Self ::from_object ( object . clone ( ) )
. expect ( "`Promise::any` with the default `%Promise%` constructor always returns a native `JsPromise`" )
}
}
/// Returns the first promise that settles from a list of promises.
/// Returns the first promise that settles from a list of promises.
@ -939,22 +911,24 @@ impl JsPromise {
/// let (b, resolvers_b) = JsPromise::new_pending(context);
/// let (b, resolvers_b) = JsPromise::new_pending(context);
/// let (c, resolvers_c) = JsPromise::new_pending(context);
/// let (c, resolvers_c) = JsPromise::new_pending(context);
///
///
/// let promise = JsPromise::race([a, b, c], context)? ;
/// let promise = JsPromise::race([a, b, c], context);
///
///
/// resolvers_b.reject.call(&JsValue::undefined(), &[], context);
/// resolvers_b
/// .reject
/// .call(&JsValue::undefined(), &[], context)?;
/// resolvers_a
/// resolvers_a
/// .resolve
/// .resolve
/// .call(&JsValue::undefined(), &[5.into()], context);
/// .call(&JsValue::undefined(), &[5.into()], context)? ;
/// resolvers_c.reject.call(
/// resolvers_c.reject.call(
/// &JsValue::undefined(),
/// &JsValue::undefined(),
/// &[js_string!("c error").into()],
/// &[js_string!("c error").into()],
/// context,
/// context,
/// );
/// )? ;
///
///
/// context.run_jobs();
/// context.run_jobs();
///
///
/// assert_eq!(
/// assert_eq!(
/// promise.state()? ,
/// promise.state(),
/// PromiseState::Rejected(JsValue::undefined())
/// PromiseState::Rejected(JsValue::undefined())
/// );
/// );
///
///
@ -963,7 +937,7 @@ impl JsPromise {
/// ```
/// ```
///
///
/// [`Promise.race`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
/// [`Promise.race`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
pub fn race < I > ( promises : I , context : & mut Context < ' _ > ) -> JsResult < Self >
pub fn race < I > ( promises : I , context : & mut Context < ' _ > ) -> Self
where
where
I : IntoIterator < Item = Self > ,
I : IntoIterator < Item = Self > ,
{
{
@ -976,12 +950,15 @@ impl JsPromise {
. constructor ( )
. constructor ( )
. into ( ) ;
. into ( ) ;
let value = Promise ::race ( c , & [ promises . into ( ) ] , context ) ? ;
let value = Promise ::race ( c , & [ promises . into ( ) ] , context )
let value = value
. expect ( "`Promise.race` cannot fail with the default `%Promise%` constructor" ) ;
let object = value
. as_object ( )
. as_object ( )
. expect ( "Promise.race always returns an object on success" ) ;
. expect ( "` Promise.race` always returns an object on success" ) ;
Self ::from_object ( value . clone ( ) )
Self ::from_object ( object . clone ( ) )
. expect ( "`Promise::race` with the default `%Promise%` constructor always returns a native `JsPromise`" )
}
}
/// Creates a `JsFuture` from this `JsPromise`.
/// Creates a `JsFuture` from this `JsPromise`.
@ -1003,7 +980,7 @@ impl JsPromise {
/// let context = &mut Context::default();
/// let context = &mut Context::default();
///
///
/// let (promise, resolvers) = JsPromise::new_pending(context);
/// let (promise, resolvers) = JsPromise::new_pending(context);
/// let promise_future = promise.into_js_future(context)? ;
/// let promise_future = promise.into_js_future(context);
///
///
/// let future1 = async move { promise_future.await };
/// let future1 = async move { promise_future.await };
///
///
@ -1023,7 +1000,7 @@ impl JsPromise {
/// # Ok(())
/// # Ok(())
/// # }
/// # }
/// ```
/// ```
pub fn into_js_future ( self , context : & mut Context < ' _ > ) -> JsResult < Js Future > {
pub fn into_js_future ( self , context : & mut Context < ' _ > ) -> JsFuture {
// Mostly based from:
// Mostly based from:
// https://docs.rs/wasm-bindgen-futures/0.4.37/src/wasm_bindgen_futures/lib.rs.html#109-168
// https://docs.rs/wasm-bindgen-futures/0.4.37/src/wasm_bindgen_futures/lib.rs.html#109-168
@ -1057,39 +1034,35 @@ impl JsPromise {
let resolve = {
let resolve = {
let state = state . clone ( ) ;
let state = state . clone ( ) ;
FunctionObjectBuilder ::new (
NativeFunction ::from_copy_closure_with_captures (
context . realm ( ) ,
move | _ , args , state , _ | {
NativeFunction ::from_copy_closure_with_captures (
finish ( state , Ok ( args . get_or_undefined ( 0 ) . clone ( ) ) ) ;
move | _ , args , state , _ | {
Ok ( JsValue ::undefined ( ) )
finish ( state , Ok ( args . get_or_undefined ( 0 ) . clone ( ) ) ) ;
} ,
Ok ( JsValue ::undefined ( ) )
state ,
} ,
state ,
) ,
)
)
. build ( )
} ;
} ;
let reject = {
let reject = {
let state = state . clone ( ) ;
let state = state . clone ( ) ;
FunctionObjectBuilder ::new (
NativeFunction ::from_copy_closure_with_captures (
context . realm ( ) ,
move | _ , args , state , _ | {
NativeFunction ::from_copy_closure_with_captures (
let err = JsError ::from_opaque ( args . get_or_undefined ( 0 ) . clone ( ) ) ;
move | _ , args , state , _ | {
finish ( state , Err ( err ) ) ;
let err = JsError ::from_opaque ( args . get_or_undefined ( 0 ) . clone ( ) ) ;
Ok ( JsValue ::undefined ( ) )
finish ( state , Err ( err ) ) ;
} ,
Ok ( JsValue ::undefined ( ) )
state ,
} ,
state ,
) ,
)
)
. build ( )
} ;
} ;
drop ( self . then ( Some ( resolve ) , Some ( reject ) , context ) ? ) ;
drop ( self . then (
Some ( resolve . to_js_function ( context . realm ( ) ) ) ,
Some ( reject . to_js_function ( context . realm ( ) ) ) ,
context ,
) ) ;
Ok ( JsFuture { inner : state } )
JsFuture { inner : state }
}
}
}
}