1use std::sync::Arc;
9
10use harn_vm::{Vm, VmError, VmValue};
11
12use crate::error::HostlibError;
13
14pub type SyncHandler = Arc<dyn Fn(&[VmValue]) -> Result<VmValue, HostlibError> + Send + Sync>;
18
19#[derive(Clone)]
23pub struct RegisteredBuiltin {
24 pub name: &'static str,
26 pub module: &'static str,
28 pub method: &'static str,
30 pub handler: SyncHandler,
32}
33
34impl std::fmt::Debug for RegisteredBuiltin {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 f.debug_struct("RegisteredBuiltin")
37 .field("name", &self.name)
38 .field("module", &self.module)
39 .field("method", &self.method)
40 .finish()
41 }
42}
43
44#[derive(Default)]
46pub struct BuiltinRegistry {
47 builtins: Vec<RegisteredBuiltin>,
48}
49
50impl BuiltinRegistry {
51 pub fn new() -> Self {
53 Self::default()
54 }
55
56 pub fn register(&mut self, builtin: RegisteredBuiltin) {
58 self.builtins.push(builtin);
59 }
60
61 pub fn register_unimplemented(
64 &mut self,
65 name: &'static str,
66 module: &'static str,
67 method: &'static str,
68 ) {
69 let handler: SyncHandler =
70 Arc::new(move |_args| Err(HostlibError::Unimplemented { builtin: name }));
71 self.register(RegisteredBuiltin {
72 name,
73 module,
74 method,
75 handler,
76 });
77 }
78
79 pub fn iter(&self) -> impl Iterator<Item = &RegisteredBuiltin> {
81 self.builtins.iter()
82 }
83
84 pub fn len(&self) -> usize {
86 self.builtins.len()
87 }
88
89 pub fn is_empty(&self) -> bool {
91 self.builtins.is_empty()
92 }
93
94 pub fn find(&self, name: &str) -> Option<&RegisteredBuiltin> {
96 self.builtins.iter().find(|b| b.name == name)
97 }
98}
99
100pub trait HostlibCapability: 'static {
104 fn module_name(&self) -> &'static str;
106
107 fn register_builtins(&self, registry: &mut BuiltinRegistry);
109}
110
111pub struct HostlibRegistry {
117 builtins: BuiltinRegistry,
118 modules: Vec<&'static str>,
119}
120
121impl Default for HostlibRegistry {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl HostlibRegistry {
128 pub fn new() -> Self {
131 Self {
132 builtins: BuiltinRegistry::new(),
133 modules: Vec::new(),
134 }
135 }
136
137 #[must_use]
139 pub fn with<C: HostlibCapability>(mut self, capability: C) -> Self {
140 let module = capability.module_name();
141 capability.register_builtins(&mut self.builtins);
142 self.modules.push(module);
143 self
144 }
145
146 pub fn register_into_vm(&mut self, vm: &mut Vm) {
148 for builtin in self.builtins.iter().cloned().collect::<Vec<_>>() {
149 let handler = builtin.handler.clone();
150 vm.register_builtin(
151 builtin.name,
152 move |args, _out| -> Result<VmValue, VmError> {
153 handler(args).map_err(VmError::from)
154 },
155 );
156 }
157 }
158
159 pub fn builtins(&self) -> &BuiltinRegistry {
162 &self.builtins
163 }
164
165 pub fn modules(&self) -> &[&'static str] {
167 &self.modules
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn unimplemented_builtins_route_through_error() {
177 let mut registry = BuiltinRegistry::new();
178 registry.register_unimplemented("hostlib_demo", "demo", "ping");
179 let entry = registry.find("hostlib_demo").expect("registered");
180 let err = (entry.handler)(&[]).expect_err("should be unimplemented");
181 assert!(
182 matches!(err, HostlibError::Unimplemented { builtin } if builtin == "hostlib_demo")
183 );
184 }
185
186 #[test]
187 fn registry_records_modules_in_order() {
188 struct First;
189 impl HostlibCapability for First {
190 fn module_name(&self) -> &'static str {
191 "first"
192 }
193 fn register_builtins(&self, _registry: &mut BuiltinRegistry) {}
194 }
195 struct Second;
196 impl HostlibCapability for Second {
197 fn module_name(&self) -> &'static str {
198 "second"
199 }
200 fn register_builtins(&self, _registry: &mut BuiltinRegistry) {}
201 }
202
203 let registry = HostlibRegistry::new().with(First).with(Second);
204 assert_eq!(registry.modules(), &["first", "second"]);
205 }
206}