1use std::sync::{Arc, Mutex};
18
19use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
20use hyperlight_common::for_each_tuple;
21use hyperlight_common::func::{Error as FuncError, Function, ResultType};
22
23use super::{ParameterTuple, SupportedReturnType};
24use crate::sandbox::UninitializedSandbox;
25use crate::sandbox::host_funcs::FunctionEntry;
26use crate::{HyperlightError, Result, new_error};
27
28pub trait Registerable {
31 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
33 &mut self,
34 name: &str,
35 hf: impl Into<HostFunction<Output, Args>>,
36 ) -> Result<()>;
37}
38impl Registerable for UninitializedSandbox {
39 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
40 &mut self,
41 name: &str,
42 hf: impl Into<HostFunction<Output, Args>>,
43 ) -> Result<()> {
44 let mut hfs = self
45 .host_funcs
46 .try_lock()
47 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
48
49 let entry = FunctionEntry {
50 function: hf.into().into(),
51 parameter_types: Args::TYPE,
52 return_type: Output::TYPE,
53 };
54
55 (*hfs).register_host_function(name.to_string(), entry);
56 Ok(())
57 }
58}
59
60impl Registerable for crate::MultiUseSandbox {
80 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
81 &mut self,
82 name: &str,
83 hf: impl Into<HostFunction<Output, Args>>,
84 ) -> Result<()> {
85 let mut hfs = self
86 .host_funcs
87 .try_lock()
88 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
89
90 let entry = FunctionEntry {
91 function: hf.into().into(),
92 parameter_types: Args::TYPE,
93 return_type: Output::TYPE,
94 };
95
96 (*hfs).register_host_function(name.to_string(), entry);
97
98 self.snapshot = None;
102 Ok(())
103 }
104}
105
106impl Registerable for crate::HostFunctions {
107 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
108 &mut self,
109 name: &str,
110 hf: impl Into<HostFunction<Output, Args>>,
111 ) -> Result<()> {
112 let entry = FunctionEntry {
113 function: hf.into().into(),
114 parameter_types: Args::TYPE,
115 return_type: Output::TYPE,
116 };
117
118 self.inner_mut()
119 .register_host_function(name.to_string(), entry);
120 Ok(())
121 }
122}
123
124#[derive(Clone)]
127pub struct HostFunction<Output, Args>
128where
129 Args: ParameterTuple,
130 Output: SupportedReturnType,
131{
132 func: Arc<dyn Function<Output, Args, HyperlightError> + Send + Sync + 'static>,
157}
158
159pub(crate) struct TypeErasedHostFunction {
160 func: Box<dyn Fn(Vec<ParameterValue>) -> Result<ReturnValue> + Send + Sync + 'static>,
161}
162
163impl<Args, Output> HostFunction<Output, Args>
164where
165 Args: ParameterTuple,
166 Output: SupportedReturnType,
167{
168 pub fn call(&self, args: Args) -> Result<Output> {
170 self.func.call(args)
171 }
172}
173
174impl TypeErasedHostFunction {
175 pub(crate) fn call(&self, args: Vec<ParameterValue>) -> Result<ReturnValue> {
176 (self.func)(args)
177 }
178}
179
180impl From<FuncError> for HyperlightError {
181 fn from(e: FuncError) -> Self {
182 match e {
183 FuncError::ParameterValueConversionFailure(from, to) => {
184 HyperlightError::ParameterValueConversionFailure(from, to)
185 }
186 FuncError::ReturnValueConversionFailure(from, to) => {
187 HyperlightError::ReturnValueConversionFailure(from, to)
188 }
189 FuncError::UnexpectedNoOfArguments(got, expected) => {
190 HyperlightError::UnexpectedNoOfArguments(got, expected)
191 }
192 FuncError::UnexpectedParameterValueType(got, expected) => {
193 HyperlightError::UnexpectedParameterValueType(got, expected)
194 }
195 FuncError::UnexpectedReturnValueType(got, expected) => {
196 HyperlightError::UnexpectedReturnValueType(got, expected)
197 }
198 }
199 }
200}
201
202impl<Args, Output> From<HostFunction<Output, Args>> for TypeErasedHostFunction
203where
204 Args: ParameterTuple,
205 Output: SupportedReturnType,
206{
207 fn from(func: HostFunction<Output, Args>) -> TypeErasedHostFunction {
208 TypeErasedHostFunction {
209 func: Box::new(move |args: Vec<ParameterValue>| {
210 let args = Args::from_value(args)?;
211 Ok(func.call(args)?.into_value())
212 }),
213 }
214 }
215}
216
217macro_rules! impl_host_function {
218 ([$N:expr] ($($p:ident: $P:ident),*)) => {
219 impl<F, R, $($P),*> From<F> for HostFunction<R::ReturnType, ($($P,)*)>
227 where
228 F: FnMut($($P),*) -> R + Send + 'static,
229 ($($P,)*): ParameterTuple,
230 R: ResultType<HyperlightError>,
231 {
232 fn from(func: F) -> HostFunction<R::ReturnType, ($($P,)*)> {
233 let func = Mutex::new(func);
234 let func = move |$($p: $P,)*| {
235 let mut func = func.lock().map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
236 (func)($($p),*).into_result()
237 };
238 let func = Arc::new(func);
239 HostFunction { func }
240 }
241 }
242 };
243}
244
245for_each_tuple!(impl_host_function);
246
247pub(crate) fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
248 func: impl Into<HostFunction<Output, Args>>,
249 sandbox: &mut UninitializedSandbox,
250 name: &str,
251) -> Result<()> {
252 let func = func.into().into();
253
254 let entry = FunctionEntry {
255 function: func,
256 parameter_types: Args::TYPE,
257 return_type: Output::TYPE,
258 };
259
260 sandbox
261 .host_funcs
262 .try_lock()
263 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
264 .register_host_function(name.to_string(), entry);
265
266 Ok(())
267}