rush_wasm_engine/
wasm_runtime_build.rs1use crate::{WasmLoaderFile, WasmRuntime, WASM_LOADER_FILE};
2use anyhow::anyhow;
3use std::collections::HashMap;
4use wd_tools::PFErr;
5
6#[async_trait::async_trait]
7pub trait WasmLoader: Send + Sync {
8 fn load(&self, _rule_name: String, file: String) -> anyhow::Result<Vec<u8>>;
9 async fn async_load(&self, rule_name: String, file: String) -> anyhow::Result<Vec<u8>> {
10 self.load(rule_name, file)
11 }
12}
13
14#[derive(Default)]
15pub struct WasmRuntimeFactory {
16 loader: HashMap<&'static str, Box<dyn WasmLoader>>,
17}
18
19impl WasmRuntimeFactory {
20 pub fn new() -> Self {
21 let loader: HashMap<&'static str, Box<dyn WasmLoader>> = HashMap::new();
22 let mut lrf = Self { loader };
23 lrf.add_loader(WASM_LOADER_FILE, WasmLoaderFile);
24 lrf
25 }
26 pub fn add_loader<Load: WasmLoader + 'static>(&mut self, tag: &'static str, loader: Load) {
27 self.loader.insert(tag, Box::new(loader));
28 }
29 pub fn remove_loader<S: AsRef<str>>(&mut self, tag: S) {
30 self.loader.remove(tag.as_ref());
31 }
32 fn check_engine(buf: &str) -> anyhow::Result<(String, String)> {
33 let buf = buf.trim_start_matches(|c| " \n\r\t".contains(c));
34 let (head, body) = if let Some(s) = buf.split_once('\n') {
35 s
36 } else {
37 return anyhow!("first input must is : rule [name] [description] wasm [other]").err();
38 };
39 let list = head.split(' ').collect::<Vec<_>>();
40 if list.len() < 4 {
41 return anyhow!("rule header format: rule [name] [description] wasm [other]").err();
42 }
43 if list[0].to_lowercase() != "rule" {
44 return anyhow!("rule header must have start 'rule'").err();
45 }
46 if list[3].to_lowercase() != "wasm" {
47 return anyhow!("WasmRuntime no support rule[{}]", list[3]).err();
48 }
49 let body = body.trim_start_matches(|c| " \n\r\t".contains(c));
50 Ok((list[2].to_string(), body.into()))
51 }
52 pub fn build<S: AsRef<str>>(&self, rule: S) -> anyhow::Result<WasmRuntime> {
53 let (rule, buf) = Self::check_engine(rule.as_ref())?;
54 for (k, v) in self.loader.iter() {
55 if buf.starts_with(*k) {
56 let bytes = v.load(rule, buf)?;
57 return WasmRuntime::new(bytes);
58 }
59 }
60 anyhow!("not found eligible loader").err()
61 }
62 pub async fn async_build<S: AsRef<str>>(&self, rule: S) -> anyhow::Result<WasmRuntime> {
63 let (rule, buf) = Self::check_engine(rule.as_ref())?;
64 for (k, v) in self.loader.iter() {
65 if buf.starts_with(*k) {
66 let bytes = v.async_load(rule, buf).await?;
67 return WasmRuntime::new(bytes);
68 }
69 }
70 anyhow!("not found eligible loader").err()
71 }
72}
73
74#[cfg(test)]
75mod test {
76 use crate::WasmRuntimeFactory;
77 use serde_json::Value;
78 use std::collections::HashMap;
79
80 const WASM_RULE: &'static str = "
81 rule WASM_RULE _ wasm
82 wasm_file: ../target/wasm32-unknown-unknown/release/wasm_example_one.wasm
83 ";
84
85 #[test]
86 fn test_wasm_build() {
87 let rt = WasmRuntimeFactory::new().build(WASM_RULE).unwrap();
88
89 let result: HashMap<String, String> = rt.call(Value::String("hello".into())).unwrap();
90 assert_eq!(result.get("input").unwrap().as_str(), "hello");
91 }
92}