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 }
57}
58
59impl Registerable for crate::MultiUseSandbox {
79 fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
80 &mut self,
81 name: &str,
82 hf: impl Into<HostFunction<Output, Args>>,
83 ) -> Result<()> {
84 let mut hfs = self
85 .host_funcs
86 .try_lock()
87 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
88
89 let entry = FunctionEntry {
90 function: hf.into().into(),
91 parameter_types: Args::TYPE,
92 return_type: Output::TYPE,
93 };
94
95 (*hfs).register_host_function(name.to_string(), entry)
96 }
97}
98
99#[derive(Clone)]
102pub struct HostFunction<Output, Args>
103where
104 Args: ParameterTuple,
105 Output: SupportedReturnType,
106{
107 func: Arc<dyn Function<Output, Args, HyperlightError> + Send + Sync + 'static>,
132}
133
134pub(crate) struct TypeErasedHostFunction {
135 func: Box<dyn Fn(Vec<ParameterValue>) -> Result<ReturnValue> + Send + Sync + 'static>,
136}
137
138impl<Args, Output> HostFunction<Output, Args>
139where
140 Args: ParameterTuple,
141 Output: SupportedReturnType,
142{
143 pub fn call(&self, args: Args) -> Result<Output> {
145 self.func.call(args)
146 }
147}
148
149impl TypeErasedHostFunction {
150 pub(crate) fn call(&self, args: Vec<ParameterValue>) -> Result<ReturnValue> {
151 (self.func)(args)
152 }
153}
154
155impl From<FuncError> for HyperlightError {
156 fn from(e: FuncError) -> Self {
157 match e {
158 FuncError::ParameterValueConversionFailure(from, to) => {
159 HyperlightError::ParameterValueConversionFailure(from, to)
160 }
161 FuncError::ReturnValueConversionFailure(from, to) => {
162 HyperlightError::ReturnValueConversionFailure(from, to)
163 }
164 FuncError::UnexpectedNoOfArguments(got, expected) => {
165 HyperlightError::UnexpectedNoOfArguments(got, expected)
166 }
167 FuncError::UnexpectedParameterValueType(got, expected) => {
168 HyperlightError::UnexpectedParameterValueType(got, expected)
169 }
170 FuncError::UnexpectedReturnValueType(got, expected) => {
171 HyperlightError::UnexpectedReturnValueType(got, expected)
172 }
173 }
174 }
175}
176
177impl<Args, Output> From<HostFunction<Output, Args>> for TypeErasedHostFunction
178where
179 Args: ParameterTuple,
180 Output: SupportedReturnType,
181{
182 fn from(func: HostFunction<Output, Args>) -> TypeErasedHostFunction {
183 TypeErasedHostFunction {
184 func: Box::new(move |args: Vec<ParameterValue>| {
185 let args = Args::from_value(args)?;
186 Ok(func.call(args)?.into_value())
187 }),
188 }
189 }
190}
191
192macro_rules! impl_host_function {
193 ([$N:expr] ($($p:ident: $P:ident),*)) => {
194 impl<F, R, $($P),*> From<F> for HostFunction<R::ReturnType, ($($P,)*)>
202 where
203 F: FnMut($($P),*) -> R + Send + 'static,
204 ($($P,)*): ParameterTuple,
205 R: ResultType<HyperlightError>,
206 {
207 fn from(func: F) -> HostFunction<R::ReturnType, ($($P,)*)> {
208 let func = Mutex::new(func);
209 let func = move |$($p: $P,)*| {
210 let mut func = func.lock().map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
211 (func)($($p),*).into_result()
212 };
213 let func = Arc::new(func);
214 HostFunction { func }
215 }
216 }
217 };
218}
219
220for_each_tuple!(impl_host_function);
221
222pub(crate) fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
223 func: impl Into<HostFunction<Output, Args>>,
224 sandbox: &mut UninitializedSandbox,
225 name: &str,
226) -> Result<()> {
227 let func = func.into().into();
228
229 let entry = FunctionEntry {
230 function: func,
231 parameter_types: Args::TYPE,
232 return_type: Output::TYPE,
233 };
234
235 sandbox
236 .host_funcs
237 .try_lock()
238 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
239 .register_host_function(name.to_string(), entry)?;
240
241 Ok(())
242}