Skip to main content

hyperlight_common/flatbuffer_wrappers/
host_function_definition.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025 The Hyperlight Authors.
3
4use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6
7use anyhow::{Error, Result, anyhow};
8use flatbuffers::{FlatBufferBuilder, WIPOffset};
9#[cfg(feature = "tracing")]
10use tracing::{Span, instrument};
11
12use super::function_types::{ParameterType, ReturnType};
13use crate::flatbuffers::hyperlight::generated::{
14    HostFunctionDefinition as FbHostFunctionDefinition,
15    HostFunctionDefinitionArgs as FbHostFunctionDefinitionArgs, ParameterType as FbParameterType,
16};
17
18/// The definition of a function exposed from the host to the guest
19#[derive(Debug, Default, Clone, PartialEq, Eq)]
20pub struct HostFunctionDefinition {
21    /// The function name
22    pub function_name: String,
23    /// The type of the parameter values for the host function call.
24    pub parameter_types: Option<Vec<ParameterType>>,
25    /// The type of the return value from the host function call
26    pub return_type: ReturnType,
27}
28
29impl HostFunctionDefinition {
30    /// Create a new `HostFunctionDefinition`.
31    #[cfg_attr(feature = "tracing", instrument(skip_all, parent = Span::current(), level= "Trace"))]
32    pub fn new(
33        function_name: String,
34        parameter_types: Option<Vec<ParameterType>>,
35        return_type: ReturnType,
36    ) -> Self {
37        Self {
38            function_name,
39            parameter_types,
40            return_type,
41        }
42    }
43
44    /// Convert this `HostFunctionDefinition` into a `WIPOffset<FbHostFunctionDefinition>`.
45    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
46    pub(crate) fn convert_to_flatbuffer_def<'a>(
47        &self,
48        builder: &mut FlatBufferBuilder<'a>,
49    ) -> Result<WIPOffset<FbHostFunctionDefinition<'a>>> {
50        let host_function_name = builder.create_string(&self.function_name);
51        let return_value_type = self.return_type.into();
52        let vec_parameters = match &self.parameter_types {
53            Some(vec_pvt) => {
54                let num_items = vec_pvt.len();
55                let mut parameters: Vec<FbParameterType> = Vec::with_capacity(num_items);
56                for pvt in vec_pvt {
57                    let fb_pvt = pvt.clone().into();
58                    parameters.push(fb_pvt);
59                }
60                Some(builder.create_vector(&parameters))
61            }
62            None => None,
63        };
64
65        let fb_host_function_definition: WIPOffset<FbHostFunctionDefinition> =
66            FbHostFunctionDefinition::create(
67                builder,
68                &FbHostFunctionDefinitionArgs {
69                    function_name: Some(host_function_name),
70                    return_type: return_value_type,
71                    parameters: vec_parameters,
72                },
73            );
74
75        Ok(fb_host_function_definition)
76    }
77
78    /// Verify that the function call has the correct parameter types.
79    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
80    pub fn verify_equal_parameter_types(
81        &self,
82        function_call_parameter_types: &[ParameterType],
83    ) -> Result<()> {
84        if let Some(parameter_types) = &self.parameter_types {
85            for (i, parameter_type) in parameter_types.iter().enumerate() {
86                if parameter_type != &function_call_parameter_types[i] {
87                    return Err(anyhow!("Incorrect parameter type for parameter {}", i + 1));
88                }
89            }
90        }
91        Ok(())
92    }
93}
94
95impl TryFrom<&FbHostFunctionDefinition<'_>> for HostFunctionDefinition {
96    type Error = Error;
97    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
98    fn try_from(value: &FbHostFunctionDefinition) -> Result<Self> {
99        let function_name = value.function_name().to_string();
100        let return_type = value.return_type().try_into().map_err(|_| {
101            anyhow!(
102                "Failed to convert return type for function {}",
103                function_name
104            )
105        })?;
106        let parameter_types = match value.parameters() {
107            Some(pvt) => {
108                let len = pvt.len();
109                let mut pv: Vec<ParameterType> = Vec::with_capacity(len);
110                for fb_pvt in pvt {
111                    let pvt: ParameterType = fb_pvt.try_into().map_err(|_| {
112                        anyhow!(
113                            "Failed to convert parameter type for function {}",
114                            function_name
115                        )
116                    })?;
117                    pv.push(pvt);
118                }
119                Some(pv)
120            }
121            None => None,
122        };
123
124        Ok(Self::new(function_name, parameter_types, return_type))
125    }
126}
127
128impl TryFrom<&[u8]> for HostFunctionDefinition {
129    type Error = Error;
130    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
131    fn try_from(value: &[u8]) -> Result<Self> {
132        let fb_host_function_definition = flatbuffers::root::<FbHostFunctionDefinition<'_>>(value)
133            .map_err(|e| anyhow!("Error while reading HostFunctionDefinition: {:?}", e))?;
134        Self::try_from(&fb_host_function_definition)
135    }
136}
137
138impl TryFrom<&HostFunctionDefinition> for Vec<u8> {
139    type Error = Error;
140    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
141    fn try_from(hfd: &HostFunctionDefinition) -> Result<Vec<u8>> {
142        let mut builder = flatbuffers::FlatBufferBuilder::new();
143        let host_function_definition = hfd.convert_to_flatbuffer_def(&mut builder)?;
144        builder.finish_size_prefixed(host_function_definition, None);
145        Ok(builder.finished_data().to_vec())
146    }
147}