hyperlight_host/func/
host_functions.rs1use 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, &mut self.mgr)
56 }
57}
58
59#[derive(Clone)]
62pub struct HostFunction<Output, Args>
63where
64 Args: ParameterTuple,
65 Output: SupportedReturnType,
66{
67 func: Arc<dyn Function<Output, Args, HyperlightError> + Send + Sync + 'static>,
92}
93
94pub(crate) struct TypeErasedHostFunction {
95 func: Box<dyn Fn(Vec<ParameterValue>) -> Result<ReturnValue> + Send + Sync + 'static>,
96}
97
98impl<Args, Output> HostFunction<Output, Args>
99where
100 Args: ParameterTuple,
101 Output: SupportedReturnType,
102{
103 pub fn call(&self, args: Args) -> Result<Output> {
105 self.func.call(args)
106 }
107}
108
109impl TypeErasedHostFunction {
110 pub(crate) fn call(&self, args: Vec<ParameterValue>) -> Result<ReturnValue> {
111 (self.func)(args)
112 }
113}
114
115impl From<FuncError> for HyperlightError {
116 fn from(e: FuncError) -> Self {
117 match e {
118 FuncError::ParameterValueConversionFailure(from, to) => {
119 HyperlightError::ParameterValueConversionFailure(from, to)
120 }
121 FuncError::ReturnValueConversionFailure(from, to) => {
122 HyperlightError::ReturnValueConversionFailure(from, to)
123 }
124 FuncError::UnexpectedNoOfArguments(got, expected) => {
125 HyperlightError::UnexpectedNoOfArguments(got, expected)
126 }
127 FuncError::UnexpectedParameterValueType(got, expected) => {
128 HyperlightError::UnexpectedParameterValueType(got, expected)
129 }
130 FuncError::UnexpectedReturnValueType(got, expected) => {
131 HyperlightError::UnexpectedReturnValueType(got, expected)
132 }
133 }
134 }
135}
136
137impl<Args, Output> From<HostFunction<Output, Args>> for TypeErasedHostFunction
138where
139 Args: ParameterTuple,
140 Output: SupportedReturnType,
141{
142 fn from(func: HostFunction<Output, Args>) -> TypeErasedHostFunction {
143 TypeErasedHostFunction {
144 func: Box::new(move |args: Vec<ParameterValue>| {
145 let args = Args::from_value(args)?;
146 Ok(func.call(args)?.into_value())
147 }),
148 }
149 }
150}
151
152macro_rules! impl_host_function {
153 ([$N:expr] ($($p:ident: $P:ident),*)) => {
154 impl<F, R, $($P),*> From<F> for HostFunction<R::ReturnType, ($($P,)*)>
162 where
163 F: FnMut($($P),*) -> R + Send + 'static,
164 ($($P,)*): ParameterTuple,
165 R: ResultType<HyperlightError>,
166 {
167 fn from(func: F) -> HostFunction<R::ReturnType, ($($P,)*)> {
168 let func = Mutex::new(func);
169 let func = move |$($p: $P,)*| {
170 let mut func = func.lock().map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?;
171 (func)($($p),*).into_result()
172 };
173 let func = Arc::new(func);
174 HostFunction { func }
175 }
176 }
177 };
178}
179
180for_each_tuple!(impl_host_function);
181
182pub(crate) fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
183 func: impl Into<HostFunction<Output, Args>>,
184 sandbox: &mut UninitializedSandbox,
185 name: &str,
186) -> Result<()> {
187 let func = func.into().into();
188
189 let entry = FunctionEntry {
190 function: func,
191 parameter_types: Args::TYPE,
192 return_type: Output::TYPE,
193 };
194
195 sandbox
196 .host_funcs
197 .try_lock()
198 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
199 .register_host_function(name.to_string(), entry, &mut sandbox.mgr)?;
200
201 Ok(())
202}