1use indexmap::IndexMap;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6pub enum WasmType {
7 I32,
9 I64,
11 F32,
13 F64,
15 Ptr,
17 Void,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct HostFunctionDef {
24 pub name: String,
26 pub params: Vec<WasmType>,
28 pub return_type: WasmType,
30}
31
32impl HostFunctionDef {
33 pub fn new(name: impl Into<String>, params: Vec<WasmType>, return_type: WasmType) -> Self {
34 Self {
35 name: name.into(),
36 params,
37 return_type,
38 }
39 }
40}
41
42#[derive(Debug, Clone, Default)]
45pub struct HostFunctionRegistry {
46 functions: IndexMap<String, HostFunctionDef>,
47}
48
49impl HostFunctionRegistry {
50 pub fn with_standard_functions() -> Self {
52 let mut registry = Self::default();
53
54 registry.register(HostFunctionDef::new(
56 "hstringEquals",
57 vec![WasmType::Ptr, WasmType::Ptr],
58 WasmType::I32,
59 ));
60
61 registry.register(HostFunctionDef::new(
63 "hlistContainsString",
64 vec![WasmType::Ptr, WasmType::Ptr],
65 WasmType::I32,
66 ));
67 registry.register(HostFunctionDef::new("hnewList", vec![], WasmType::Ptr));
68
69 registry.register(HostFunctionDef::new(
70 "hgetItem",
71 vec![WasmType::Ptr, WasmType::I32],
72 WasmType::Ptr,
73 ));
74
75 registry.register(HostFunctionDef::new(
76 "hsize",
77 vec![WasmType::Ptr],
78 WasmType::I32,
79 ));
80
81 registry.register(HostFunctionDef::new(
82 "happend",
83 vec![WasmType::Ptr, WasmType::Ptr],
84 WasmType::Void,
85 ));
86
87 registry.register(HostFunctionDef::new(
88 "hsetItem",
89 vec![WasmType::Ptr, WasmType::I32, WasmType::Ptr],
90 WasmType::Void,
91 ));
92
93 registry.register(HostFunctionDef::new(
94 "hinsert",
95 vec![WasmType::Ptr, WasmType::I32, WasmType::Ptr],
96 WasmType::Void,
97 ));
98
99 registry.register(HostFunctionDef::new(
100 "hremove",
101 vec![WasmType::Ptr, WasmType::I32],
102 WasmType::Void,
103 ));
104
105 registry.register(HostFunctionDef::new(
107 "hparseSchedule",
108 vec![WasmType::I32, WasmType::Ptr], WasmType::Ptr,
110 ));
111
112 registry.register(HostFunctionDef::new(
113 "hscheduleString",
114 vec![WasmType::Ptr],
115 WasmType::Ptr,
116 ));
117
118 registry.register(HostFunctionDef::new(
120 "hround",
121 vec![WasmType::F32],
122 WasmType::I32,
123 ));
124
125 registry
126 }
127
128 pub fn new() -> Self {
130 Self::default()
131 }
132
133 pub fn register(&mut self, def: HostFunctionDef) {
135 self.functions.insert(def.name.clone(), def);
136 }
137
138 pub fn lookup(&self, name: &str) -> Option<&HostFunctionDef> {
140 self.functions.get(name)
141 }
142
143 pub fn function_names(&self) -> Vec<&str> {
145 self.functions.keys().map(|s| s.as_str()).collect()
146 }
147
148 pub fn len(&self) -> usize {
150 self.functions.len()
151 }
152
153 pub fn is_empty(&self) -> bool {
155 self.functions.is_empty()
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn test_empty_registry() {
165 let registry = HostFunctionRegistry::new();
166 assert_eq!(registry.len(), 0);
167 assert!(registry.is_empty());
168 }
169
170 #[test]
171 fn test_register_function() {
172 let mut registry = HostFunctionRegistry::new();
173 let func = HostFunctionDef::new(
174 "test_func",
175 vec![WasmType::I32, WasmType::Ptr],
176 WasmType::I32,
177 );
178
179 registry.register(func.clone());
180 assert_eq!(registry.len(), 1);
181
182 let looked_up = registry.lookup("test_func");
183 assert!(looked_up.is_some());
184 assert_eq!(looked_up.unwrap(), &func);
185 }
186
187 #[test]
188 fn test_lookup_nonexistent() {
189 let registry = HostFunctionRegistry::new();
190 assert!(registry.lookup("nonexistent").is_none());
191 }
192
193 #[test]
194 fn test_standard_functions() {
195 let registry = HostFunctionRegistry::with_standard_functions();
196
197 assert!(registry.len() > 0);
199
200 assert!(registry.lookup("hstringEquals").is_some());
202 assert!(registry.lookup("hnewList").is_some());
203 assert!(registry.lookup("hgetItem").is_some());
204 assert!(registry.lookup("hsize").is_some());
205 assert!(registry.lookup("happend").is_some());
206 assert!(registry.lookup("hparseSchedule").is_some());
207 assert!(registry.lookup("hscheduleString").is_some());
208 assert!(registry.lookup("hround").is_some());
209 }
210
211 #[test]
212 fn test_hstring_equals_signature() {
213 let registry = HostFunctionRegistry::with_standard_functions();
214 let func = registry.lookup("hstringEquals").unwrap();
215
216 assert_eq!(func.name, "hstringEquals");
217 assert_eq!(func.params, vec![WasmType::Ptr, WasmType::Ptr]);
218 assert_eq!(func.return_type, WasmType::I32);
219 }
220
221 #[test]
222 fn test_function_names() {
223 let mut registry = HostFunctionRegistry::new();
224 registry.register(HostFunctionDef::new("func1", vec![], WasmType::Void));
225 registry.register(HostFunctionDef::new("func2", vec![], WasmType::Void));
226
227 let names = registry.function_names();
228 assert_eq!(names.len(), 2);
229 assert!(names.contains(&"func1"));
230 assert!(names.contains(&"func2"));
231 }
232
233 #[test]
234 fn test_wasm_type_serialization() {
235 let wasm_type = WasmType::I32;
236 let json = serde_json::to_string(&wasm_type).unwrap();
237 let deserialized: WasmType = serde_json::from_str(&json).unwrap();
238 assert_eq!(wasm_type, deserialized);
239 }
240}