diff --git a/cli/main.rs b/cli/main.rs index 953e0194300242..891f18f3934d75 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -92,10 +92,9 @@ where } } -// TODO(ry) Move this to main.rs pub fn print_file_info(worker: &Worker, url: &str) { let maybe_out = - worker::fetch_module_meta_data_and_maybe_compile(&worker.state, url, "."); + state::fetch_module_meta_data_and_maybe_compile(&worker.state, url, "."); if let Err(err) = maybe_out { println!("{}", err); return; @@ -126,7 +125,8 @@ pub fn print_file_info(worker: &Worker, url: &str) { ); } - if let Some(deps) = worker.modules.deps(&out.module_name) { + let modules = worker.modules.lock().unwrap(); + if let Some(deps) = modules.deps(&out.module_name) { println!("{}{}", ansi::bold("deps:\n".to_string()), deps.name); if let Some(ref depsdeps) = deps.deps { for d in depsdeps { @@ -193,7 +193,7 @@ fn fetch_or_info_command( worker .execute_mod_async(&main_url, true) - .and_then(move |worker| { + .and_then(move |()| { if print_info { print_file_info(&worker, &main_module); } @@ -201,7 +201,7 @@ fn fetch_or_info_command( js_check(result); Ok(()) }) - }).map_err(|(err, _worker)| print_err_and_exit(err)) + }).map_err(print_err_and_exit) }); tokio_util::run(main_future); } @@ -289,12 +289,12 @@ fn run_script(flags: DenoFlags, argv: Vec) { worker .execute_mod_async(&main_url, false) - .and_then(move |worker| { + .and_then(move |()| { worker.then(|result| { js_check(result); Ok(()) }) - }).map_err(|(err, _worker)| print_err_and_exit(err)) + }).map_err(print_err_and_exit) }); tokio_util::run(main_future); } diff --git a/cli/ops.rs b/cli/ops.rs index e41c9caa20e18c..0e41eacc05606d 100644 --- a/cli/ops.rs +++ b/cli/ops.rs @@ -2067,7 +2067,7 @@ fn op_create_worker( // TODO(ry) Use execute_mod_async here. let result = worker.execute_mod(&specifier_url, false); match result { - Ok(worker) => { + Ok(()) => { let mut workers_tl = parent_state.workers.lock().unwrap(); workers_tl.insert(rid, worker.shared()); let builder = &mut FlatBufferBuilder::new(); @@ -2085,10 +2085,8 @@ fn op_create_worker( }, )) } - Err((errors::RustOrJsError::Js(_), _worker)) => { - Err(errors::worker_init_failed()) - } - Err((errors::RustOrJsError::Rust(err), _worker)) => Err(err), + Err(errors::RustOrJsError::Js(_)) => Err(errors::worker_init_failed()), + Err(errors::RustOrJsError::Rust(err)) => Err(err), } }())) } diff --git a/cli/state.rs b/cli/state.rs index dffd1202f9fcd8..cc3edec8773f98 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -1,18 +1,27 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +use crate::compiler::compile_async; +use crate::compiler::ModuleMetaData; use crate::deno_dir; +use crate::errors::DenoError; use crate::errors::DenoResult; use crate::flags; use crate::global_timer::GlobalTimer; +use crate::msg; use crate::ops; use crate::permissions::DenoPermissions; use crate::progress::Progress; use crate::resources; use crate::resources::ResourceId; +use crate::tokio_util; +use crate::worker::resolve_module_spec; use crate::worker::Worker; use deno::Buf; +use deno::Loader; use deno::Op; use deno::PinnedBuf; +use futures::future::Either; use futures::future::Shared; +use futures::Future; use std; use std::collections::HashMap; use std::collections::HashSet; @@ -94,6 +103,82 @@ impl ThreadSafeState { } } +fn fetch_module_meta_data_and_maybe_compile_async( + state: &ThreadSafeState, + specifier: &str, + referrer: &str, +) -> impl Future { + let state_ = state.clone(); + let specifier = specifier.to_string(); + let referrer = referrer.to_string(); + + let f = + futures::future::result(ThreadSafeState::resolve(&specifier, &referrer)); + f.and_then(move |module_id| { + let use_cache = !state_.flags.reload || state_.has_compiled(&module_id); + let no_fetch = state_.flags.no_fetch; + + state_ + .dir + .fetch_module_meta_data_async(&specifier, &referrer, use_cache, no_fetch) + .and_then(move |out| { + if out.media_type == msg::MediaType::TypeScript + && !out.has_output_code_and_source_map() + { + debug!(">>>>> compile_sync START"); + Either::A( + compile_async(state_.clone(), &specifier, &referrer, &out) + .map_err(|e| { + debug!("compiler error exiting!"); + eprintln!("\n{}", e.to_string()); + std::process::exit(1); + }).and_then(move |out| { + debug!(">>>>> compile_sync END"); + Ok(out) + }), + ) + } else { + Either::B(futures::future::ok(out)) + } + }) + }) +} + +pub fn fetch_module_meta_data_and_maybe_compile( + state: &ThreadSafeState, + specifier: &str, + referrer: &str, +) -> Result { + tokio_util::block_on(fetch_module_meta_data_and_maybe_compile_async( + state, specifier, referrer, + )) +} + +impl Loader for ThreadSafeState { + type Error = DenoError; + + fn resolve(specifier: &str, referrer: &str) -> Result { + resolve_module_spec(specifier, referrer).map_err(DenoError::from) + } + + /// Given an absolute url, load its source code. + fn load(&self, url: &str) -> Box> { + self.metrics.resolve_count.fetch_add(1, Ordering::SeqCst); + Box::new( + fetch_module_meta_data_and_maybe_compile_async(self, url, ".") + .map_err(|err| { + eprintln!("{}", err); + err + }).map(|module_meta_data| deno::SourceCodeInfo { + // Real module name, might be different from initial URL + // due to redirections. + code: module_meta_data.js_source(), + module_name: module_meta_data.module_name, + }), + ) + } +} + impl ThreadSafeState { pub fn new( flags: flags::DenoFlags, diff --git a/cli/worker.rs b/cli/worker.rs index c08a4338577743..f95826674f8ab9 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -1,28 +1,25 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -use crate::compiler::compile_async; -use crate::compiler::ModuleMetaData; use crate::errors::DenoError; use crate::errors::RustOrJsError; use crate::js_errors; -use crate::msg; use crate::state::ThreadSafeState; use crate::tokio_util; use deno; use deno::Config; use deno::JSError; -use deno::Loader; use deno::StartupData; -use futures::future::Either; use futures::Async; use futures::Future; -use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::sync::Mutex; use url::Url; /// Wraps deno::Isolate to provide source maps, ops for the CLI, and /// high-level module loading +#[derive(Clone)] pub struct Worker { - inner: deno::Isolate, - pub modules: deno::Modules, + inner: Arc>, + pub modules: Arc>, pub state: ThreadSafeState, } @@ -38,8 +35,8 @@ impl Worker { state_.dispatch(control_buf, zero_copy_buf) }); Self { - inner: deno::Isolate::new(startup_data, config), - modules: deno::Modules::new(), + inner: Arc::new(Mutex::new(deno::Isolate::new(startup_data, config))), + modules: Arc::new(Mutex::new(deno::Modules::new())), state, } } @@ -56,48 +53,55 @@ impl Worker { js_filename: &str, js_source: &str, ) -> Result<(), JSError> { - self.inner.execute(js_filename, js_source) + let mut isolate = self.inner.lock().unwrap(); + isolate.execute(js_filename, js_source) } /// Consumes worker. Executes the provided JavaScript module. pub fn execute_mod_async( - self, + &mut self, js_url: &Url, is_prefetch: bool, - ) -> impl Future { - let recursive_load = deno::RecursiveLoad::new(js_url.as_str(), self); - recursive_load.and_then( - move |(id, mut self_)| -> Result, Self)> { - self_.state.progress.done(); + ) -> impl Future { + let worker = self.clone(); + let worker_ = worker.clone(); + let loader = self.state.clone(); + let isolate = self.inner.clone(); + let modules = self.modules.clone(); + let recursive_load = + deno::RecursiveLoad::new(js_url.as_str(), loader, isolate, modules); + recursive_load + .and_then(move |id| -> Result<(), deno::JSErrorOr> { + worker.state.progress.done(); if is_prefetch { - Ok(self_) + Ok(()) } else { - let result = self_.inner.mod_evaluate(id); + let mut isolate = worker.inner.lock().unwrap(); + let result = isolate.mod_evaluate(id); if let Err(err) = result { - Err((deno::JSErrorOr::JSError(err), self_)) + Err(deno::JSErrorOr::JSError(err)) } else { - Ok(self_) + Ok(()) } } - }, - ) - .map_err(|(err, self_)| { - self_.state.progress.done(); - // Convert to RustOrJsError AND apply_source_map. - let err = match err { - deno::JSErrorOr::JSError(err) => RustOrJsError::Js(self_.apply_source_map(err)), - deno::JSErrorOr::Other(err) => RustOrJsError::Rust(err), - }; - (err, self_) - }) + }).map_err(move |err| { + worker_.state.progress.done(); + // Convert to RustOrJsError AND apply_source_map. + match err { + deno::JSErrorOr::JSError(err) => { + RustOrJsError::Js(worker_.apply_source_map(err)) + } + deno::JSErrorOr::Other(err) => RustOrJsError::Rust(err), + } + }) } /// Consumes worker. Executes the provided JavaScript module. pub fn execute_mod( - self, + &mut self, js_url: &Url, is_prefetch: bool, - ) -> Result { + ) -> Result<(), RustOrJsError> { tokio_util::block_on(self.execute_mod_async(js_url, is_prefetch)) } @@ -159,103 +163,16 @@ pub fn root_specifier_to_url( } } -impl Loader for Worker { - type Error = DenoError; - - fn resolve(specifier: &str, referrer: &str) -> Result { - resolve_module_spec(specifier, referrer).map_err(DenoError::from) - } - - /// Given an absolute url, load its source code. - fn load( - &mut self, - url: &str, - ) -> Box> { - self - .state - .metrics - .resolve_count - .fetch_add(1, Ordering::SeqCst); - Box::new( - fetch_module_meta_data_and_maybe_compile_async(&self.state, url, ".") - .map_err(|err| { - eprintln!("{}", err); - err - }).map(|module_meta_data| deno::SourceCodeInfo { - // Real module name, might be different from initial URL - // due to redirections. - code: module_meta_data.js_source(), - module_name: module_meta_data.module_name, - }), - ) - } - - fn isolate_and_modules<'a: 'b + 'c, 'b, 'c>( - &'a mut self, - ) -> (&'b mut deno::Isolate, &'c mut deno::Modules) { - (&mut self.inner, &mut self.modules) - } -} - impl Future for Worker { type Item = (); type Error = JSError; fn poll(&mut self) -> Result, Self::Error> { - self.inner.poll().map_err(|err| self.apply_source_map(err)) + let mut isolate = self.inner.lock().unwrap(); + isolate.poll().map_err(|err| self.apply_source_map(err)) } } -fn fetch_module_meta_data_and_maybe_compile_async( - state: &ThreadSafeState, - specifier: &str, - referrer: &str, -) -> impl Future { - let state_ = state.clone(); - let specifier = specifier.to_string(); - let referrer = referrer.to_string(); - - let f = futures::future::result(Worker::resolve(&specifier, &referrer)); - f.and_then(move |module_id| { - let use_cache = !state_.flags.reload || state_.has_compiled(&module_id); - let no_fetch = state_.flags.no_fetch; - - state_ - .dir - .fetch_module_meta_data_async(&specifier, &referrer, use_cache, no_fetch) - .and_then(move |out| { - if out.media_type == msg::MediaType::TypeScript - && !out.has_output_code_and_source_map() - { - debug!(">>>>> compile_sync START"); - Either::A( - compile_async(state_.clone(), &specifier, &referrer, &out) - .map_err(|e| { - debug!("compiler error exiting!"); - eprintln!("\n{}", e.to_string()); - std::process::exit(1); - }).and_then(move |out| { - debug!(">>>>> compile_sync END"); - Ok(out) - }), - ) - } else { - Either::B(futures::future::ok(out)) - } - }) - }) -} - -pub fn fetch_module_meta_data_and_maybe_compile( - state: &ThreadSafeState, - specifier: &str, - referrer: &str, -) -> Result { - tokio_util::block_on(fetch_module_meta_data_and_maybe_compile_async( - state, specifier, referrer, - )) -} - #[cfg(test)] mod tests { use super::*; @@ -286,15 +203,12 @@ mod tests { ); let state_ = state.clone(); tokio_util::run(lazy(move || { - let worker = Worker::new("TEST".to_string(), StartupData::None, state); + let mut worker = + Worker::new("TEST".to_string(), StartupData::None, state); let result = worker.execute_mod(&js_url, false); - let worker = match result { - Err((err, worker)) => { - eprintln!("execute_mod err {:?}", err); - worker - } - Ok(worker) => worker, - }; + if let Err(err) = result { + eprintln!("execute_mod err {:?}", err); + } tokio_util::panic_on_error(worker) })); @@ -318,15 +232,12 @@ mod tests { ); let state_ = state.clone(); tokio_util::run(lazy(move || { - let worker = Worker::new("TEST".to_string(), StartupData::None, state); + let mut worker = + Worker::new("TEST".to_string(), StartupData::None, state); let result = worker.execute_mod(&js_url, false); - let worker = match result { - Err((err, worker)) => { - eprintln!("execute_mod err {:?}", err); - worker - } - Ok(worker) => worker, - }; + if let Err(err) = result { + eprintln!("execute_mod err {:?}", err); + } tokio_util::panic_on_error(worker) })); @@ -356,13 +267,9 @@ mod tests { ); js_check(worker.execute("denoMain()")); let result = worker.execute_mod(&js_url, false); - let worker = match result { - Err((err, worker)) => { - eprintln!("execute_mod err {:?}", err); - worker - } - Ok(worker) => worker, - }; + if let Err(err) = result { + eprintln!("execute_mod err {:?}", err); + } tokio_util::panic_on_error(worker) })); @@ -470,7 +377,7 @@ mod tests { fn execute_mod_resolve_error() { tokio_util::init(|| { // "foo" is not a vailid module specifier so this should return an error. - let worker = create_test_worker(); + let mut worker = create_test_worker(); let js_url = root_specifier_to_url("does-not-exist").unwrap(); let result = worker.execute_mod_async(&js_url, false).wait(); assert!(result.is_err()); @@ -482,7 +389,7 @@ mod tests { tokio_util::init(|| { // This assumes cwd is project root (an assumption made throughout the // tests). - let worker = create_test_worker(); + let mut worker = create_test_worker(); let js_url = root_specifier_to_url("./tests/002_hello.ts").unwrap(); let result = worker.execute_mod_async(&js_url, false).wait(); assert!(result.is_ok()); diff --git a/core/modules.rs b/core/modules.rs index 0fb3147cb20f69..8a600fd7e031ec 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -17,6 +17,8 @@ use std::collections::HashSet; use std::error::Error; use std::fmt; use std::marker::PhantomData; +use std::sync::Arc; +use std::sync::Mutex; /// Represent result of fetching the source code of a module. /// Contains both module name and code. @@ -34,7 +36,7 @@ pub struct SourceCodeInfo { pub type SourceCodeInfoFuture = dyn Future + Send; -pub trait Loader { +pub trait Loader: Send + Sync { type Error: std::error::Error + 'static; /// Returns an absolute URL. @@ -44,21 +46,7 @@ pub trait Loader { fn resolve(specifier: &str, referrer: &str) -> Result; /// Given an absolute url, load its source code. - fn load(&mut self, url: &str) -> Box>; - - fn isolate_and_modules<'a: 'b + 'c, 'b, 'c>( - &'a mut self, - ) -> (&'b mut Isolate, &'c mut Modules); - - fn isolate<'a: 'b, 'b>(&'a mut self) -> &'b mut Isolate { - let (isolate, _) = self.isolate_and_modules(); - isolate - } - - fn modules<'a: 'b, 'b>(&'a mut self) -> &'b mut Modules { - let (_, modules) = self.isolate_and_modules(); - modules - } + fn load(&self, url: &str) -> Box>; } struct PendingLoad { @@ -71,7 +59,9 @@ struct PendingLoad { /// complicating the Isolate API. Note that RecursiveLoad will take ownership of /// an Isolate during load. pub struct RecursiveLoad { - loader: Option, + loader: L, + isolate: Arc>, + modules: Arc>, pending: Vec>, is_pending: HashSet, phantom: PhantomData, @@ -83,9 +73,16 @@ pub struct RecursiveLoad { impl RecursiveLoad { /// Starts a new parallel load of the given URL. - pub fn new(url: &str, loader: L) -> Self { + pub fn new( + url: &str, + loader: L, + isolate: Arc>, + modules: Arc>, + ) -> Self { Self { - loader: Some(loader), + loader, + isolate, + modules, root: None, root_specifier: Some(url.to_string()), root_id: None, @@ -95,10 +92,6 @@ impl RecursiveLoad { } } - fn take_loader(&mut self) -> L { - self.loader.take().unwrap() - } - fn add( &mut self, specifier: &str, @@ -108,20 +101,20 @@ impl RecursiveLoad { let url = L::resolve(specifier, referrer)?; let is_root = if let Some(parent_id) = parent_id { - let loader = self.loader.as_mut().unwrap(); - let modules = loader.modules(); - modules.add_child(parent_id, &url); + { + let mut m = self.modules.lock().unwrap(); + m.add_child(parent_id, &url); + } false } else { true }; { - let loader = self.loader.as_mut().unwrap(); - let modules = loader.modules(); // #B We only add modules that have not yet been resolved for RecursiveLoad. // Only short circuit after add_child(). // This impacts possible conditions in #A. + let modules = self.modules.lock().unwrap(); if modules.is_registered(&url) { return Ok(url); } @@ -129,10 +122,7 @@ impl RecursiveLoad { if !self.is_pending.contains(&url) { self.is_pending.insert(url.clone()); - let source_code_info_future = { - let loader = self.loader.as_mut().unwrap(); - loader.load(&url) - }; + let source_code_info_future = { self.loader.load(&url) }; self.pending.push(PendingLoad { url: url.clone(), source_code_info_future, @@ -153,15 +143,15 @@ pub enum JSErrorOr { } impl Future for RecursiveLoad { - type Item = (deno_mod, L); - type Error = (JSErrorOr, L); + type Item = deno_mod; + type Error = JSErrorOr; fn poll(&mut self) -> Poll { if self.root.is_none() && self.root_specifier.is_some() { let s = self.root_specifier.take().unwrap(); match self.add(&s, ".", None) { Err(err) => { - return Err((JSErrorOr::Other(err), self.take_loader())); + return Err(JSErrorOr::Other(err)); } Ok(root) => { self.root = Some(root); @@ -176,7 +166,7 @@ impl Future for RecursiveLoad { let pending = &mut self.pending[i]; match pending.source_code_info_future.poll() { Err(err) => { - return Err((JSErrorOr::Other(err), self.take_loader())); + return Err(JSErrorOr::Other(err)); } Ok(Async::NotReady) => { i += 1; @@ -195,8 +185,7 @@ impl Future for RecursiveLoad { // 2b. The module with resolved module name has not yet been registerd // -> register & alias let is_module_registered = { - let loader = self.loader.as_mut().unwrap(); - let modules = loader.modules(); + let modules = self.modules.lock().unwrap(); modules.is_registered(&source_code_info.module_name) }; @@ -206,8 +195,7 @@ impl Future for RecursiveLoad { let module_name = &source_code_info.module_name; let result = { - let loader = self.loader.as_mut().unwrap(); - let isolate = loader.isolate(); + let isolate = self.isolate.lock().unwrap(); isolate.mod_new( completed.is_root, module_name, @@ -215,7 +203,7 @@ impl Future for RecursiveLoad { ) }; if let Err(err) = result { - return Err((JSErrorOr::JSError(err), self.take_loader())); + return Err(JSErrorOr::JSError(err)); } let mod_id = result.unwrap(); if completed.is_root { @@ -225,8 +213,7 @@ impl Future for RecursiveLoad { // Register new module. { - let loader = self.loader.as_mut().unwrap(); - let modules = loader.modules(); + let mut modules = self.modules.lock().unwrap(); modules.register(mod_id, module_name); // If necessary, register the alias. if need_alias { @@ -237,19 +224,17 @@ impl Future for RecursiveLoad { // Now we must iterate over all imports of the module and load them. let imports = { - let loader = self.loader.as_mut().unwrap(); - let isolate = loader.isolate(); + let isolate = self.isolate.lock().unwrap(); isolate.mod_get_imports(mod_id) }; let referrer = module_name; for specifier in imports { self .add(&specifier, referrer, Some(mod_id)) - .map_err(|e| (JSErrorOr::Other(e), self.take_loader()))?; + .map_err(JSErrorOr::Other)?; } } else if need_alias { - let loader = self.loader.as_mut().unwrap(); - let modules = loader.modules(); + let mut modules = self.modules.lock().unwrap(); modules.alias(&completed.url, &source_code_info.module_name); } } @@ -261,11 +246,10 @@ impl Future for RecursiveLoad { } let root_id = self.root_id.unwrap(); - let mut loader = self.take_loader(); - let (isolate, modules) = loader.isolate_and_modules(); let result = { let mut resolve_cb = |specifier: &str, referrer_id: deno_mod| -> deno_mod { + let modules = self.modules.lock().unwrap(); let referrer = modules.get_name(referrer_id).unwrap(); match L::resolve(specifier, &referrer) { Ok(url) => match modules.get_id(&url) { @@ -278,12 +262,13 @@ impl Future for RecursiveLoad { } }; + let mut isolate = self.isolate.lock().unwrap(); isolate.mod_instantiate(root_id, &mut resolve_cb) }; match result { - Err(err) => Err((JSErrorOr::JSError(err), loader)), - Ok(()) => Ok(Async::Ready((root_id, loader))), + Err(err) => Err(JSErrorOr::JSError(err)), + Ok(()) => Ok(Async::Ready(root_id)), } } } @@ -548,9 +533,9 @@ mod tests { use std::fmt; struct MockLoader { - pub loads: Vec, - pub isolate: Isolate, - pub modules: Modules, + pub loads: Arc>>, + pub isolate: Arc>, + pub modules: Arc>, } impl MockLoader { @@ -558,9 +543,9 @@ mod tests { let modules = Modules::new(); let (isolate, _dispatch_count) = setup(Mode::AsyncImmediate); Self { - loads: Vec::new(), - isolate, - modules, + loads: Arc::new(Mutex::new(Vec::new())), + isolate: Arc::new(Mutex::new(isolate)), + modules: Arc::new(Mutex::new(modules)), } } } @@ -663,17 +648,12 @@ mod tests { } } - fn load(&mut self, url: &str) -> Box> { - self.loads.push(url.to_string()); + fn load(&self, url: &str) -> Box> { + let mut loads = self.loads.lock().unwrap(); + loads.push(url.to_string()); let url = url.to_string(); Box::new(DelayedSourceCodeFuture { url, counter: 0 }) } - - fn isolate_and_modules<'a: 'b + 'c, 'b, 'c>( - &'a mut self, - ) -> (&'b mut Isolate, &'c mut Modules) { - (&mut self.isolate, &mut self.modules) - } } const A_SRC: &str = r#" @@ -710,15 +690,24 @@ mod tests { #[test] fn test_recursive_load() { let loader = MockLoader::new(); - let mut recursive_load = RecursiveLoad::new("a.js", loader); + let modules = loader.modules.clone(); + let modules_ = modules.clone(); + let isolate = loader.isolate.clone(); + let isolate_ = isolate.clone(); + let loads = loader.loads.clone(); + let mut recursive_load = + RecursiveLoad::new("a.js", loader, isolate, modules); let result = recursive_load.poll(); assert!(result.is_ok()); - if let Async::Ready((a_id, mut loader)) = result.ok().unwrap() { - js_check(loader.isolate.mod_evaluate(a_id)); - assert_eq!(loader.loads, vec!["a.js", "b.js", "c.js", "d.js"]); + if let Async::Ready(a_id) = result.ok().unwrap() { + let mut isolate = isolate_.lock().unwrap(); + js_check(isolate.mod_evaluate(a_id)); + + let l = loads.lock().unwrap(); + assert_eq!(l.to_vec(), vec!["a.js", "b.js", "c.js", "d.js"]); - let modules = &loader.modules; + let modules = modules_.lock().unwrap(); assert_eq!(modules.get_id("a.js"), Some(a_id)); let b_id = modules.get_id("b.js").unwrap(); @@ -756,18 +745,27 @@ mod tests { #[test] fn test_circular_load() { let loader = MockLoader::new(); - let mut recursive_load = RecursiveLoad::new("circular1.js", loader); + let isolate = loader.isolate.clone(); + let isolate_ = isolate.clone(); + let modules = loader.modules.clone(); + let modules_ = modules.clone(); + let loads = loader.loads.clone(); + let mut recursive_load = + RecursiveLoad::new("circular1.js", loader, isolate, modules); let result = recursive_load.poll(); assert!(result.is_ok()); - if let Async::Ready((circular1_id, mut loader)) = result.ok().unwrap() { - js_check(loader.isolate.mod_evaluate(circular1_id)); + if let Async::Ready(circular1_id) = result.ok().unwrap() { + let mut isolate = isolate_.lock().unwrap(); + js_check(isolate.mod_evaluate(circular1_id)); + + let l = loads.lock().unwrap(); assert_eq!( - loader.loads, + l.to_vec(), vec!["circular1.js", "circular2.js", "circular3.js"] ); - let modules = &loader.modules; + let modules = modules_.lock().unwrap(); assert_eq!(modules.get_id("circular1.js"), Some(circular1_id)); let circular2_id = modules.get_id("circular2.js").unwrap(); @@ -813,18 +811,26 @@ mod tests { #[test] fn test_redirect_load() { let loader = MockLoader::new(); - let mut recursive_load = RecursiveLoad::new("redirect1.js", loader); + let isolate = loader.isolate.clone(); + let isolate_ = isolate.clone(); + let modules = loader.modules.clone(); + let modules_ = modules.clone(); + let loads = loader.loads.clone(); + let mut recursive_load = + RecursiveLoad::new("redirect1.js", loader, isolate, modules); let result = recursive_load.poll(); assert!(result.is_ok()); - if let Async::Ready((redirect1_id, mut loader)) = result.ok().unwrap() { - js_check(loader.isolate.mod_evaluate(redirect1_id)); + if let Async::Ready(redirect1_id) = result.ok().unwrap() { + let mut isolate = isolate_.lock().unwrap(); + js_check(isolate.mod_evaluate(redirect1_id)); + let l = loads.lock().unwrap(); assert_eq!( - loader.loads, + l.to_vec(), vec!["redirect1.js", "./redirect2.js", "./dir/redirect3.js"] ); - let modules = &loader.modules; + let modules = modules_.lock().unwrap(); assert_eq!(modules.get_id("redirect1.js"), Some(redirect1_id)); @@ -861,24 +867,28 @@ mod tests { #[test] fn slow_never_ready_modules() { let loader = MockLoader::new(); - let mut recursive_load = RecursiveLoad::new("main.js", loader); + let isolate = loader.isolate.clone(); + let modules = loader.modules.clone(); + let loads = loader.loads.clone(); + let mut recursive_load = + RecursiveLoad::new("main.js", loader, isolate, modules); let result = recursive_load.poll(); assert!(result.is_ok()); assert!(result.ok().unwrap().is_not_ready()); { - let loader = recursive_load.loader.as_ref().unwrap(); - assert_eq!(loader.loads, vec!["main.js", "never_ready.js", "slow.js"]); + let l = loads.lock().unwrap(); + assert_eq!(l.to_vec(), vec!["main.js", "never_ready.js", "slow.js"]); } for _ in 0..10 { let result = recursive_load.poll(); assert!(result.is_ok()); assert!(result.ok().unwrap().is_not_ready()); - let loader = recursive_load.loader.as_ref().unwrap(); + let l = loads.lock().unwrap();; assert_eq!( - loader.loads, + l.to_vec(), vec![ "main.js", "never_ready.js", @@ -900,12 +910,14 @@ mod tests { #[test] fn loader_disappears_after_error() { let loader = MockLoader::new(); - let mut recursive_load = RecursiveLoad::new("bad_import.js", loader); + let isolate = loader.isolate.clone(); + let modules = loader.modules.clone(); + let mut recursive_load = + RecursiveLoad::new("bad_import.js", loader, isolate, modules); let result = recursive_load.poll(); assert!(result.is_err()); - let (either_err, _loader) = result.err().unwrap(); + let either_err = result.err().unwrap(); assert_eq!(either_err, JSErrorOr::Other(MockError::ResolveErr)); - assert!(recursive_load.loader.is_none()); } #[test]