1- use anyhow:: { anyhow, Result } ;
1+ use anyhow:: { anyhow, ensure , Result } ;
22use std:: path:: PathBuf ;
33use std:: string:: String ;
44use wasmtime:: { AsContextMut , Cache , Config , Engine , Linker , Module , ResourceLimiter , Store } ;
@@ -25,7 +25,19 @@ pub fn uses_msgpack_provider(module: &Module) -> bool {
2525 } )
2626}
2727
28+ /// Parameters for a single run. The standard provider is compiled for each call.
2829pub struct FunctionRunParams < ' a > {
30+ pub function_path : PathBuf ,
31+ pub input : BytesContainer ,
32+ pub export : & ' a str ,
33+ pub profile_opts : Option < & ' a ProfileOpts > ,
34+ pub scale_factor : f64 ,
35+ pub module : Module ,
36+ pub engine : Engine ,
37+ }
38+
39+ /// Parameters for a run that reuses a Function and its compiled standard provider.
40+ pub struct PreparedFunctionRunParams < ' a > {
2941 pub function_path : PathBuf ,
3042 pub input : BytesContainer ,
3143 pub export : & ' a str ,
@@ -89,6 +101,8 @@ impl ResourceLimiter for MemoryLimiter {
89101 }
90102}
91103
104+ /// Runs a Function using the supplied engine and module.
105+ /// For repeated runs, use [`run_prepared`] to compile the standard provider once.
92106pub fn run ( params : FunctionRunParams ) -> Result < FunctionRunResult > {
93107 let FunctionRunParams {
94108 function_path,
@@ -97,6 +111,67 @@ pub fn run(params: FunctionRunParams) -> Result<FunctionRunResult> {
97111 profile_opts,
98112 scale_factor,
99113 module,
114+ engine,
115+ } = params;
116+ let module = ValidatedModule :: new ( module) ?;
117+ ensure ! (
118+ Engine :: same( & engine, module. inner( ) . engine( ) ) ,
119+ "cross-`Engine` instantiation is not currently supported"
120+ ) ;
121+
122+ run_prepared ( PreparedFunctionRunParams {
123+ function_path,
124+ input,
125+ export,
126+ profile_opts,
127+ scale_factor,
128+ module : & module,
129+ } )
130+ }
131+
132+ /// Runs a prepared Function with fresh execution state, using its module's engine.
133+ ///
134+ /// Compile the Function and its standard provider once, then reuse them for each input:
135+ ///
136+ /// ```no_run
137+ /// use function_runner::{
138+ /// engine::{new_engine, run_prepared, PreparedFunctionRunParams, ValidatedModule},
139+ /// BytesContainer, BytesContainerType, Codec,
140+ /// };
141+ /// use wasmtime::Module;
142+ ///
143+ /// # fn main() -> anyhow::Result<()> {
144+ /// let engine = new_engine()?;
145+ /// let path = std::path::PathBuf::from("function.wasm");
146+ /// let module = Module::from_file(&engine, &path)?;
147+ /// let codec = if function_runner::engine::uses_msgpack_provider(&module) {
148+ /// Codec::Messagepack
149+ /// } else {
150+ /// Codec::Json
151+ /// };
152+ /// let module = ValidatedModule::new(module)?;
153+ ///
154+ /// for json in [br#"{"hello":"world"}"#, br#"{"hello":"again"}"#] {
155+ /// run_prepared(PreparedFunctionRunParams {
156+ /// function_path: path.clone(),
157+ /// input: BytesContainer::new(BytesContainerType::Input, codec, json.to_vec())?,
158+ /// export: "_start",
159+ /// profile_opts: None,
160+ /// scale_factor: 1.0,
161+ /// module: &module,
162+ /// })?;
163+ /// }
164+ /// # Ok(())
165+ /// # }
166+ /// ```
167+ pub fn run_prepared ( params : PreparedFunctionRunParams ) -> Result < FunctionRunResult > {
168+ let PreparedFunctionRunParams {
169+ function_path,
170+ input,
171+ export,
172+ profile_opts,
173+ scale_factor,
174+ module,
100175 } = params;
101176
102177 let engine = module. inner ( ) . engine ( ) ;
@@ -236,7 +311,8 @@ mod tests {
236311 function_path : Path :: new ( "tests/fixtures/build/js_function.wasm" ) . to_path_buf ( ) ,
237312 input,
238313 export : DEFAULT_EXPORT ,
239- module : & ValidatedModule :: new ( module) ?,
314+ module,
315+ engine,
240316 scale_factor : 1.0 ,
241317 profile_opts : None ,
242318 } ) ?;
@@ -260,7 +336,8 @@ mod tests {
260336 function_path : Path :: new ( "tests/fixtures/build/js_function_v2.wasm" ) . to_path_buf ( ) ,
261337 input,
262338 export : DEFAULT_EXPORT ,
263- module : & ValidatedModule :: new ( module) ?,
339+ module,
340+ engine,
264341 scale_factor : 1.0 ,
265342 profile_opts : None ,
266343 } ) ?;
@@ -284,7 +361,8 @@ mod tests {
284361 function_path : Path :: new ( "tests/fixtures/build/js_function_v3.wasm" ) . to_path_buf ( ) ,
285362 input,
286363 export : DEFAULT_EXPORT ,
287- module : & ValidatedModule :: new ( module) ?,
364+ module,
365+ engine,
288366 scale_factor : 1.0 ,
289367 profile_opts : None ,
290368 } ) ?;
@@ -293,37 +371,6 @@ mod tests {
293371 Ok ( ( ) )
294372 }
295373
296- #[ test]
297- fn test_validated_module_can_be_reused_across_runs ( ) -> Result < ( ) > {
298- let path = Path :: new ( "tests/fixtures/build/js_function_javy_plugin_v3.wasm" ) ;
299- let engine = new_engine ( ) ?;
300- let module = ValidatedModule :: new ( Module :: from_file ( & engine, path) ?) ?;
301-
302- for _ in 0 ..3 {
303- let input = BytesContainer :: new (
304- BytesContainerType :: Input ,
305- Codec :: Messagepack ,
306- serde_json:: to_vec ( & json ! ( { "hello" : "world" } ) ) ?,
307- ) ?;
308- let function_run_result = run ( FunctionRunParams {
309- function_path : path. to_path_buf ( ) ,
310- input,
311- export : DEFAULT_EXPORT ,
312- module : & module,
313- scale_factor : 1.0 ,
314- profile_opts : None ,
315- } ) ?;
316-
317- assert ! ( function_run_result. success) ;
318- assert_eq ! (
319- function_run_result. output. json_value,
320- Some ( json!( { "hello" : "world output" } ) )
321- ) ;
322- }
323-
324- Ok ( ( ) )
325- }
326-
327374 #[ test]
328375 fn test_js_functions_javy_v1 ( ) -> Result < ( ) > {
329376 let engine = new_engine ( ) ?;
@@ -340,7 +387,8 @@ mod tests {
340387 . to_path_buf ( ) ,
341388 input,
342389 export : DEFAULT_EXPORT ,
343- module : & ValidatedModule :: new ( module) ?,
390+ module,
391+ engine,
344392 scale_factor : 1.0 ,
345393 profile_opts : None ,
346394 } ) ?;
@@ -357,7 +405,8 @@ mod tests {
357405 function_path : Path :: new ( "tests/fixtures/build/exit_code.wasm" ) . to_path_buf ( ) ,
358406 input : json_input ( & serde_json:: to_vec ( & json ! ( { "code" : 0 } ) ) ?) ?,
359407 export : DEFAULT_EXPORT ,
360- module : & ValidatedModule :: new ( module) ?,
408+ module,
409+ engine,
361410 scale_factor : 1.0 ,
362411 profile_opts : None ,
363412 } ) ?;
@@ -374,7 +423,8 @@ mod tests {
374423 function_path : Path :: new ( "tests/fixtures/build/exit_code.wasm" ) . to_path_buf ( ) ,
375424 input : json_input ( & serde_json:: to_vec ( & json ! ( { "code" : 1 } ) ) ?) ?,
376425 export : DEFAULT_EXPORT ,
377- module : & ValidatedModule :: new ( module) ?,
426+ module,
427+ engine,
378428 scale_factor : 1.0 ,
379429 profile_opts : None ,
380430 } ) ?;
@@ -394,7 +444,8 @@ mod tests {
394444 function_path : Path :: new ( "tests/fixtures/build/linear_memory.wasm" ) . to_path_buf ( ) ,
395445 input : json_input ( & serde_json:: to_vec ( & json ! ( { } ) ) ?) ?,
396446 export : DEFAULT_EXPORT ,
397- module : & ValidatedModule :: new ( module) ?,
447+ module,
448+ engine,
398449 scale_factor : 1.0 ,
399450 profile_opts : None ,
400451 } ) ?;
@@ -415,7 +466,8 @@ mod tests {
415466 function_path : Path :: new ( "tests/fixtures/build/log_truncation_function.wasm" )
416467 . to_path_buf ( ) ,
417468 export : DEFAULT_EXPORT ,
418- module : & ValidatedModule :: new ( module) ?,
469+ module,
470+ engine,
419471 scale_factor : 1.0 ,
420472 profile_opts : None ,
421473 } ) ?;
@@ -440,7 +492,8 @@ mod tests {
440492 function_path : file_path. to_path_buf ( ) ,
441493 input : json_input ( & serde_json:: to_vec ( & json ! ( { "code" : 0 } ) ) ?) ?,
442494 export : DEFAULT_EXPORT ,
443- module : & ValidatedModule :: new ( module) ?,
495+ module,
496+ engine,
444497 scale_factor : 1.0 ,
445498 profile_opts : None ,
446499 } ) ?;
@@ -468,7 +521,8 @@ mod tests {
468521 function_path : trampolined_path. to_path_buf ( ) ,
469522 input : input_bytes. unwrap ( ) ,
470523 export : DEFAULT_EXPORT ,
471- module : & ValidatedModule :: new ( module) ?,
524+ module,
525+ engine,
472526 scale_factor : 1.0 ,
473527 profile_opts : None ,
474528 } ) ;
0 commit comments