1use std::{
2 collections::{HashMap, HashSet},
3 path::{Path, PathBuf},
4 pin::Pin,
5 rc::Rc,
6 sync::Arc,
7 task::Poll,
8 time::Duration,
9};
10
11use deno_core::{
12 futures::FutureExt, serde_json, serde_v8::from_v8, v8, JsRuntime, JsRuntimeForSnapshot,
13 PollEventLoopOptions,
14};
15use deno_features::FeatureChecker;
16use serde::de::DeserializeOwned;
17use tokio_util::sync::CancellationToken;
18
19use crate::{
20 ext,
21 module_loader::{LoaderOptions, RustyLoader},
22 traits::{ToDefinedValue, ToModuleSpecifier, ToV8String},
23 transpiler::transpile,
24 utilities, Error, ExtensionOptions, Module, ModuleHandle,
25};
26
27pub trait RuntimeTrait {
29 fn try_new(options: deno_core::RuntimeOptions) -> Result<Self, Error>
30 where
31 Self: Sized;
32 fn rt_mut(&mut self) -> &mut JsRuntime;
33}
34impl RuntimeTrait for JsRuntime {
35 fn try_new(options: deno_core::RuntimeOptions) -> Result<Self, Error>
36 where
37 Self: Sized,
38 {
39 let rt = Self::try_new(options)?;
40 Ok(rt)
41 }
42 fn rt_mut(&mut self) -> &mut JsRuntime {
43 self
44 }
45}
46impl RuntimeTrait for JsRuntimeForSnapshot {
47 fn try_new(options: deno_core::RuntimeOptions) -> Result<Self, Error>
48 where
49 Self: Sized,
50 {
51 let rt = Self::try_new(options)?;
52 Ok(rt)
53 }
54 fn rt_mut(&mut self) -> &mut JsRuntime {
55 self
56 }
57}
58
59pub trait RsFunction:
61 Fn(&[serde_json::Value]) -> Result<serde_json::Value, Error> + 'static
62{
63}
64impl<F> RsFunction for F where
65 F: Fn(&[serde_json::Value]) -> Result<serde_json::Value, Error> + 'static
66{
67}
68
69pub trait RsAsyncFunction:
71 Fn(
72 Vec<serde_json::Value>,
73 ) -> Pin<Box<dyn std::future::Future<Output = Result<serde_json::Value, Error>>>>
74 + 'static
75{
76}
77impl<F> RsAsyncFunction for F where
78 F: Fn(
79 Vec<serde_json::Value>,
80 ) -> Pin<Box<dyn std::future::Future<Output = Result<serde_json::Value, Error>>>>
81 + 'static
82{
83}
84
85fn decode_args<'a>(
89 args: &impl serde::ser::Serialize,
90 scope: &mut v8::HandleScope<'a>,
91) -> Result<Vec<v8::Local<'a, v8::Value>>, Error> {
92 let args = deno_core::serde_v8::to_v8(scope, args)?;
93 match v8::Local::<v8::Array>::try_from(args) {
94 Ok(args) => {
95 let len = args.length();
96 let mut result = Vec::with_capacity(len as usize);
97 for i in 0..len {
98 let index = v8::Integer::new(
99 scope,
100 i.try_into().map_err(|_| {
101 Error::Runtime(format!(
102 "Could not decode {len} arguments - use `big_json_args`"
103 ))
104 })?,
105 );
106 let arg = args
107 .get(scope, index.into())
108 .ok_or_else(|| Error::Runtime(format!("Invalid argument at index {i}")))?;
109 result.push(arg);
110 }
111 Ok(result)
112 }
113 Err(_) if args.is_undefined() || args.is_null() => Ok(vec![]),
114 Err(_) => Ok(vec![args]),
115 }
116}
117
118pub struct RuntimeOptions {
120 pub extensions: Vec<deno_core::Extension>,
122
123 pub extension_options: ext::ExtensionOptions,
125
126 pub default_entrypoint: Option<String>,
128
129 pub timeout: Duration,
131
132 pub max_heap_size: Option<usize>,
139
140 #[allow(deprecated)]
142 pub module_cache: Option<Box<dyn crate::module_loader::ModuleCacheProvider>>,
143
144 pub import_provider: Option<Box<dyn crate::module_loader::ImportProvider>>,
146
147 pub startup_snapshot: Option<&'static [u8]>,
153
154 pub isolate_params: Option<v8::CreateParams>,
160
161 pub shared_array_buffer_store: Option<deno_core::SharedArrayBufferStore>,
165
166 pub schema_whlist: HashSet<String>,
170}
171
172impl Default for RuntimeOptions {
173 fn default() -> Self {
174 Self {
175 extensions: Vec::default(),
176 default_entrypoint: None,
177 timeout: Duration::MAX,
178 max_heap_size: None,
179 module_cache: None,
180 import_provider: None,
181 startup_snapshot: None,
182 isolate_params: None,
183 shared_array_buffer_store: None,
184 schema_whlist: HashSet::default(),
185
186 extension_options: ExtensionOptions::default(),
187 }
188 }
189}
190
191pub struct InnerRuntime<RT: RuntimeTrait> {
198 pub module_loader: Rc<RustyLoader>,
199 pub deno_runtime: RT,
200
201 pub cwd: PathBuf,
202 pub default_entrypoint: Option<String>,
203}
204impl<RT: RuntimeTrait> InnerRuntime<RT> {
205 pub fn new(
206 options: RuntimeOptions,
207 heap_exhausted_token: CancellationToken,
208 ) -> Result<Self, Error> {
209 let cwd = std::env::current_dir()?;
210 let module_loader = Rc::new(RustyLoader::new(LoaderOptions {
211 cache_provider: options.module_cache,
212 import_provider: options.import_provider,
213 schema_whlist: options.schema_whlist,
214 cwd: cwd.clone(),
215
216 #[cfg(feature = "node_experimental")]
217 node_resolver: options.extension_options.node_resolver.clone(),
218
219 ..Default::default()
220 }));
221
222 let is_snapshot = options.startup_snapshot.is_some();
224 let extensions = ext::all_extensions(
225 options.extensions,
226 options.extension_options,
227 options.shared_array_buffer_store.clone(),
228 is_snapshot,
229 );
230
231 let isolate_params = match options.isolate_params {
233 Some(params) => {
234 if let Some(max_heap_size) = options.max_heap_size {
235 Some(params.heap_limits(0, max_heap_size))
236 } else {
237 Some(params)
238 }
239 }
240 None => {
241 if let Some(max_heap_size) = options.max_heap_size {
242 let params = v8::Isolate::create_params().heap_limits(0, max_heap_size);
243 Some(params)
244 } else {
245 None
246 }
247 }
248 };
249
250 let mut deno_runtime = RT::try_new(deno_core::RuntimeOptions {
251 module_loader: Some(module_loader.clone()),
252
253 extension_transpiler: Some(module_loader.as_extension_transpiler()),
254 create_params: isolate_params,
255 shared_array_buffer_store: options.shared_array_buffer_store.clone(),
256
257 startup_snapshot: options.startup_snapshot,
258 extensions,
259
260 ..Default::default()
261 })?;
262
263 let mut feature_checker = FeatureChecker::default();
264 feature_checker.set_exit_cb(Box::new(|_, _| {}));
265 deno_runtime
266 .rt_mut()
267 .op_state()
268 .borrow_mut()
269 .put(Arc::new(feature_checker));
270
271 if options.max_heap_size.is_some() {
273 let isolate_handle = deno_runtime.rt_mut().v8_isolate().thread_safe_handle();
274
275 deno_runtime
276 .rt_mut()
277 .add_near_heap_limit_callback(move |current_value, _| {
278 isolate_handle.terminate_execution();
279
280 heap_exhausted_token.cancel();
282
283 5 * current_value
286 });
287 }
288
289 let default_entrypoint = options.default_entrypoint;
290 Ok(Self {
291 module_loader,
292 deno_runtime,
293 cwd,
294 default_entrypoint,
295 })
296 }
297
298 #[allow(dead_code)]
300 pub fn into_inner(self) -> RT {
301 self.deno_runtime
302 }
303
304 pub fn deno_runtime(&mut self) -> &mut JsRuntime {
306 self.deno_runtime.rt_mut()
307 }
308
309 pub fn set_current_dir(&mut self, path: impl AsRef<Path>) -> Result<&Path, Error> {
312 let path = path.as_ref();
313 let path = utilities::resolve_path(path, Some(&self.cwd))?
314 .to_file_path()
315 .map_err(|()| Error::Runtime("Invalid path".to_string()))?;
316
317 self.cwd = path;
318 self.module_loader.set_current_dir(self.cwd.clone());
319 Ok(&self.cwd)
320 }
321
322 pub fn current_dir(&self) -> &Path {
323 &self.cwd
324 }
325
326 pub fn take<T>(&mut self) -> Option<T>
328 where
329 T: 'static,
330 {
331 let state = self.deno_runtime().op_state();
332 if let Ok(mut state) = state.try_borrow_mut() {
333 if state.has::<T>() {
334 return Some(state.take());
335 }
336 }
337
338 None
339 }
340
341 pub fn put<T>(&mut self, value: T) -> Result<(), Error>
344 where
345 T: 'static,
346 {
347 let state = self.deno_runtime().op_state();
348 let mut state = state.try_borrow_mut()?;
349 state.put(value);
350
351 Ok(())
352 }
353
354 pub fn register_async_function<F>(&mut self, name: &str, callback: F) -> Result<(), Error>
358 where
359 F: RsAsyncFunction,
360 {
361 let state = self.deno_runtime().op_state();
362 let mut state = state.try_borrow_mut()?;
363
364 if !state.has::<HashMap<String, Box<dyn RsAsyncFunction>>>() {
365 state.put(HashMap::<String, Box<dyn RsAsyncFunction>>::new());
366 }
367
368 state
370 .borrow_mut::<HashMap<String, Box<dyn RsAsyncFunction>>>()
371 .insert(name.to_string(), Box::new(callback));
372
373 Ok(())
374 }
375
376 pub fn register_function<F>(&mut self, name: &str, callback: F) -> Result<(), Error>
380 where
381 F: RsFunction,
382 {
383 let state = self.deno_runtime().op_state();
384 let mut state = state.try_borrow_mut()?;
385
386 if !state.has::<HashMap<String, Box<dyn RsFunction>>>() {
387 state.put(HashMap::<String, Box<dyn RsFunction>>::new());
388 }
389
390 state
392 .borrow_mut::<HashMap<String, Box<dyn RsFunction>>>()
393 .insert(name.to_string(), Box::new(callback));
394
395 Ok(())
396 }
397
398 pub async fn await_event_loop(
400 &mut self,
401 options: PollEventLoopOptions,
402 timeout: Option<Duration>,
403 ) -> Result<(), Error> {
404 if let Some(timeout) = timeout {
405 Ok(tokio::select! {
406 r = self.deno_runtime().run_event_loop(options) => r,
407 () = tokio::time::sleep(timeout) => Ok(()),
408 }?)
409 } else {
410 Ok(self.deno_runtime().run_event_loop(options).await?)
411 }
412 }
413
414 pub async fn advance_event_loop(
417 &mut self,
418 options: PollEventLoopOptions,
419 ) -> Result<bool, Error> {
420 let result = std::future::poll_fn(|cx| {
421 Poll::Ready(match self.deno_runtime().poll_event_loop(cx, options) {
422 Poll::Ready(t) => t.map(|()| false),
423 Poll::Pending => Ok(true),
424 })
425 })
426 .await?;
427
428 Ok(result)
429 }
430
431 #[allow(clippy::unused_async, reason = "Prevent panic on sleep calls")]
444 pub async fn eval(&mut self, expr: impl ToString) -> Result<v8::Global<v8::Value>, Error> {
445 let result = self.deno_runtime().execute_script("", expr.to_string())?;
446 Ok(result)
447 }
448
449 pub fn get_global_value(&mut self, name: &str) -> Result<v8::Global<v8::Value>, Error> {
457 let context = self.deno_runtime().main_context();
458 let mut scope = self.deno_runtime().handle_scope();
459 let global = context.open(&mut scope).global(&mut scope);
460
461 let key = name.to_v8_string(&mut scope)?;
462 let value = global.get(&mut scope, key.into());
463
464 match value.if_defined() {
465 Some(v) => Ok(v8::Global::<v8::Value>::new(&mut scope, v)),
466 _ => Err(Error::ValueNotFound(name.to_string())),
467 }
468 }
469
470 pub fn get_module_export_value(
479 &mut self,
480 module_context: &ModuleHandle,
481 name: &str,
482 ) -> Result<v8::Global<v8::Value>, Error> {
483 let module_namespace = self
484 .deno_runtime()
485 .get_module_namespace(module_context.id())?;
486 let mut scope = self.deno_runtime().handle_scope();
487 let module_namespace = module_namespace.open(&mut scope);
488 assert!(module_namespace.is_module_namespace_object());
489
490 let key = name.to_v8_string(&mut scope)?;
491 let value = module_namespace.get(&mut scope, key.into());
492
493 match value.if_defined() {
494 Some(v) => Ok(v8::Global::<v8::Value>::new(&mut scope, v)),
495 _ => Err(Error::ValueNotFound(name.to_string())),
496 }
497 }
498
499 pub async fn resolve_with_event_loop(
500 &mut self,
501 value: v8::Global<v8::Value>,
502 ) -> Result<v8::Global<v8::Value>, Error> {
503 let future = self.deno_runtime().resolve(value);
504 let result = self
505 .deno_runtime()
506 .with_event_loop_future(future, PollEventLoopOptions::default())
507 .await?;
508 Ok(result)
509 }
510
511 pub fn decode_value<T>(&mut self, value: v8::Global<v8::Value>) -> Result<T, Error>
512 where
513 T: DeserializeOwned,
514 {
515 let mut scope = self.deno_runtime().handle_scope();
516 let result = v8::Local::<v8::Value>::new(&mut scope, value);
517 Ok(from_v8(&mut scope, result)?)
518 }
519
520 pub fn get_value_ref(
521 &mut self,
522 module_context: Option<&ModuleHandle>,
523 name: &str,
524 ) -> Result<v8::Global<v8::Value>, Error> {
525 let result = module_context
527 .and_then(|module_context| self.get_module_export_value(module_context, name).ok());
528
529 match result {
531 Some(result) => Ok(result),
532 None => self
533 .get_global_value(name)
534 .map_err(|_| Error::ValueNotFound(name.to_string())),
535 }
536 }
537
538 pub fn get_function_by_name(
549 &mut self,
550 module_context: Option<&ModuleHandle>,
551 name: &str,
552 ) -> Result<v8::Global<v8::Function>, Error> {
553 let value = self.get_value_ref(module_context, name)?;
555
556 let mut scope = self.deno_runtime().handle_scope();
558 let local_value = v8::Local::<v8::Value>::new(&mut scope, value);
559 let f: v8::Local<v8::Function> = local_value
560 .try_into()
561 .or::<Error>(Err(Error::ValueNotCallable(name.to_string())))?;
562
563 Ok(v8::Global::<v8::Function>::new(&mut scope, f))
565 }
566
567 pub fn call_function_by_ref(
568 &mut self,
569 module_context: Option<&ModuleHandle>,
570 function: &v8::Global<v8::Function>,
571 args: &impl serde::ser::Serialize,
572 ) -> Result<v8::Global<v8::Value>, Error> {
573 let module_namespace = if let Some(module_context) = module_context {
575 Some(
576 self.deno_runtime()
577 .get_module_namespace(module_context.id())?,
578 )
579 } else {
580 None
581 };
582
583 let mut scope = self.deno_runtime().handle_scope();
584 let mut scope = v8::TryCatch::new(&mut scope);
585
586 let namespace: v8::Local<v8::Value> = if let Some(namespace) = module_namespace {
589 v8::Local::<v8::Object>::new(&mut scope, namespace).into()
590 } else {
591 let obj: v8::Local<v8::Value> = v8::undefined(&mut scope).into();
594 obj
595 };
596
597 let function_instance = function.open(&mut scope);
598
599 let args = decode_args(args, &mut scope)?;
601
602 let result = function_instance.call(&mut scope, namespace, &args);
604 match result {
605 Some(value) => {
606 let value = v8::Global::new(&mut scope, value);
607 Ok(value)
608 }
609 None if scope.has_caught() => {
610 let e = scope
611 .message()
612 .ok_or_else(|| Error::Runtime("Unknown error".to_string()))?;
613
614 let filename = e.get_script_resource_name(&mut scope);
615 let linenumber = e.get_line_number(&mut scope).unwrap_or_default();
616 let filename = if let Some(v) = filename {
617 let filename = v.to_rust_string_lossy(&mut scope);
618 format!("{filename}:{linenumber}: ")
619 } else if let Some(module_context) = module_context {
620 let filename = module_context.module().filename().to_string_lossy();
621 format!("{filename}:{linenumber}: ")
622 } else {
623 String::new()
624 };
625
626 let msg = e.get(&mut scope).to_rust_string_lossy(&mut scope);
627
628 let s = format!("{filename}{msg}");
629 Err(Error::Runtime(s))
630 }
631 None => Err(Error::Runtime(
632 "Unknown error during function execution".to_string(),
633 )),
634 }
635 }
636
637 pub async fn with_event_loop_future<'fut, T, E>(
644 &mut self,
645 mut fut: impl std::future::Future<Output = Result<T, E>> + Unpin + 'fut,
646 poll_options: PollEventLoopOptions,
647 ) -> Result<T, Error>
648 where
649 deno_core::error::AnyError: From<E>,
650 Error: std::convert::From<E>,
651 {
652 std::future::poll_fn(|cx| {
654 let evt_status = self.deno_runtime().poll_event_loop(cx, poll_options);
655 let fut_status = fut.poll_unpin(cx);
656
657 match (evt_status, fut_status) {
658 (Poll::Ready(Err(e)), _) => {
659 Poll::Ready(Err(e.into()))
661 }
662
663 (_, Poll::Pending) => {
664 Poll::Pending
666 }
667
668 (_, Poll::Ready(t)) => {
669 for _ in 0..100 {
670 if let Poll::Ready(Err(e)) =
671 self.deno_runtime().poll_event_loop(cx, poll_options)
672 {
673 return Poll::Ready(Err(e.into()));
674 }
675 }
676
677 Poll::Ready(t.map_err(Into::into))
679 }
680 }
681 })
682 .await
683 }
684
685 pub fn get_module_entrypoint(
687 &mut self,
688 module_context: &mut ModuleHandle,
689 ) -> Result<Option<v8::Global<v8::Function>>, Error> {
690 let default = self.default_entrypoint.clone();
691
692 let state = self.deno_runtime().op_state();
694 let mut deep_state = state.try_borrow_mut()?;
695 let entrypoint = deep_state.try_take::<v8::Global<v8::Function>>();
696 if let Some(entrypoint) = entrypoint {
697 return Ok(Some(entrypoint));
698 }
699
700 if let Ok(default_export) = self.get_module_export_value(module_context, "default") {
702 let mut scope = self.deno_runtime().handle_scope();
703 let default_export = v8::Local::new(&mut scope, default_export);
704 if default_export.is_function() {
705 if let Ok(f) = v8::Local::<v8::Function>::try_from(default_export) {
706 return Ok(Some(v8::Global::new(&mut scope, f)));
707 }
708 }
709 }
710
711 if let Some(default) = default.as_deref() {
713 if let Ok(f) = self.get_function_by_name(Some(module_context), default) {
714 return Ok(Some(f));
715 }
716 }
717
718 Ok(None)
719 }
720
721 pub async fn load_modules(
728 &mut self,
729 main_module: Option<&Module>,
730 side_modules: Vec<&Module>,
731 ) -> Result<ModuleHandle, Error> {
732 if main_module.is_none() && side_modules.is_empty() {
733 return Err(Error::Runtime(
734 "Internal error: attempt to load no modules".to_string(),
735 ));
736 }
737
738 let mut module_handle_stub = ModuleHandle::default();
739
740 for side_module in side_modules {
742 let module_specifier = side_module.filename().to_module_specifier(&self.cwd)?;
743 let (code, sourcemap) = transpile(&module_specifier, side_module.contents())?;
744
745 #[cfg(feature = "node_experimental")]
747 let code = self
748 .module_loader
749 .translate_cjs(&module_specifier, &code)
750 .await?;
751
752 let fast_code = deno_core::FastString::from(code.clone());
753
754 let s_modid = self
755 .deno_runtime()
756 .load_side_es_module_from_code(&module_specifier, fast_code)
757 .await?;
758
759 self.module_loader.insert_source_map(
761 module_specifier.as_str(),
762 code,
763 sourcemap.map(|s| s.to_vec()),
764 );
765
766 let mod_load = self.deno_runtime().mod_evaluate(s_modid);
767 self.with_event_loop_future(mod_load, PollEventLoopOptions::default())
768 .await?;
769 module_handle_stub = ModuleHandle::new(side_module, s_modid, None);
770 }
771
772 if let Some(module) = main_module {
774 let module_specifier = module.filename().to_module_specifier(&self.cwd)?;
775 let (code, sourcemap) = transpile(&module_specifier, module.contents())?;
776
777 #[cfg(feature = "node_experimental")]
779 let code = self
780 .module_loader
781 .translate_cjs(&module_specifier, &code)
782 .await?;
783
784 let fast_code = deno_core::FastString::from(code.clone());
785
786 let module_id = self
787 .deno_runtime()
788 .load_main_es_module_from_code(&module_specifier, fast_code)
789 .await?;
790
791 self.module_loader.insert_source_map(
793 module_specifier.as_str(),
794 code,
795 sourcemap.map(|s| s.to_vec()),
796 );
797
798 let mod_load = self.deno_runtime().mod_evaluate(module_id);
800 self.with_event_loop_future(mod_load, PollEventLoopOptions::default())
801 .await?;
802 module_handle_stub = ModuleHandle::new(module, module_id, None);
803 }
804
805 let entrypoint = self.get_module_entrypoint(&mut module_handle_stub)?;
807
808 Ok(ModuleHandle::new(
809 module_handle_stub.module(),
810 module_handle_stub.id(),
811 entrypoint,
812 ))
813 }
814}
815
816#[cfg(test)]
817mod test_inner_runtime {
818 use serde::Deserialize;
819
820 use crate::{async_callback, big_json_args, js_value::Function, json_args, sync_callback};
821
822 #[cfg(any(feature = "web", feature = "web_stub"))]
823 use crate::js_value::Promise;
824
825 use super::*;
826
827 fn run_async_task<T, F, U>(f: F) -> T
829 where
830 U: std::future::Future<Output = Result<T, Error>>,
831 F: FnOnce() -> U,
832 {
833 let timeout = Duration::from_secs(2);
834 let tokio = tokio::runtime::Builder::new_current_thread()
835 .enable_all()
836 .thread_keep_alive(timeout)
837 .build()
838 .unwrap();
839 tokio
840 .block_on(async move {
841 tokio::time::timeout(timeout, f())
842 .await
843 .expect("Test failed")
844 })
845 .expect("Timed out")
846 }
847
848 macro_rules! assert_v8 {
849 ($l:expr, $r:expr, $t:ty, $rt:expr) => {
850 assert_eq!($rt.decode_value::<$t>($l).expect("Wrong type"), $r,)
851 };
852 }
853
854 #[test]
855 fn test_decode_args() {
856 let mut runtime =
857 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
858 .expect("Could not load runtime");
859 let mut scope = runtime.deno_runtime.handle_scope();
860
861 let args = decode_args(&json_args!(), &mut scope).expect("Could not decode args");
863 assert_eq!(args.len(), 0);
864
865 let args = decode_args(&json_args!(2), &mut scope).expect("Could not decode args");
867 assert_eq!(args.len(), 1);
868
869 let args = decode_args(&2, &mut scope).expect("Could not decode args");
871 assert_eq!(args.len(), 1);
872
873 let args = decode_args(&json_args!(2, "test"), &mut scope).expect("Could not decode args");
875 assert_eq!(args.len(), 2);
876
877 let args = decode_args(&json_args!(2, 3), &mut scope).expect("Could not decode args");
879 assert_eq!(args.len(), 2);
880
881 let args = decode_args(
883 &(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
884 &mut scope,
885 )
886 .expect("Could not decode args");
887 assert_eq!(args.len(), 16);
888
889 let args = decode_args(
891 &big_json_args!(
892 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
893 10, 11, 12, 13, 14, 15
894 ),
895 &mut scope,
896 )
897 .expect("Could not decode args");
898 assert_eq!(args.len(), 32);
899 }
900
901 #[test]
902 fn test_put_take() {
903 let mut runtime =
904 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
905 .expect("Could not load runtime");
906
907 runtime.put(2usize).expect("Could not put value");
908 let v = runtime.take::<usize>().expect("Could not take value");
909 assert_eq!(v, 2);
910 }
911
912 #[test]
913 fn test_register_async_function() {
914 let mut runtime =
915 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
916 .expect("Could not load runtime");
917 runtime
918 .register_async_function(
919 "test",
920 async_callback!(|a: i64, b: i64| async move { Ok::<i64, Error>(a + b) }),
921 )
922 .expect("Could not register function");
923
924 let module = Module::new(
925 "test.js",
926 "
927 globalThis.v = await rustyscript.async_functions.test(2, 3);
928 ",
929 );
930
931 let rt = &mut runtime;
932 let module = run_async_task(|| async move { rt.load_modules(Some(&module), vec![]).await });
933
934 let result = runtime
935 .get_value_ref(Some(&module), "v")
936 .expect("Could not find global");
937 assert_v8!(result, 5, usize, runtime);
938 }
939
940 #[test]
941 fn test_register_function() {
942 let mut runtime =
943 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
944 .expect("Could not load runtime");
945 runtime
946 .register_function(
947 "test",
948 sync_callback!(|a: i64, b: i64| { Ok::<i64, Error>(a + b) }),
949 )
950 .expect("Could not register function");
951
952 run_async_task(|| async move {
953 let v = runtime
954 .eval("rustyscript.functions.test(2, 3)")
955 .await
956 .expect("failed to eval");
957 assert_v8!(v, 5, usize, runtime);
958 Ok(())
959 });
960 }
961
962 #[cfg(any(feature = "web", feature = "web_stub"))]
963 #[test]
964 fn test_eval() {
965 let mut runtime =
966 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
967 .expect("Could not load runtime");
968
969 run_async_task(|| async move {
970 let v = runtime.eval("2 + 2").await.expect("failed to eval");
971 assert_v8!(v, 4, usize, runtime);
972 let result = runtime
973 .eval(
974 "
975 let sleep = (ms) => new Promise((r) => setTimeout(r, ms));
976 sleep(500).then(() => 2);
977 ",
978 )
979 .await
980 .expect("failed to eval");
981
982 let result: Promise<u32> = runtime
983 .decode_value(result)
984 .expect("Could not decode promise");
985
986 let result: u32 = result.resolve(runtime.deno_runtime()).await?;
987 assert_eq!(result, 2);
988 Ok(())
989 });
990 }
991
992 #[cfg(feature = "web_stub")]
993 #[test]
994 fn test_base64() {
995 let mut runtime =
996 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
997 .expect("Could not load runtime");
998
999 run_async_task(|| async move {
1000 let result = runtime.eval("btoa('foo')").await.expect("failed to eval");
1001 assert_v8!(result, "Zm9v", String, runtime);
1002
1003 let result = runtime
1004 .eval("atob(btoa('foo'))")
1005 .await
1006 .expect("failed to eval");
1007 assert_v8!(result, "foo", String, runtime);
1008
1009 Ok(())
1010 });
1011 }
1012
1013 #[test]
1014 fn test_get_value_ref() {
1015 let module = Module::new(
1016 "test.js",
1017 "
1018 globalThis.a = 2;
1019 export const b = 'test';
1020 export const fnc = null;
1021 ",
1022 );
1023
1024 let mut runtime =
1025 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1026 .expect("Could not load runtime");
1027
1028 let rt = &mut runtime;
1029 let module = run_async_task(|| async move { rt.load_modules(Some(&module), vec![]).await });
1030
1031 let v = runtime
1032 .get_value_ref(None, "a")
1033 .expect("Could not find global");
1034 assert_v8!(v, 2, usize, runtime);
1035
1036 let v = runtime
1037 .get_value_ref(Some(&module), "a")
1038 .expect("Could not find global");
1039 assert_v8!(v, 2, usize, runtime);
1040
1041 let v = runtime
1042 .get_value_ref(Some(&module), "b")
1043 .expect("Could not find export");
1044 assert_v8!(v, "test", String, runtime);
1045
1046 runtime
1047 .get_value_ref(Some(&module), "c")
1048 .expect_err("Could not detect null");
1049
1050 runtime
1051 .get_value_ref(Some(&module), "d")
1052 .expect_err("Could not detect undeclared");
1053 }
1054
1055 #[test]
1056 fn test_get_function_by_name() {
1057 let module = Module::new(
1058 "test.js",
1059 "
1060 globalThis.fna = () => {};
1061 export function fnb() {}
1062 export const fnc = 2;
1063 ",
1064 );
1065
1066 let mut runtime =
1067 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1068 .expect("Could not load runtime");
1069
1070 let rt = &mut runtime;
1071 let module = run_async_task(|| async move { rt.load_modules(Some(&module), vec![]).await });
1072
1073 runtime
1074 .get_function_by_name(Some(&module), "fna")
1075 .expect("Did not find global");
1076 runtime
1077 .get_function_by_name(Some(&module), "fnb")
1078 .expect("Did not find export");
1079 runtime
1080 .get_function_by_name(Some(&module), "fnc")
1081 .expect_err("Did not detect non-function");
1082 runtime
1083 .get_function_by_name(Some(&module), "fnd")
1084 .expect_err("Did not detect undefined");
1085 }
1086
1087 #[test]
1088 fn test_call_function_by_ref() {
1089 let module = Module::new(
1090 "test.js",
1091 "
1092 globalThis.fna = (i) => i;
1093 export function fnb() {
1094 return 'test';
1095 }
1096 export const fnc = 2;
1097 export const fne = () => {};
1098
1099 export const will_err = () => {
1100 throw new Error('msg');
1101 }
1102 ",
1103 );
1104
1105 run_async_task(|| async move {
1106 let mut runtime =
1107 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1108 .expect("Could not load runtime");
1109 let handle = runtime.load_modules(Some(&module), vec![]).await?;
1110
1111 let f = runtime.get_function_by_name(None, "fna").unwrap();
1112 let result = runtime
1113 .call_function_by_ref(Some(&handle), &f, json_args!(2))
1114 .expect("Could not call global");
1115 assert_v8!(result, 2, usize, runtime);
1116
1117 let f = runtime.get_function_by_name(Some(&handle), "fnb").unwrap();
1118 let result = runtime
1119 .call_function_by_ref(Some(&handle), &f, json_args!())
1120 .expect("Could not call export");
1121 assert_v8!(result, "test", String, runtime);
1122
1123 let f = runtime.get_function_by_name(Some(&handle), "fne").unwrap();
1124 runtime
1125 .call_function_by_ref(Some(&handle), &f, json_args!())
1126 .expect("Did not allow undefined return");
1127
1128 let f = runtime
1129 .get_function_by_name(Some(&handle), "will_err")
1130 .unwrap();
1131 runtime
1132 .call_function_by_ref(Some(&handle), &f, json_args!())
1133 .expect_err("Did not catch error");
1134
1135 Ok(())
1136 });
1137 }
1138
1139 #[test]
1140 fn test_ts_loader() {
1141 let module = Module::new(
1142 "test.ts",
1143 "
1144 export function test(left:number, right:number): number {
1145 return left + right;
1146 }
1147 ",
1148 );
1149
1150 let mut runtime =
1151 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1152 .expect("Could not load runtime");
1153
1154 let rt = &mut runtime;
1155 let module = run_async_task(|| async move { rt.load_modules(Some(&module), vec![]).await });
1156
1157 let f = runtime.get_function_by_name(Some(&module), "test").unwrap();
1158 let rt = &mut runtime;
1159 let result = run_async_task(|| async move {
1160 rt.call_function_by_ref(Some(&module), &f, json_args!(2, 3))
1161 });
1162 assert_v8!(result, 5, usize, runtime);
1163 }
1164
1165 #[cfg(any(feature = "web", feature = "web_stub"))]
1166 #[test]
1167 fn test_toplevel_await() {
1168 let module = Module::new(
1169 "test.js",
1170 "
1171 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
1172 await sleep(100);
1173 export function test() {
1174 return 2;
1175 }
1176 ",
1177 );
1178
1179 let mut runtime =
1180 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1181 .expect("Could not load runtime");
1182
1183 let rt = &mut runtime;
1184 let module = run_async_task(|| async move {
1185 let h = rt.load_modules(Some(&module), vec![]).await;
1186 rt.await_event_loop(PollEventLoopOptions::default(), None)
1187 .await?;
1188 h
1189 });
1190
1191 let f = runtime.get_function_by_name(Some(&module), "test").unwrap();
1192 let rt = &mut runtime;
1193 let result =
1194 run_async_task(
1195 || async move { rt.call_function_by_ref(Some(&module), &f, json_args!()) },
1196 );
1197 assert_v8!(result, 2, usize, runtime);
1198 }
1199
1200 #[cfg(any(feature = "web", feature = "web_stub"))]
1201 #[test]
1202 fn test_promise() {
1203 let module = Module::new(
1204 "test.js",
1205 "
1206 export const test = () => {
1207 return new Promise((resolve) => {
1208 setTimeout(() => {
1209 resolve(2);
1210 }, 50);
1211 });
1212 }
1213 ",
1214 );
1215
1216 let mut runtime =
1217 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1218 .expect("Could not load runtime");
1219
1220 let rt = &mut runtime;
1221 run_async_task(|| async move {
1222 let module = rt.load_modules(Some(&module), vec![]).await?;
1223
1224 let f = rt.get_function_by_name(Some(&module), "test").unwrap();
1225 let result = rt.call_function_by_ref(Some(&module), &f, json_args!())?;
1226
1227 let result = rt.resolve_with_event_loop(result).await?;
1228 assert_v8!(result, 2, usize, rt);
1229
1230 Ok(())
1231 });
1232 }
1233
1234 #[cfg(any(feature = "web", feature = "web_stub"))]
1235 #[test]
1236 fn test_async_fn() {
1237 let module = Module::new(
1238 "test.js",
1239 "
1240 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
1241 export async function test() {
1242 await sleep(100);
1243 return 2;
1244 }
1245 ",
1246 );
1247
1248 let mut runtime =
1249 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1250 .expect("Could not load runtime");
1251
1252 let rt = &mut runtime;
1253 run_async_task(|| async move {
1254 let module = rt.load_modules(Some(&module), vec![]).await?;
1255
1256 let f = rt.get_function_by_name(Some(&module), "test")?;
1257 let result = rt.call_function_by_ref(Some(&module), &f, json_args!())?;
1258 let result: Promise<usize> = rt.decode_value(result).expect("Could not deserialize");
1259 let result: usize = result.resolve(rt.deno_runtime()).await?;
1260 assert_eq!(2, result);
1261
1262 Ok(())
1263 });
1264 }
1265
1266 #[test]
1267 fn test_deep_error() {
1268 let module = Module::new(
1269 "test.js",
1270 "
1271 await new Promise(r => setTimeout(r)); throw 'huh';
1272 ",
1273 );
1274
1275 let mut runtime =
1276 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1277 .expect("Could not load runtime");
1278
1279 let rt = &mut runtime;
1280 run_async_task(|| async move {
1281 let result = rt.load_modules(Some(&module), vec![]).await;
1282 assert!(result.is_err());
1283 Ok(())
1284 });
1285 }
1286
1287 #[test]
1288 fn test_serialize_deep_fn() {
1289 let module = Module::new(
1290 "test.js",
1291 "
1292 let a = 2;
1293 export const test = {
1294 'name': 'test',
1295 'func': (x) => x + a
1296 }
1297 ",
1298 );
1299
1300 let mut runtime =
1301 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1302 .expect("Could not load runtime");
1303
1304 let rt = &mut runtime;
1305 let module = run_async_task(|| async move { rt.load_modules(Some(&module), vec![]).await });
1306
1307 #[derive(Deserialize)]
1308 #[allow(clippy::items_after_statements)]
1309 struct TestStruct {
1310 #[allow(dead_code)]
1311 name: String,
1312 func: Function,
1313 }
1314
1315 let structure = runtime.get_value_ref(Some(&module), "test").unwrap();
1316 let structure: TestStruct = runtime
1317 .decode_value(structure)
1318 .expect("Could not deserialize");
1319
1320 let function = structure
1321 .func
1322 .as_global(&mut runtime.deno_runtime().handle_scope());
1323
1324 run_async_task(|| async move {
1325 let value = runtime
1326 .call_function_by_ref(Some(&module), &function, json_args!(2))
1327 .expect("could not call function");
1328 assert_v8!(value, 4, usize, runtime);
1329
1330 let value = runtime
1331 .call_function_by_ref(Some(&module), &function, json_args!(3))
1332 .expect("could not call function twice");
1333 assert_v8!(value, 5, usize, runtime);
1334
1335 Ok(())
1336 });
1337 }
1338
1339 #[test]
1340 fn test_async_load_errors() {
1341 let module = Module::new(
1342 "test.js",
1343 "
1344 throw new Error('msg');
1345 ",
1346 );
1347
1348 let mut runtime =
1349 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1350 .expect("Could not load runtime");
1351
1352 let rt = &mut runtime;
1353 let module_ = module.clone();
1354 let result =
1355 run_async_task(
1356 || async move { Ok(rt.load_modules(Some(&module_), vec![]).await.is_err()) },
1357 );
1358 assert!(result);
1359
1360 let mut runtime =
1361 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1362 .expect("Could not load runtime");
1363
1364 let rt = &mut runtime;
1365 let result =
1366 run_async_task(
1367 || async move { Ok(rt.load_modules(None, vec![&module]).await.is_err()) },
1368 );
1369 assert!(result);
1370 }
1371
1372 #[test]
1373 fn test_serialize_fn() {
1374 let module = Module::new(
1375 "test.js",
1376 "
1377 export const test = (x) => 2*x;
1378 ",
1379 );
1380
1381 let mut runtime =
1382 InnerRuntime::<JsRuntime>::new(RuntimeOptions::default(), CancellationToken::new())
1383 .expect("Could not load runtime");
1384
1385 let rt = &mut runtime;
1386 let module = run_async_task(|| async move { rt.load_modules(Some(&module), vec![]).await });
1387
1388 let function = runtime
1389 .get_function_by_name(Some(&module), "test")
1390 .expect("Could not get function");
1391
1392 run_async_task(|| async move {
1393 let value = runtime
1394 .call_function_by_ref(Some(&module), &function, json_args!(2))
1395 .expect("could not call function");
1396 assert_v8!(value, 4, usize, runtime);
1397
1398 let value = runtime
1399 .call_function_by_ref(None, &function, json_args!(2))
1400 .expect("could not call function");
1401 assert_v8!(value, 4, usize, runtime);
1402
1403 Ok(())
1404 });
1405 }
1406}