1use std::sync::{Arc, Mutex};
5
6use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
7use hyperlight_common::for_each_tuple;
8use hyperlight_common::func::{Error as FuncError, Function, ResultType};
9
10use super::{ParameterTuple, SupportedReturnType};
11use crate::sandbox::UninitializedSandbox;
12use crate::sandbox::host_funcs::FunctionEntry;
13use crate::{HyperlightError, Result, new_error};
14
15pub trait Registerable {
18 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
20 &mut self,
21 name: &str,
22 hf: impl Into<HostFunction<Output, Args>>,
23 ) -> Result<()>;
24}
25impl Registerable for UninitializedSandbox {
26 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
27 &mut self,
28 name: &str,
29 hf: impl Into<HostFunction<Output, Args>>,
30 ) -> Result<()> {
31 let mut hfs = self
32 .host_funcs
33 .try_lock()
34 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
35
36 let entry = FunctionEntry {
37 function: hf.into().into(),
38 parameter_types: Args::TYPE,
39 return_type: Output::TYPE,
40 };
41
42 (*hfs).register_host_function(name.to_string(), entry);
43 Ok(())
44 }
45}
46
47impl Registerable for crate::MultiUseSandbox {
67 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
68 &mut self,
69 name: &str,
70 hf: impl Into<HostFunction<Output, Args>>,
71 ) -> Result<()> {
72 let mut hfs = self
73 .host_funcs
74 .try_lock()
75 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
76
77 let entry = FunctionEntry {
78 function: hf.into().into(),
79 parameter_types: Args::TYPE,
80 return_type: Output::TYPE,
81 };
82
83 (*hfs).register_host_function(name.to_string(), entry);
84
85 self.snapshot = None;
89 Ok(())
90 }
91}
92
93impl Registerable for crate::HostFunctions {
94 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
95 &mut self,
96 name: &str,
97 hf: impl Into<HostFunction<Output, Args>>,
98 ) -> Result<()> {
99 let entry = FunctionEntry {
100 function: hf.into().into(),
101 parameter_types: Args::TYPE,
102 return_type: Output::TYPE,
103 };
104
105 self.inner_mut()
106 .register_host_function(name.to_string(), entry);
107 Ok(())
108 }
109}
110
111#[derive(Clone)]
114pub struct HostFunction<Output, Args>
115where
116 Args: ParameterTuple,
117 Output: SupportedReturnType,
118{
119 func: Arc<dyn Function<Output, Args, HyperlightError> + Send + Sync + 'static>,
144}
145
146pub(crate) struct TypeErasedHostFunction {
147 func: Box<dyn Fn(Vec<ParameterValue>) -> Result<ReturnValue> + Send + Sync + 'static>,
148}
149
150impl<Args, Output> HostFunction<Output, Args>
151where
152 Args: ParameterTuple,
153 Output: SupportedReturnType,
154{
155 pub fn call(&self, args: Args) -> Result<Output> {
157 self.func.call(args)
158 }
159}
160
161impl TypeErasedHostFunction {
162 pub(crate) fn call(&self, args: Vec<ParameterValue>) -> Result<ReturnValue> {
163 (self.func)(args)
164 }
165}
166
167impl From<FuncError> for HyperlightError {
168 fn from(e: FuncError) -> Self {
169 match e {
170 FuncError::ParameterValueConversionFailure(from, to) => {
171 HyperlightError::ParameterValueConversionFailure(from, to)
172 }
173 FuncError::ReturnValueConversionFailure(from, to) => {
174 HyperlightError::ReturnValueConversionFailure(from, to)
175 }
176 FuncError::UnexpectedNoOfArguments(got, expected) => {
177 HyperlightError::UnexpectedNoOfArguments(got, expected)
178 }
179 FuncError::UnexpectedParameterValueType(got, expected) => {
180 HyperlightError::UnexpectedParameterValueType(got, expected)
181 }
182 FuncError::UnexpectedReturnValueType(got, expected) => {
183 HyperlightError::UnexpectedReturnValueType(got, expected)
184 }
185 }
186 }
187}
188
189impl<Args, Output> From<HostFunction<Output, Args>> for TypeErasedHostFunction
190where
191 Args: ParameterTuple,
192 Output: SupportedReturnType,
193{
194 fn from(func: HostFunction<Output, Args>) -> TypeErasedHostFunction {
195 TypeErasedHostFunction {
196 func: Box::new(move |args: Vec<ParameterValue>| {
197 let args = Args::from_value(args)?;
198 Ok(func.call(args)?.into_value())
199 }),
200 }
201 }
202}
203
204macro_rules! impl_host_function {
205 ([$N:expr] ($($p:ident: $P:ident),*)) => {
206 impl<F, R, $($P),*> From<F> for HostFunction<R::ReturnType, ($($P,)*)>
214 where
215 F: FnMut($($P),*) -> R + Send + 'static,
216 ($($P,)*): ParameterTuple,
217 R: ResultType<HyperlightError>,
218 {
219 fn from(func: F) -> HostFunction<R::ReturnType, ($($P,)*)> {
220 let func = Mutex::new(func);
221 let func = move |$($p: $P,)*| {
222 let mut func = func.lock().map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
223 (func)($($p),*).into_result()
224 };
225 let func = Arc::new(func);
226 HostFunction { func }
227 }
228 }
229 };
230}
231
232for_each_tuple!(impl_host_function);
233
234pub(crate) fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
235 func: impl Into<HostFunction<Output, Args>>,
236 sandbox: &mut UninitializedSandbox,
237 name: &str,
238) -> Result<()> {
239 let func = func.into().into();
240
241 let entry = FunctionEntry {
242 function: func,
243 parameter_types: Args::TYPE,
244 return_type: Output::TYPE,
245 };
246
247 sandbox
248 .host_funcs
249 .try_lock()
250 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
251 .register_host_function(name.to_string(), entry);
252
253 Ok(())
254}