summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Ávila de Espíndola <espindola@chiselstrike.com>2022-01-24 11:59:41 -0500
committerGitHub <noreply@github.com>2022-01-24 17:59:41 +0100
commitae0414fa3581d76af44192567d73dce987c69b9d (patch)
tree6a6ad5ad5f622abc36b0c4ad6d872521c9cb8102
parent23d2b34d4b9aed1fd082ac4cdd01459537e687c5 (diff)
refactor(core): Extract JsRuntime::poll_value out of JsRuntime::resolve_value (#13461)
-rw-r--r--core/runtime.rs114
1 files changed, 82 insertions, 32 deletions
diff --git a/core/runtime.rs b/core/runtime.rs
index fbe97fd93..b0ab92f46 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -686,6 +686,42 @@ impl JsRuntime {
scope.perform_microtask_checkpoint();
}
+ pub fn poll_value(
+ &mut self,
+ global: &v8::Global<v8::Value>,
+ cx: &mut Context,
+ ) -> Poll<Result<v8::Global<v8::Value>, Error>> {
+ let state = self.poll_event_loop(cx, false);
+
+ let mut scope = self.handle_scope();
+ let local = v8::Local::<v8::Value>::new(&mut scope, global);
+
+ if let Ok(promise) = v8::Local::<v8::Promise>::try_from(local) {
+ match promise.state() {
+ v8::PromiseState::Pending => match state {
+ Poll::Ready(Ok(_)) => {
+ let msg = "Promise resolution is still pending but the event loop has already resolved.";
+ Poll::Ready(Err(generic_error(msg)))
+ }
+ Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
+ Poll::Pending => Poll::Pending,
+ },
+ v8::PromiseState::Fulfilled => {
+ let value = promise.result(&mut scope);
+ let value_handle = v8::Global::new(&mut scope, value);
+ Poll::Ready(Ok(value_handle))
+ }
+ v8::PromiseState::Rejected => {
+ let exception = promise.result(&mut scope);
+ Poll::Ready(exception_to_err_result(&mut scope, exception, false))
+ }
+ }
+ } else {
+ let value_handle = v8::Global::new(&mut scope, local);
+ Poll::Ready(Ok(value_handle))
+ }
+ }
+
/// Waits for the given value to resolve while polling the event loop.
///
/// This future resolves when either the value is resolved or the event loop runs to
@@ -694,38 +730,7 @@ impl JsRuntime {
&mut self,
global: v8::Global<v8::Value>,
) -> Result<v8::Global<v8::Value>, Error> {
- poll_fn(|cx| {
- let state = self.poll_event_loop(cx, false);
-
- let mut scope = self.handle_scope();
- let local = v8::Local::<v8::Value>::new(&mut scope, &global);
-
- if let Ok(promise) = v8::Local::<v8::Promise>::try_from(local) {
- match promise.state() {
- v8::PromiseState::Pending => match state {
- Poll::Ready(Ok(_)) => {
- let msg = "Promise resolution is still pending but the event loop has already resolved.";
- Poll::Ready(Err(generic_error(msg)))
- },
- Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
- Poll::Pending => Poll::Pending,
- },
- v8::PromiseState::Fulfilled => {
- let value = promise.result(&mut scope);
- let value_handle = v8::Global::new(&mut scope, value);
- Poll::Ready(Ok(value_handle))
- }
- v8::PromiseState::Rejected => {
- let exception = promise.result(&mut scope);
- Poll::Ready(exception_to_err_result(&mut scope, exception, false))
- }
- }
- } else {
- let value_handle = v8::Global::new(&mut scope, local);
- Poll::Ready(Ok(value_handle))
- }
- })
- .await
+ poll_fn(|cx| self.poll_value(&global, cx)).await
}
/// Runs event loop to completion
@@ -1860,6 +1865,51 @@ pub mod tests {
}
#[tokio::test]
+ async fn test_poll_value() {
+ run_in_task(|cx| {
+ let mut runtime = JsRuntime::new(Default::default());
+ let value_global = runtime
+ .execute_script("a.js", "Promise.resolve(1 + 2)")
+ .unwrap();
+ let v = runtime.poll_value(&value_global, cx);
+ {
+ let scope = &mut runtime.handle_scope();
+ assert!(
+ matches!(v, Poll::Ready(Ok(v)) if v.open(scope).integer_value(scope).unwrap() == 3)
+ );
+ }
+
+ let value_global = runtime
+ .execute_script(
+ "a.js",
+ "Promise.resolve(new Promise(resolve => resolve(2 + 2)))",
+ )
+ .unwrap();
+ let v = runtime.poll_value(&value_global, cx);
+ {
+ let scope = &mut runtime.handle_scope();
+ assert!(
+ matches!(v, Poll::Ready(Ok(v)) if v.open(scope).integer_value(scope).unwrap() == 4)
+ );
+ }
+
+ let value_global = runtime
+ .execute_script("a.js", "Promise.reject(new Error('fail'))")
+ .unwrap();
+ let v = runtime.poll_value(&value_global, cx);
+ assert!(
+ matches!(v, Poll::Ready(Err(e)) if e.downcast_ref::<JsError>().unwrap().message == "Uncaught Error: fail")
+ );
+
+ let value_global = runtime
+ .execute_script("a.js", "new Promise(resolve => {})")
+ .unwrap();
+ let v = runtime.poll_value(&value_global, cx);
+ matches!(v, Poll::Ready(Err(e)) if e.to_string() == "Promise resolution is still pending but the event loop has already resolved.");
+ });
+ }
+
+ #[tokio::test]
async fn test_resolve_value() {
let mut runtime = JsRuntime::new(Default::default());
let value_global = runtime