Browse Source

Allow passing owned `HostHooks` and `JobQueues` to `Context` (#2811)

This allows `thread_local` contexts to have owned `HostHooks` and `JobQueues`.

It changes the following:

- Creates a new `MaybeShared` struct that can hold either a reference or an `Rc`.
- Changes the `job_queue` and `host_hooks` parameters of `Context` to use `MaybeShared`.

This PR also allows us to make `SimpleJobQueue` the default promise runner, which I think it's pretty cool :)

cc @lastmjs
pull/2814/head
José Julián Espina 2 years ago
parent
commit
0d6ba53ff2
  1. 4
      boa_cli/src/main.rs
  2. 4
      boa_engine/src/builtins/intl/locale/tests.rs
  3. 4
      boa_engine/src/builtins/intl/locale/utils.rs
  4. 11
      boa_engine/src/builtins/promise/tests.rs
  5. 4
      boa_engine/src/context/hooks.rs
  6. 9
      boa_engine/src/context/icu.rs
  7. 42
      boa_engine/src/context/maybe_shared.rs
  8. 71
      boa_engine/src/context/mod.rs
  9. 25
      boa_engine/src/job.rs
  10. 3
      boa_engine/src/lib.rs
  11. 37
      boa_engine/src/object/builtins/jspromise.rs
  12. 11
      boa_engine/src/tests/promise.rs
  13. 4
      boa_examples/src/bin/futures.rs
  14. 11
      boa_tester/src/exec/mod.rs

4
boa_cli/src/main.rs

@ -302,9 +302,9 @@ fn evaluate_files(args: &Opt, context: &mut Context<'_>) -> Result<(), io::Error
fn main() -> Result<(), io::Error> { fn main() -> Result<(), io::Error> {
let args = Opt::parse(); let args = Opt::parse();
let queue = Jobs::default(); let queue: &dyn JobQueue = &Jobs::default();
let mut context = ContextBuilder::new() let mut context = ContextBuilder::new()
.job_queue(&queue) .job_queue(queue)
.build() .build()
.expect("cannot fail with default global object"); .expect("cannot fail with default global object");

4
boa_engine/src/builtins/intl/locale/tests.rs

@ -7,7 +7,7 @@ use icu_locid::{
locale, Locale, locale, Locale,
}; };
use icu_plurals::provider::CardinalV1Marker; use icu_plurals::provider::CardinalV1Marker;
use icu_provider::{DataLocale, DataProvider, DataRequest, DataRequestMetadata}; use icu_provider::{BufferProvider, DataLocale, DataProvider, DataRequest, DataRequestMetadata};
use crate::{ use crate::{
builtins::intl::{ builtins::intl::{
@ -73,7 +73,7 @@ impl Service for TestService {
#[test] #[test]
fn locale_resolution() { fn locale_resolution() {
let provider = boa_icu_provider::buffer(); let provider: &dyn BufferProvider = boa_icu_provider::buffer();
let icu = Icu::new(BoaProvider::Buffer(provider)).unwrap(); let icu = Icu::new(BoaProvider::Buffer(provider)).unwrap();
let mut default = default_locale(icu.locale_canonicalizer()); let mut default = default_locale(icu.locale_canonicalizer());
default default

4
boa_engine/src/builtins/intl/locale/utils.rs

@ -547,7 +547,7 @@ pub(in crate::builtins::intl) fn validate_extension<M: KeyedDataMarker>(
mod tests { mod tests {
use icu_locid::{langid, locale, Locale}; use icu_locid::{langid, locale, Locale};
use icu_plurals::provider::CardinalV1Marker; use icu_plurals::provider::CardinalV1Marker;
use icu_provider::AsDeserializingBufferProvider; use icu_provider::{AsDeserializingBufferProvider, BufferProvider};
use crate::{ use crate::{
builtins::intl::locale::utils::{ builtins::intl::locale::utils::{
@ -579,7 +579,7 @@ mod tests {
#[test] #[test]
fn lookup_match() { fn lookup_match() {
let provider = boa_icu_provider::buffer(); let provider: &dyn BufferProvider = boa_icu_provider::buffer();
let icu = Icu::new(BoaProvider::Buffer(provider)).unwrap(); let icu = Icu::new(BoaProvider::Buffer(provider)).unwrap();
// requested: [] // requested: []

11
boa_engine/src/builtins/promise/tests.rs

@ -1,12 +1,9 @@
use crate::{context::ContextBuilder, job::SimpleJobQueue, run_test_actions_with, TestAction}; use crate::{run_test_actions, TestAction};
use indoc::indoc; use indoc::indoc;
#[test] #[test]
fn promise() { fn promise() {
let queue = SimpleJobQueue::new(); run_test_actions([
let context = &mut ContextBuilder::new().job_queue(&queue).build().unwrap();
run_test_actions_with(
[
TestAction::run(indoc! {r#" TestAction::run(indoc! {r#"
let count = 0; let count = 0;
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
@ -19,7 +16,5 @@ fn promise() {
#[allow(clippy::redundant_closure_for_method_calls)] #[allow(clippy::redundant_closure_for_method_calls)]
TestAction::inspect_context(|ctx| ctx.run_jobs()), TestAction::inspect_context(|ctx| ctx.run_jobs()),
TestAction::assert_eq("count", 3), TestAction::assert_eq("count", 3),
], ]);
context,
);
} }

4
boa_engine/src/context/hooks.rs

@ -38,8 +38,8 @@ use super::intrinsics::Intrinsics;
/// Err(JsNativeError::typ().with_message("eval calls not available").into()) /// Err(JsNativeError::typ().with_message("eval calls not available").into())
/// } /// }
/// } /// }
/// let hooks = Hooks; // Can have additional state. /// let hooks: &dyn HostHooks = &Hooks; // Can have additional state.
/// let context = &mut ContextBuilder::new().host_hooks(&hooks).build().unwrap(); /// let context = &mut ContextBuilder::new().host_hooks(hooks).build().unwrap();
/// let result = context.eval_script(Source::from_bytes(r#"eval("let a = 5")"#)); /// let result = context.eval_script(Source::from_bytes(r#"eval("let a = 5")"#));
/// assert_eq!(result.unwrap_err().to_string(), "TypeError: eval calls not available"); /// assert_eq!(result.unwrap_err().to_string(), "TypeError: eval calls not available");
/// ``` /// ```

9
boa_engine/src/context/icu.rs

@ -43,7 +43,7 @@ where
M::Yokeable: ZeroFrom<'static, M::Yokeable> + MaybeSendSync, M::Yokeable: ZeroFrom<'static, M::Yokeable> + MaybeSendSync,
{ {
fn load(&self, req: DataRequest<'_>) -> Result<DataResponse<M>, DataError> { fn load(&self, req: DataRequest<'_>) -> Result<DataResponse<M>, DataError> {
match *self { match self {
BoaProvider::Buffer(provider) => provider.as_deserializing().load(req), BoaProvider::Buffer(provider) => provider.as_deserializing().load(req),
BoaProvider::Any(provider) => provider.as_downcasting().load(req), BoaProvider::Any(provider) => provider.as_downcasting().load(req),
} }
@ -125,8 +125,8 @@ impl BoaProvider<'_> {
} }
} }
/// Collection of tools initialized from a [`DataProvider`] that are used /// Collection of tools initialized from a [`DataProvider`] that are used for the functionality of
/// for the functionality of `Intl`. /// `Intl`.
pub(crate) struct Icu<'provider> { pub(crate) struct Icu<'provider> {
provider: BoaProvider<'provider>, provider: BoaProvider<'provider>,
locale_canonicalizer: LocaleCanonicalizer, locale_canonicalizer: LocaleCanonicalizer,
@ -148,8 +148,7 @@ impl<'provider> Icu<'provider> {
/// ///
/// # Errors /// # Errors
/// ///
/// This method will return an error if any of the tools /// Returns an error if any of the tools required cannot be constructed.
/// required cannot be constructed.
pub(crate) fn new( pub(crate) fn new(
provider: BoaProvider<'provider>, provider: BoaProvider<'provider>,
) -> Result<Icu<'provider>, LocaleTransformError> { ) -> Result<Icu<'provider>, LocaleTransformError> {

42
boa_engine/src/context/maybe_shared.rs

@ -0,0 +1,42 @@
use std::{ops::Deref, rc::Rc};
/// A [`Cow`][std::borrow::Cow]-like pointer where the `Owned` variant is an [`Rc`].
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum MaybeShared<'a, T: ?Sized> {
/// Borrowed data.
Borrowed(&'a T),
/// `Rc` shared data.
Shared(Rc<T>),
}
impl<T: ?Sized> Clone for MaybeShared<'_, T> {
fn clone(&self) -> Self {
match self {
Self::Borrowed(b) => Self::Borrowed(b),
Self::Shared(sh) => Self::Shared(sh.clone()),
}
}
}
impl<T: ?Sized> Deref for MaybeShared<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
MaybeShared::Borrowed(b) => b,
MaybeShared::Shared(sh) => sh,
}
}
}
impl<'a, T: ?Sized> From<&'a T> for MaybeShared<'a, T> {
fn from(value: &'a T) -> Self {
Self::Borrowed(value)
}
}
impl<T: ?Sized> From<Rc<T>> for MaybeShared<'static, T> {
fn from(value: Rc<T>) -> Self {
Self::Shared(value)
}
}

71
boa_engine/src/context/mod.rs

@ -1,26 +1,26 @@
//! The ECMAScript context. //! The ECMAScript context.
mod hooks; mod hooks;
pub mod intrinsics;
pub use hooks::{DefaultHooks, HostHooks};
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
pub(crate) mod icu; pub(crate) mod icu;
pub mod intrinsics;
mod maybe_shared;
pub use hooks::{DefaultHooks, HostHooks};
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
pub use icu::BoaProvider; pub use icu::BoaProvider;
use intrinsics::Intrinsics; use intrinsics::Intrinsics;
pub use maybe_shared::MaybeShared;
use std::io::Read;
#[cfg(not(feature = "intl"))] #[cfg(not(feature = "intl"))]
pub use std::marker::PhantomData; pub use std::marker::PhantomData;
use std::{io::Read, rc::Rc};
use crate::{ use crate::{
builtins, builtins,
bytecompiler::ByteCompiler, bytecompiler::ByteCompiler,
class::{Class, ClassBuilder}, class::{Class, ClassBuilder},
job::{IdleJobQueue, JobQueue, NativeJob}, job::{JobQueue, NativeJob, SimpleJobQueue},
native_function::NativeFunction, native_function::NativeFunction,
object::{FunctionObjectBuilder, JsObject}, object::{FunctionObjectBuilder, JsObject},
optimizer::{Optimizer, OptimizerOptions, OptimizerStatistics}, optimizer::{Optimizer, OptimizerOptions, OptimizerStatistics},
@ -99,9 +99,9 @@ pub struct Context<'host> {
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
icu: icu::Icu<'host>, icu: icu::Icu<'host>,
host_hooks: &'host dyn HostHooks, host_hooks: MaybeShared<'host, dyn HostHooks>,
job_queue: &'host dyn JobQueue, job_queue: MaybeShared<'host, dyn JobQueue>,
optimizer_options: OptimizerOptions, optimizer_options: OptimizerOptions,
} }
@ -494,12 +494,12 @@ impl<'host> Context<'host> {
/// Enqueues a [`NativeJob`] on the [`JobQueue`]. /// Enqueues a [`NativeJob`] on the [`JobQueue`].
pub fn enqueue_job(&mut self, job: NativeJob) { pub fn enqueue_job(&mut self, job: NativeJob) {
self.job_queue.enqueue_promise_job(job, self); self.job_queue().enqueue_promise_job(job, self);
} }
/// Runs all the jobs in the job queue. /// Runs all the jobs in the job queue.
pub fn run_jobs(&mut self) { pub fn run_jobs(&mut self) {
self.job_queue.run_jobs(self); self.job_queue().run_jobs(self);
self.clear_kept_objects(); self.clear_kept_objects();
} }
@ -524,13 +524,13 @@ impl<'host> Context<'host> {
} }
/// Gets the host hooks. /// Gets the host hooks.
pub fn host_hooks(&self) -> &'host dyn HostHooks { pub fn host_hooks(&self) -> MaybeShared<'host, dyn HostHooks> {
self.host_hooks self.host_hooks.clone()
} }
/// Gets the job queue. /// Gets the job queue.
pub fn job_queue(&mut self) -> &'host dyn JobQueue { pub fn job_queue(&self) -> MaybeShared<'host, dyn JobQueue> {
self.job_queue self.job_queue.clone()
} }
} }
@ -558,8 +558,8 @@ impl<'host> Context<'host> {
#[derive(Default)] #[derive(Default)]
pub struct ContextBuilder<'icu, 'hooks, 'queue> { pub struct ContextBuilder<'icu, 'hooks, 'queue> {
interner: Option<Interner>, interner: Option<Interner>,
host_hooks: Option<&'hooks dyn HostHooks>, host_hooks: Option<MaybeShared<'hooks, dyn HostHooks>>,
job_queue: Option<&'queue dyn JobQueue>, job_queue: Option<MaybeShared<'queue, dyn JobQueue>>,
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
icu: Option<icu::Icu<'icu>>, icu: Option<icu::Icu<'icu>>,
#[cfg(not(feature = "intl"))] #[cfg(not(feature = "intl"))]
@ -570,10 +570,15 @@ pub struct ContextBuilder<'icu, 'hooks, 'queue> {
impl std::fmt::Debug for ContextBuilder<'_, '_, '_> { impl std::fmt::Debug for ContextBuilder<'_, '_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[derive(Clone, Copy, Debug)]
struct JobQueue;
#[derive(Clone, Copy, Debug)]
struct HostHooks;
let mut out = f.debug_struct("ContextBuilder"); let mut out = f.debug_struct("ContextBuilder");
out.field("interner", &self.interner) out.field("interner", &self.interner)
.field("host_hooks", &"HostHooks"); .field("host_hooks", &self.host_hooks.as_ref().map(|_| HostHooks))
.field("job_queue", &self.job_queue.as_ref().map(|_| JobQueue));
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
out.field("icu", &self.icu); out.field("icu", &self.icu);
@ -632,18 +637,27 @@ impl<'icu, 'hooks, 'queue> ContextBuilder<'icu, 'hooks, 'queue> {
/// ///
/// [`Host Hooks`]: https://tc39.es/ecma262/#sec-host-hooks-summary /// [`Host Hooks`]: https://tc39.es/ecma262/#sec-host-hooks-summary
#[must_use] #[must_use]
pub fn host_hooks(self, host_hooks: &dyn HostHooks) -> ContextBuilder<'icu, '_, 'queue> { pub fn host_hooks<'new_hooks, H>(
self,
host_hooks: H,
) -> ContextBuilder<'icu, 'new_hooks, 'queue>
where
H: Into<MaybeShared<'new_hooks, dyn HostHooks>>,
{
ContextBuilder { ContextBuilder {
host_hooks: Some(host_hooks), host_hooks: Some(host_hooks.into()),
..self ..self
} }
} }
/// Initializes the [`JobQueue`] for the context. /// Initializes the [`JobQueue`] for the context.
#[must_use] #[must_use]
pub fn job_queue(self, job_queue: &dyn JobQueue) -> ContextBuilder<'icu, 'hooks, '_> { pub fn job_queue<'new_queue, Q>(self, job_queue: Q) -> ContextBuilder<'icu, 'hooks, 'new_queue>
where
Q: Into<MaybeShared<'new_queue, dyn JobQueue>>,
{
ContextBuilder { ContextBuilder {
job_queue: Some(job_queue), job_queue: Some(job_queue.into()),
..self ..self
} }
} }
@ -666,8 +680,11 @@ impl<'icu, 'hooks, 'queue> ContextBuilder<'icu, 'hooks, 'queue> {
'hooks: 'host, 'hooks: 'host,
'queue: 'host, 'queue: 'host,
{ {
let host_hooks = self.host_hooks.unwrap_or(&DefaultHooks); let host_hooks = self.host_hooks.unwrap_or_else(|| {
let realm = Realm::create(host_hooks); let hooks: &dyn HostHooks = &DefaultHooks;
hooks.into()
});
let realm = Realm::create(&*host_hooks);
let vm = Vm::new(realm.environment().clone()); let vm = Vm::new(realm.environment().clone());
let mut context = Context { let mut context = Context {
@ -677,14 +694,18 @@ impl<'icu, 'hooks, 'queue> ContextBuilder<'icu, 'hooks, 'queue> {
strict: false, strict: false,
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
icu: self.icu.unwrap_or_else(|| { icu: self.icu.unwrap_or_else(|| {
let provider = BoaProvider::Buffer(boa_icu_provider::buffer()); let buffer: &dyn icu_provider::BufferProvider = boa_icu_provider::buffer();
let provider = BoaProvider::Buffer(buffer);
icu::Icu::new(provider).expect("Failed to initialize default icu data.") icu::Icu::new(provider).expect("Failed to initialize default icu data.")
}), }),
#[cfg(feature = "fuzz")] #[cfg(feature = "fuzz")]
instructions_remaining: self.instructions_remaining, instructions_remaining: self.instructions_remaining,
kept_alive: Vec::new(), kept_alive: Vec::new(),
host_hooks, host_hooks,
job_queue: self.job_queue.unwrap_or(&IdleJobQueue), job_queue: self.job_queue.unwrap_or_else(|| {
let queue: Rc<dyn JobQueue> = Rc::new(SimpleJobQueue::new());
queue.into()
}),
optimizer_options: OptimizerOptions::OPTIMIZE_ALL, optimizer_options: OptimizerOptions::OPTIMIZE_ALL,
}; };

25
boa_engine/src/job.rs

@ -198,10 +198,17 @@ pub trait JobQueue {
/// A job queue that does nothing. /// A job queue that does nothing.
/// ///
/// This is the default job queue for the [`Context`], and is useful if you want to disable /// This queue is mostly useful if you want to disable the promise capabilities of the engine. This
/// the promise capabilities of the engine. /// can be done by passing a reference to it to the [`ContextBuilder`]:
/// ///
/// If you want to enable running promise jobs, see [`SimpleJobQueue`]. /// ```
/// use boa_engine::{context::ContextBuilder, job::{JobQueue, IdleJobQueue}};
///
/// let queue: &dyn JobQueue = &IdleJobQueue;
/// let context = ContextBuilder::new().job_queue(queue).build();
/// ```
///
/// [`ContextBuilder`]: crate::context::ContextBuilder
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct IdleJobQueue; pub struct IdleJobQueue;
@ -215,16 +222,10 @@ impl JobQueue for IdleJobQueue {
/// A simple FIFO job queue that bails on the first error. /// A simple FIFO job queue that bails on the first error.
/// ///
/// To enable running promise jobs on the engine, you need to pass it to the [`ContextBuilder`]: /// This is the default job queue for the [`Context`], but it is mostly pretty limited for
/// custom event queues.
/// ///
/// ``` /// To disable running promise jobs on the engine, see [`IdleJobQueue`].
/// use boa_engine::{context::ContextBuilder, job::SimpleJobQueue};
///
/// let queue = SimpleJobQueue::new();
/// let context = ContextBuilder::new().job_queue(&queue).build();
/// ```
///
/// [`ContextBuilder`]: crate::context::ContextBuilder
#[derive(Default)] #[derive(Default)]
pub struct SimpleJobQueue(RefCell<VecDeque<NativeJob>>); pub struct SimpleJobQueue(RefCell<VecDeque<NativeJob>>);

3
boa_engine/src/lib.rs

@ -151,6 +151,7 @@ pub mod error;
pub mod job; pub mod job;
pub mod native_function; pub mod native_function;
pub mod object; pub mod object;
pub mod optimizer;
pub mod property; pub mod property;
pub mod realm; pub mod realm;
pub mod string; pub mod string;
@ -158,8 +159,6 @@ pub mod symbol;
pub mod value; pub mod value;
pub mod vm; pub mod vm;
pub mod optimizer;
#[cfg(feature = "console")] #[cfg(feature = "console")]
pub mod console; pub mod console;

37
boa_engine/src/object/builtins/jspromise.rs

@ -27,7 +27,6 @@ use super::{JsArray, JsFunction};
/// ``` /// ```
/// # use boa_engine::{ /// # use boa_engine::{
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # job::SimpleJobQueue,
/// # js_string, /// # js_string,
/// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # property::Attribute, /// # property::Attribute,
@ -35,8 +34,7 @@ use super::{JsArray, JsFunction};
/// # }; /// # };
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// context.register_global_property("finally", false, Attribute::all()); /// context.register_global_property("finally", false, Attribute::all());
/// ///
@ -131,14 +129,12 @@ impl JsPromise {
/// ``` /// ```
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # job::SimpleJobQueue,
/// # object::builtins::JsPromise, /// # object::builtins::JsPromise,
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # Context, JsValue, js_string /// # Context, JsValue, js_string
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// let promise = JsPromise::new(|resolvers, context| { /// let promise = JsPromise::new(|resolvers, context| {
/// let result = js_string!("hello world").into(); /// let result = js_string!("hello world").into();
@ -393,14 +389,12 @@ impl JsPromise {
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # job::SimpleJobQueue,
/// # js_string, /// # js_string,
/// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # Context, JsArgs, JsError, JsValue, NativeFunction, /// # Context, JsArgs, JsError, JsValue, NativeFunction,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// let promise = JsPromise::new( /// let promise = JsPromise::new(
/// |resolvers, context| { /// |resolvers, context| {
@ -461,13 +455,11 @@ impl JsPromise {
/// # use boa_engine::{ /// # use boa_engine::{
/// # js_string, /// # js_string,
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # job::SimpleJobQueue,
/// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # Context, JsArgs, JsNativeError, JsValue, NativeFunction, /// # Context, JsArgs, JsNativeError, JsValue, NativeFunction,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// let promise = JsPromise::new( /// let promise = JsPromise::new(
/// |resolvers, context| { /// |resolvers, context| {
@ -524,14 +516,12 @@ impl JsPromise {
/// ``` /// ```
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # job::SimpleJobQueue,
/// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # object::{builtins::JsPromise, FunctionObjectBuilder},
/// # property::Attribute, /// # property::Attribute,
/// # Context, JsNativeError, JsValue, NativeFunction, /// # Context, JsNativeError, JsValue, NativeFunction,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// context.register_global_property("finally", false, Attribute::all()); /// context.register_global_property("finally", false, Attribute::all());
/// ///
@ -594,14 +584,12 @@ impl JsPromise {
/// ``` /// ```
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # job::SimpleJobQueue,
/// # js_string, /// # js_string,
/// # object::builtins::{JsArray, JsPromise}, /// # object::builtins::{JsArray, JsPromise},
/// # Context, JsNativeError, JsValue, /// # Context, JsNativeError, JsValue,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// let promise1 = JsPromise::all( /// let promise1 = JsPromise::all(
/// [ /// [
@ -668,15 +656,12 @@ impl JsPromise {
/// ``` /// ```
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # job::SimpleJobQueue,
/// # js_string, /// # js_string,
/// # object::builtins::{JsArray, JsPromise}, /// # object::builtins::{JsArray, JsPromise},
/// # Context, JsNativeError, JsValue, /// # Context, JsNativeError, JsValue,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
///
/// ///
/// let promise = JsPromise::all_settled( /// let promise = JsPromise::all_settled(
/// [ /// [
@ -744,14 +729,12 @@ impl JsPromise {
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # job::SimpleJobQueue,
/// # js_string, /// # js_string,
/// # object::builtins::JsPromise, /// # object::builtins::JsPromise,
/// # Context, JsNativeError, /// # Context, JsNativeError,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// ///
/// let promise = JsPromise::any( /// let promise = JsPromise::any(
@ -807,14 +790,12 @@ impl JsPromise {
/// # use std::error::Error; /// # use std::error::Error;
/// # use boa_engine::{ /// # use boa_engine::{
/// # builtins::promise::PromiseState, /// # builtins::promise::PromiseState,
/// # job::SimpleJobQueue,
/// # js_string, /// # js_string,
/// # object::builtins::JsPromise, /// # object::builtins::JsPromise,
/// # Context, JsValue, /// # Context, JsValue,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let queue = &SimpleJobQueue::new(); /// let context = &mut Context::default();
/// let context = &mut Context::builder().job_queue(queue).build()?;
/// ///
/// let (a, resolvers_a) = JsPromise::new_pending(context); /// let (a, resolvers_a) = JsPromise::new_pending(context);
/// let (b, resolvers_b) = JsPromise::new_pending(context); /// let (b, resolvers_b) = JsPromise::new_pending(context);

11
boa_engine/src/tests/promise.rs

@ -1,14 +1,11 @@
use indoc::indoc; use indoc::indoc;
use crate::{job::SimpleJobQueue, run_test_actions_with, Context, TestAction}; use crate::{run_test_actions, TestAction};
#[test] #[test]
#[allow(clippy::redundant_closure_for_method_calls)] #[allow(clippy::redundant_closure_for_method_calls)]
fn issue_2658() { fn issue_2658() {
let queue = &SimpleJobQueue::new(); run_test_actions([
let context = &mut Context::builder().job_queue(queue).build().unwrap();
run_test_actions_with(
[
TestAction::run(indoc! { TestAction::run(indoc! {
r#" r#"
let result1; let result1;
@ -39,7 +36,5 @@ fn issue_2658() {
TestAction::assert_eq("result1.value", 5), TestAction::assert_eq("result1.value", 5),
TestAction::assert("!result2.done"), TestAction::assert("!result2.done"),
TestAction::assert_eq("result2.value", 5), TestAction::assert_eq("result2.value", 5),
], ]);
context,
);
} }

4
boa_examples/src/bin/futures.rs

@ -131,8 +131,8 @@ fn delay(
fn main() { fn main() {
// Initialize the required executors and the context // Initialize the required executors and the context
let executor = LocalExecutor::new(); let executor = LocalExecutor::new();
let queue = Queue::new(executor); let queue: &dyn JobQueue = &Queue::new(executor);
let context = &mut ContextBuilder::new().job_queue(&queue).build().unwrap(); let context = &mut ContextBuilder::new().job_queue(queue).build().unwrap();
// Bind the defined async function to the ECMAScript function "delay". // Bind the defined async function to the ECMAScript function "delay".
context context

11
boa_tester/src/exec/mod.rs

@ -7,9 +7,8 @@ use crate::{
TestFlags, TestOutcomeResult, TestResult, TestSuite, VersionedStats, TestFlags, TestOutcomeResult, TestResult, TestSuite, VersionedStats,
}; };
use boa_engine::{ use boa_engine::{
context::ContextBuilder, job::SimpleJobQueue, native_function::NativeFunction, native_function::NativeFunction, object::FunctionObjectBuilder, optimizer::OptimizerOptions,
object::FunctionObjectBuilder, optimizer::OptimizerOptions, property::Attribute, Context, property::Attribute, Context, JsArgs, JsNativeErrorKind, JsValue, Source,
JsArgs, JsNativeErrorKind, JsValue, Source,
}; };
use colored::Colorize; use colored::Colorize;
use fxhash::FxHashSet; use fxhash::FxHashSet;
@ -210,11 +209,7 @@ impl Test {
let result = std::panic::catch_unwind(|| match self.expected_outcome { let result = std::panic::catch_unwind(|| match self.expected_outcome {
Outcome::Positive => { Outcome::Positive => {
let async_result = AsyncResult::default(); let async_result = AsyncResult::default();
let queue = SimpleJobQueue::new(); let context = &mut Context::default();
let context = &mut ContextBuilder::new()
.job_queue(&queue)
.build()
.expect("cannot fail with default global");
if let Err(e) = self.set_up_env(harness, context, async_result.clone()) { if let Err(e) = self.set_up_env(harness, context, async_result.clone()) {
return (false, e); return (false, e);

Loading…
Cancel
Save