rustyscript/module_wrapper.rs
1use crate::{js_value::Function, Error, Module, ModuleHandle, Runtime, RuntimeOptions};
2use deno_core::{serde_json, v8::GetPropertyNamesArgs};
3
4/// A wrapper type representing a runtime instance loaded with a single module
5///
6/// Exactly equivalent to [`Runtime::new`] followed by [`Runtime::load_module`]
7///
8/// Can also be created using the [`crate::import`] function
9pub struct ModuleWrapper {
10 module_context: ModuleHandle,
11 runtime: Runtime,
12}
13
14impl ModuleWrapper {
15 /// Creates a new `ModuleWrapper` from a given module and runtime options.
16 ///
17 /// # Arguments
18 /// * `module` - A reference to the module to load.
19 /// * `options` - The runtime options for the module.
20 ///
21 /// # Returns
22 /// A `Result` containing `Self` on success or an `Error` on failure.
23 ///
24 /// # Errors
25 /// Will return an error if module execution fails
26 pub fn new_from_module(module: &Module, options: RuntimeOptions) -> Result<Self, Error> {
27 let mut runtime = Runtime::new(options)?;
28 let module_context = runtime.load_module(module)?;
29 Ok(Self {
30 module_context,
31 runtime,
32 })
33 }
34
35 /// Creates a new `ModuleWrapper` from a file path and runtime options.
36 ///
37 /// # Arguments
38 /// * `path` - The path to the module file.
39 /// * `options` - The runtime options for the module.
40 ///
41 /// # Returns
42 /// A `Result` containing `Self` on success or an `Error` on failure.
43 ///
44 /// # Errors
45 /// Will return an error if the file cannot be loaded, or if module execution fails
46 pub fn new_from_file(path: &str, options: RuntimeOptions) -> Result<Self, Error> {
47 let module = Module::load(path)?;
48 Self::new_from_module(&module, options)
49 }
50
51 /// Returns a reference to the module context.
52 #[must_use]
53 pub fn get_module_context(&self) -> &ModuleHandle {
54 &self.module_context
55 }
56
57 /// Returns a mutable reference to the underlying runtime.
58 pub fn get_runtime(&mut self) -> &mut Runtime {
59 &mut self.runtime
60 }
61
62 /// Retrieves a value from the module by name and deserializes it.
63 ///
64 /// See [`Runtime::get_value`]
65 ///
66 /// # Arguments
67 /// * `name` - The name of the value to retrieve.
68 ///
69 /// # Returns
70 /// A `Result` containing the deserialized value of type `T` on success or an `Error` on failure.
71 ///
72 /// # Errors
73 /// Will return an error if the value cannot be found, or deserialized into the given type
74 pub fn get<T>(&mut self, name: &str) -> Result<T, Error>
75 where
76 T: serde::de::DeserializeOwned,
77 {
78 self.runtime.get_value(Some(&self.module_context), name)
79 }
80
81 /// Retrieves a future resolving to a value from the module by name and deserializes it.
82 ///
83 /// See [`Runtime::get_value_async`]
84 ///
85 /// # Arguments
86 /// * `name` - The name of the value to retrieve.
87 ///
88 /// # Returns
89 /// A `Result` containing the deserialized value of type `T` on success or an `Error` on failure.
90 ///
91 /// # Errors
92 /// Will return an error if the value cannot be found, or deserialized into the given type
93 pub async fn get_async<T>(&mut self, name: &str) -> Result<T, Error>
94 where
95 T: serde::de::DeserializeOwned,
96 {
97 self.runtime
98 .get_value_async(Some(&self.module_context), name)
99 .await
100 }
101
102 /// Retrieves a value from the module by name and deserializes it.
103 ///
104 /// Does not await promises or the event loop.
105 ///
106 /// See [`Runtime::get_value_immediate`]
107 ///
108 /// # Arguments
109 /// * `name` - The name of the value to retrieve.
110 ///
111 /// # Returns
112 /// A `Result` containing the deserialized value of type `T` on success or an `Error` on failure.
113 ///
114 /// # Errors
115 /// Will return an error if the value cannot be found, or deserialized into the given type
116 pub fn get_immediate<T>(&mut self, name: &str) -> Result<T, Error>
117 where
118 T: serde::de::DeserializeOwned,
119 {
120 self.runtime
121 .get_value_immediate(Some(&self.module_context), name)
122 }
123
124 /// Checks if a value in the module with the given name is callable as a JavaScript function.
125 ///
126 /// # Arguments
127 /// * `name` - The name of the value to check for callability.
128 ///
129 /// # Returns
130 /// `true` if the value is callable as a JavaScript function, `false` otherwise.
131 pub fn is_callable(&mut self, name: &str) -> bool {
132 let test = self.get::<Function>(name);
133 test.is_ok()
134 }
135
136 /// Calls a function in the module with the given name and arguments and deserializes the result.
137 ///
138 /// See [`Runtime::call_function`]
139 ///
140 /// # Arguments
141 /// * `name` - The name of the function to call.
142 /// * `args` - The arguments to pass to the function.
143 ///
144 /// # Returns
145 /// A `Result` containing the deserialized result of type `T` on success or an `Error` on failure.
146 ///
147 /// # Errors
148 /// Will return an error if the function cannot be called, if the function returns an error,
149 /// or if the function returns a value that cannot be deserialized into the given type
150 pub fn call<T>(&mut self, name: &str, args: &impl serde::ser::Serialize) -> Result<T, Error>
151 where
152 T: serde::de::DeserializeOwned,
153 {
154 self.runtime
155 .call_function(Some(&self.module_context), name, args)
156 }
157
158 /// Calls a function in the module with the given name and arguments and deserializes the result.
159 ///
160 /// See [`Runtime::call_function_async`]
161 ///
162 /// # Arguments
163 /// * `name` - The name of the function to call.
164 /// * `args` - The arguments to pass to the function.
165 ///
166 /// # Returns
167 /// A `Result` containing the deserialized result of type `T` on success or an `Error` on failure.
168 ///
169 /// # Errors
170 /// Will return an error if the function cannot be called, if the function returns an error,
171 /// or if the function returns a value that cannot be deserialized into the given type
172 pub async fn call_async(
173 &mut self,
174 name: &str,
175 args: &impl serde::ser::Serialize,
176 ) -> Result<serde_json::Value, Error> {
177 self.runtime
178 .call_function_async(Some(&self.module_context), name, args)
179 .await
180 }
181
182 /// Calls a function in the module with the given name and arguments and deserializes the result.
183 /// Does not await promises or the event loop.
184 ///
185 /// See [`Runtime::call_function_immediate`]
186 ///
187 /// # Arguments
188 /// * `name` - The name of the function to call.
189 /// * `args` - The arguments to pass to the function.
190 ///
191 /// # Returns
192 /// A `Result` containing the deserialized result of type `T` on success or an `Error` on failure.
193 ///
194 /// # Errors
195 /// Will return an error if the function cannot be called, if the function returns an error,
196 /// or if the function returns a value that cannot be deserialized into the given type
197 pub fn call_immediate(
198 &mut self,
199 name: &str,
200 args: &impl serde::ser::Serialize,
201 ) -> Result<serde_json::Value, Error> {
202 self.runtime
203 .call_function_immediate(Some(&self.module_context), name, args)
204 }
205
206 /// Calls a function using the module's runtime that was previously stored as a Function object
207 ///
208 /// See [`Runtime::call_stored_function`]
209 ///
210 /// # Arguments
211 /// * `function` - The Function to call.
212 /// * `args` - The arguments to pass to the function.
213 ///
214 /// # Returns
215 /// A `Result` containing the deserialized result of type `T` on success or an `Error` on failure.
216 ///
217 /// # Errors
218 /// Will return an error if the function cannot be called, if the function returns an error,
219 /// or if the function returns a value that cannot be deserialized into the given type
220 pub fn call_stored<T>(
221 &mut self,
222 function: &Function,
223 args: &impl serde::ser::Serialize,
224 ) -> Result<T, Error>
225 where
226 T: serde::de::DeserializeOwned,
227 {
228 self.runtime
229 .call_stored_function(Some(&self.module_context), function, args)
230 }
231
232 /// Calls a function using the module's runtime that was previously stored as a Function object
233 ///
234 /// See [`Runtime::call_stored_function_async`]
235 ///
236 /// # Arguments
237 /// * `function` - The Function to call.
238 /// * `args` - The arguments to pass to the function.
239 ///
240 /// # Returns
241 /// A `Result` containing the deserialized result of type `T` on success or an `Error` on failure.
242 ///
243 /// # Errors
244 /// Will return an error if the function cannot be called, if the function returns an error,
245 /// or if the function returns a value that cannot be deserialized into the given type
246 pub async fn call_stored_async(
247 &mut self,
248 function: &Function,
249 args: &impl serde::ser::Serialize,
250 ) -> Result<serde_json::Value, Error> {
251 self.runtime
252 .call_stored_function_async(Some(&self.module_context), function, args)
253 .await
254 }
255
256 /// Calls a function using the module's runtime that was previously stored as a Function object
257 ///
258 /// Does not await promises or the event loop.
259 ///
260 /// See [`Runtime::call_stored_function_immediate`]
261 ///
262 /// # Arguments
263 /// * `function` - The Function to call.
264 /// * `args` - The arguments to pass to the function.
265 ///
266 /// # Returns
267 /// A `Result` containing the deserialized result of type `T` on success or an `Error` on failure.
268 ///
269 /// # Errors
270 /// Will return an error if the function cannot be called, if the function returns an error,
271 /// or if the function returns a value that cannot be deserialized into the given type
272 pub fn call_stored_immediate(
273 &mut self,
274 function: &Function,
275 args: &impl serde::ser::Serialize,
276 ) -> Result<serde_json::Value, Error> {
277 self.runtime
278 .call_stored_function_immediate(Some(&self.module_context), function, args)
279 }
280
281 /// Retrieves the names of the module's exports.
282 /// (Keys that are not valid UTF-8, may not work as intended due to encoding issues)
283 ///
284 /// # Returns
285 /// A `Vec` of `String` containing the names of the keys.
286 pub fn keys(&mut self) -> Vec<String> {
287 let mut keys: Vec<String> = Vec::new();
288 if let Ok(namespace) = self
289 .runtime
290 .deno_runtime()
291 .get_module_namespace(self.module_context.id())
292 {
293 let mut scope = self.runtime.deno_runtime().handle_scope();
294 let global = namespace.open(&mut scope);
295 if let Some(keys_obj) =
296 global.get_property_names(&mut scope, GetPropertyNamesArgs::default())
297 {
298 for i in 0..keys_obj.length() {
299 if let Ok(key_index) = deno_core::serde_v8::to_v8(&mut scope, i) {
300 if let Some(key_name_v8) = keys_obj.get(&mut scope, key_index) {
301 let name = key_name_v8.to_rust_string_lossy(&mut scope);
302 keys.push(name);
303 }
304 }
305 }
306 }
307 }
308
309 keys
310 }
311}
312
313#[cfg(test)]
314mod test_runtime {
315 use super::*;
316 use crate::json_args;
317
318 #[test]
319 fn test_call() {
320 let module = Module::new(
321 "test.js",
322 "
323 console.log('test');
324 export const value = 3;
325 export function func() { return 4; }
326 ",
327 );
328
329 let mut module = ModuleWrapper::new_from_module(&module, RuntimeOptions::default())
330 .expect("Could not create wrapper");
331 let value: usize = module
332 .call("func", json_args!())
333 .expect("Could not call function");
334 assert_eq!(4, value);
335 }
336
337 #[test]
338 fn test_get() {
339 let module = Module::new(
340 "test.js",
341 "
342 export const value = 3;
343 export function func() { return 4; }
344 ",
345 );
346
347 let mut module = ModuleWrapper::new_from_module(&module, RuntimeOptions::default())
348 .expect("Could not create wrapper");
349 let value: usize = module.get("value").expect("Could not get value");
350 assert_eq!(3, value);
351 }
352
353 #[test]
354 fn test_callable() {
355 let module = Module::new(
356 "test.js",
357 "
358 export const value = 3;
359 export function func() { return 4; }
360 ",
361 );
362
363 let mut module = ModuleWrapper::new_from_module(&module, RuntimeOptions::default())
364 .expect("Could not create wrapper");
365
366 assert!(module.is_callable("func"));
367 assert!(!module.is_callable("value"));
368 }
369
370 #[test]
371 fn test_keys() {
372 let module = Module::new(
373 "test.js",
374 "
375 export const value = 3;
376 export function func() { return 4; }
377 ",
378 );
379
380 let mut module = ModuleWrapper::new_from_module(&module, RuntimeOptions::default())
381 .expect("Could not create wrapper");
382 let mut keys = module.keys();
383 assert_eq!(2, keys.len());
384 assert_eq!("value", keys.pop().unwrap());
385 assert_eq!("func", keys.pop().unwrap());
386 }
387}