1use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6
7use anyhow::{Error, Result, bail};
8use flatbuffers::{FlatBufferBuilder, WIPOffset, size_prefixed_root};
9#[cfg(feature = "tracing")]
10use tracing::{Span, instrument};
11
12use super::function_types::{ParameterValue, ReturnType};
13use crate::flatbuffers::hyperlight::generated::{
14 FunctionCall as FbFunctionCall, FunctionCallArgs as FbFunctionCallArgs,
15 FunctionCallType as FbFunctionCallType, Parameter, ParameterArgs,
16 ParameterValue as FbParameterValue, hlbool, hlboolArgs, hldouble, hldoubleArgs, hlfloat,
17 hlfloatArgs, hlint, hlintArgs, hllong, hllongArgs, hlstring, hlstringArgs, hluint, hluintArgs,
18 hlulong, hlulongArgs, hlvecbytes, hlvecbytesArgs,
19};
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum FunctionCallType {
24 Guest,
26 Host,
28}
29
30#[derive(Clone)]
32pub struct FunctionCall {
33 pub function_name: String,
35 pub parameters: Option<Vec<ParameterValue>>,
37 function_call_type: FunctionCallType,
38 pub expected_return_type: ReturnType,
40}
41
42impl FunctionCall {
43 #[cfg_attr(feature = "tracing", instrument(skip_all, parent = Span::current(), level= "Trace"))]
44 pub fn new(
45 function_name: String,
46 parameters: Option<Vec<ParameterValue>>,
47 function_call_type: FunctionCallType,
48 expected_return_type: ReturnType,
49 ) -> Self {
50 Self {
51 function_name,
52 parameters,
53 function_call_type,
54 expected_return_type,
55 }
56 }
57
58 pub fn function_call_type(&self) -> FunctionCallType {
60 self.function_call_type.clone()
61 }
62
63 pub fn encode<'a>(&self, builder: &'a mut FlatBufferBuilder) -> &'a [u8] {
71 let function_name = builder.create_string(&self.function_name);
72
73 let function_call_type = match self.function_call_type {
74 FunctionCallType::Guest => FbFunctionCallType::guest,
75 FunctionCallType::Host => FbFunctionCallType::host,
76 };
77
78 let expected_return_type = self.expected_return_type.into();
79
80 let parameters = match &self.parameters {
81 Some(p) if !p.is_empty() => {
82 let parameter_offsets: Vec<WIPOffset<Parameter>> = p
83 .iter()
84 .map(|param| match param {
85 ParameterValue::Int(i) => {
86 let hlint = hlint::create(builder, &hlintArgs { value: *i });
87 Parameter::create(
88 builder,
89 &ParameterArgs {
90 value_type: FbParameterValue::hlint,
91 value: Some(hlint.as_union_value()),
92 },
93 )
94 }
95 ParameterValue::UInt(ui) => {
96 let hluint = hluint::create(builder, &hluintArgs { value: *ui });
97 Parameter::create(
98 builder,
99 &ParameterArgs {
100 value_type: FbParameterValue::hluint,
101 value: Some(hluint.as_union_value()),
102 },
103 )
104 }
105 ParameterValue::Long(l) => {
106 let hllong = hllong::create(builder, &hllongArgs { value: *l });
107 Parameter::create(
108 builder,
109 &ParameterArgs {
110 value_type: FbParameterValue::hllong,
111 value: Some(hllong.as_union_value()),
112 },
113 )
114 }
115 ParameterValue::ULong(ul) => {
116 let hlulong = hlulong::create(builder, &hlulongArgs { value: *ul });
117 Parameter::create(
118 builder,
119 &ParameterArgs {
120 value_type: FbParameterValue::hlulong,
121 value: Some(hlulong.as_union_value()),
122 },
123 )
124 }
125 ParameterValue::Float(f) => {
126 let hlfloat = hlfloat::create(builder, &hlfloatArgs { value: *f });
127 Parameter::create(
128 builder,
129 &ParameterArgs {
130 value_type: FbParameterValue::hlfloat,
131 value: Some(hlfloat.as_union_value()),
132 },
133 )
134 }
135 ParameterValue::Double(d) => {
136 let hldouble = hldouble::create(builder, &hldoubleArgs { value: *d });
137 Parameter::create(
138 builder,
139 &ParameterArgs {
140 value_type: FbParameterValue::hldouble,
141 value: Some(hldouble.as_union_value()),
142 },
143 )
144 }
145 ParameterValue::Bool(b) => {
146 let hlbool = hlbool::create(builder, &hlboolArgs { value: *b });
147 Parameter::create(
148 builder,
149 &ParameterArgs {
150 value_type: FbParameterValue::hlbool,
151 value: Some(hlbool.as_union_value()),
152 },
153 )
154 }
155 ParameterValue::String(s) => {
156 let val = builder.create_string(s.as_str());
157 let hlstring =
158 hlstring::create(builder, &hlstringArgs { value: Some(val) });
159 Parameter::create(
160 builder,
161 &ParameterArgs {
162 value_type: FbParameterValue::hlstring,
163 value: Some(hlstring.as_union_value()),
164 },
165 )
166 }
167 ParameterValue::VecBytes(v) => {
168 let vec_bytes = builder.create_vector(v);
169 let hlvecbytes = hlvecbytes::create(
170 builder,
171 &hlvecbytesArgs {
172 value: Some(vec_bytes),
173 },
174 );
175 Parameter::create(
176 builder,
177 &ParameterArgs {
178 value_type: FbParameterValue::hlvecbytes,
179 value: Some(hlvecbytes.as_union_value()),
180 },
181 )
182 }
183 })
184 .collect();
185 Some(builder.create_vector(¶meter_offsets))
186 }
187 _ => None,
188 };
189
190 let function_call = FbFunctionCall::create(
191 builder,
192 &FbFunctionCallArgs {
193 function_name: Some(function_name),
194 parameters,
195 function_call_type,
196 expected_return_type,
197 },
198 );
199 builder.finish_size_prefixed(function_call, None);
200 builder.finished_data()
201 }
202}
203
204#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
205pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
206 let guest_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
207 .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
208 match guest_function_call_fb.function_call_type() {
209 FbFunctionCallType::guest => Ok(()),
210 other => {
211 bail!("Invalid function call type: {:?}", other);
212 }
213 }
214}
215
216#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
217pub fn validate_host_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
218 let host_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
219 .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
220 match host_function_call_fb.function_call_type() {
221 FbFunctionCallType::host => Ok(()),
222 other => {
223 bail!("Invalid function call type: {:?}", other);
224 }
225 }
226}
227
228impl TryFrom<&[u8]> for FunctionCall {
229 type Error = Error;
230 #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
231 fn try_from(value: &[u8]) -> Result<Self> {
232 let function_call_fb = size_prefixed_root::<FbFunctionCall>(value)
233 .map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
234 let function_name = function_call_fb.function_name();
235 let function_call_type = match function_call_fb.function_call_type() {
236 FbFunctionCallType::guest => FunctionCallType::Guest,
237 FbFunctionCallType::host => FunctionCallType::Host,
238 other => {
239 bail!("Invalid function call type: {:?}", other);
240 }
241 };
242 let expected_return_type = function_call_fb.expected_return_type().try_into()?;
243
244 let parameters = function_call_fb
245 .parameters()
246 .map(|v| {
247 v.iter()
248 .map(|p| p.try_into())
249 .collect::<Result<Vec<ParameterValue>>>()
250 })
251 .transpose()?;
252
253 Ok(Self {
254 function_name: function_name.to_string(),
255 parameters,
256 function_call_type,
257 expected_return_type,
258 })
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use alloc::vec;
265
266 use super::*;
267 use crate::flatbuffer_wrappers::function_types::ReturnType;
268
269 #[test]
270 fn read_from_flatbuffer() -> Result<()> {
271 let mut builder = FlatBufferBuilder::new();
272 let test_data = FunctionCall::new(
273 "PrintTwelveArgs".to_string(),
274 Some(vec![
275 ParameterValue::String("1".to_string()),
276 ParameterValue::Int(2),
277 ParameterValue::Long(3),
278 ParameterValue::String("4".to_string()),
279 ParameterValue::String("5".to_string()),
280 ParameterValue::Bool(true),
281 ParameterValue::Bool(false),
282 ParameterValue::UInt(8),
283 ParameterValue::ULong(9),
284 ParameterValue::Int(10),
285 ParameterValue::Float(3.123),
286 ParameterValue::Double(0.01),
287 ]),
288 FunctionCallType::Guest,
289 ReturnType::Int,
290 )
291 .encode(&mut builder);
292
293 let function_call = FunctionCall::try_from(test_data)?;
294 assert_eq!(function_call.function_name, "PrintTwelveArgs");
295 assert!(function_call.parameters.is_some());
296 let parameters = function_call.parameters.unwrap();
297 assert_eq!(parameters.len(), 12);
298 let expected_parameters = vec![
299 ParameterValue::String("1".to_string()),
300 ParameterValue::Int(2),
301 ParameterValue::Long(3),
302 ParameterValue::String("4".to_string()),
303 ParameterValue::String("5".to_string()),
304 ParameterValue::Bool(true),
305 ParameterValue::Bool(false),
306 ParameterValue::UInt(8),
307 ParameterValue::ULong(9),
308 ParameterValue::Int(10),
309 ParameterValue::Float(3.123),
310 ParameterValue::Double(0.01),
311 ];
312 assert!(expected_parameters == parameters);
313 assert_eq!(function_call.function_call_type, FunctionCallType::Guest);
314
315 Ok(())
316 }
317}