hyperlight_guest_bin/guest_function/
definition.rs1use alloc::format;
5use alloc::string::String;
6use alloc::vec::Vec;
7
8use hyperlight_common::flatbuffer_wrappers::function_call::FunctionCall;
9use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterType, ReturnType};
10use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
11use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result;
12use hyperlight_common::for_each_tuple;
13use hyperlight_common::func::{
14 Function, ParameterTuple, ResultType, ReturnValue, SupportedReturnType,
15};
16use hyperlight_guest::error::{HyperlightGuestError, Result};
17
18pub type GuestFunc = fn(FunctionCall) -> Result<Vec<u8>>;
20
21#[derive(Debug, Clone)]
26pub struct GuestFunctionDefinition<F: Copy> {
27 pub function_name: String,
29 pub parameter_types: Vec<ParameterType>,
31 pub return_type: ReturnType,
33 pub function_pointer: F,
35}
36
37#[doc(hidden)]
39pub trait IntoGuestFunction<Output, Args>
40where
41 Self: Function<Output, Args, HyperlightGuestError>,
42 Self: Copy + 'static,
43 Output: SupportedReturnType,
44 Args: ParameterTuple,
45{
46 #[doc(hidden)]
47 const ASSERT_ZERO_SIZED: ();
48
49 fn into_guest_function(self) -> fn(FunctionCall) -> Result<Vec<u8>>;
51}
52
53pub trait AsGuestFunctionDefinition<Output, Args>
55where
56 Self: Function<Output, Args, HyperlightGuestError>,
57 Self: IntoGuestFunction<Output, Args>,
58 Output: SupportedReturnType,
59 Args: ParameterTuple,
60{
61 fn as_guest_function_definition(
63 &self,
64 name: impl Into<String>,
65 ) -> GuestFunctionDefinition<GuestFunc>;
66}
67
68fn into_flatbuffer_result(value: ReturnValue) -> Vec<u8> {
69 match value {
70 ReturnValue::Void(()) => get_flatbuffer_result(()),
71 ReturnValue::Int(i) => get_flatbuffer_result(i),
72 ReturnValue::UInt(u) => get_flatbuffer_result(u),
73 ReturnValue::Long(l) => get_flatbuffer_result(l),
74 ReturnValue::ULong(ul) => get_flatbuffer_result(ul),
75 ReturnValue::Float(f) => get_flatbuffer_result(f),
76 ReturnValue::Double(d) => get_flatbuffer_result(d),
77 ReturnValue::Bool(b) => get_flatbuffer_result(b),
78 ReturnValue::String(s) => get_flatbuffer_result(s.as_str()),
79 ReturnValue::VecBytes(v) => get_flatbuffer_result(v.as_slice()),
80 }
81}
82
83macro_rules! impl_host_function {
84 ([$N:expr] ($($p:ident: $P:ident),*)) => {
85 impl<F, R, $($P),*> IntoGuestFunction<R::ReturnType, ($($P,)*)> for F
86 where
87 F: Fn($($P),*) -> R,
88 F: Function<R::ReturnType, ($($P,)*), HyperlightGuestError>,
89 F: Copy + 'static, ($($P,)*): ParameterTuple,
91 R: ResultType<HyperlightGuestError>,
92 {
93 #[doc(hidden)]
119 const ASSERT_ZERO_SIZED: () = const {
120 assert!(core::mem::size_of::<Self>() == 0)
121 };
122
123 fn into_guest_function(self) -> fn(FunctionCall) -> Result<Vec<u8>> {
124 |fc: FunctionCall| {
125 let this = unsafe { core::mem::zeroed::<F>() };
130 let params = fc.parameters.unwrap_or_default();
131 let params = <($($P,)*) as ParameterTuple>::from_value(params)?;
132 let result = Function::<R::ReturnType, ($($P,)*), HyperlightGuestError>::call(&this, params)?;
133 Ok(into_flatbuffer_result(result.into_value()))
134 }
135 }
136 }
137 };
138}
139
140impl<F, Args, Output> AsGuestFunctionDefinition<Output, Args> for F
141where
142 F: IntoGuestFunction<Output, Args>,
143 Args: ParameterTuple,
144 Output: SupportedReturnType,
145{
146 fn as_guest_function_definition(
147 &self,
148 name: impl Into<String>,
149 ) -> GuestFunctionDefinition<GuestFunc> {
150 let parameter_types = Args::TYPE.to_vec();
151 let return_type = Output::TYPE;
152 let function_pointer = self.into_guest_function();
153
154 GuestFunctionDefinition {
155 function_name: name.into(),
156 parameter_types,
157 return_type,
158 function_pointer,
159 }
160 }
161}
162
163for_each_tuple!(impl_host_function);
164
165impl<F: Copy> GuestFunctionDefinition<F> {
166 pub fn new(
168 function_name: String,
169 parameter_types: Vec<ParameterType>,
170 return_type: ReturnType,
171 function_pointer: F,
172 ) -> Self {
173 Self {
174 function_name,
175 parameter_types,
176 return_type,
177 function_pointer,
178 }
179 }
180
181 pub fn from_fn<Output, Args>(
184 function_name: String,
185 function: impl AsGuestFunctionDefinition<Output, Args>,
186 ) -> GuestFunctionDefinition<GuestFunc>
187 where
188 Args: ParameterTuple,
189 Output: SupportedReturnType,
190 {
191 function.as_guest_function_definition(function_name)
192 }
193
194 pub fn verify_parameters(&self, parameter_types: &[ParameterType]) -> Result<()> {
196 const MAX_PARAMETERS: usize = 11;
198 if parameter_types.len() > MAX_PARAMETERS {
199 return Err(HyperlightGuestError::new(
200 ErrorCode::GuestError,
201 format!(
202 "Function {} has too many parameters: {} (max allowed is {}).",
203 self.function_name,
204 parameter_types.len(),
205 MAX_PARAMETERS
206 ),
207 ));
208 }
209
210 if self.parameter_types.len() != parameter_types.len() {
211 return Err(HyperlightGuestError::new(
212 ErrorCode::GuestFunctionIncorrecNoOfParameters,
213 format!(
214 "Called function {} with {} parameters but it takes {}.",
215 self.function_name,
216 parameter_types.len(),
217 self.parameter_types.len()
218 ),
219 ));
220 }
221
222 for (i, parameter_type) in self.parameter_types.iter().enumerate() {
223 if parameter_type != ¶meter_types[i] {
224 return Err(HyperlightGuestError::new(
225 ErrorCode::GuestFunctionParameterTypeMismatch,
226 format!(
227 "Expected parameter type {:?} for parameter index {} of function {} but got {:?}.",
228 parameter_type, i, self.function_name, parameter_types[i]
229 ),
230 ));
231 }
232 }
233
234 Ok(())
235 }
236}