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}