Skip to content

Bring back HostFunctionDefinitions Region #600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
Copyright 2025 The Hyperlight Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

use alloc::string::{String, ToString};
use alloc::vec::Vec;

use anyhow::{Error, Result, anyhow};
use flatbuffers::{FlatBufferBuilder, WIPOffset};
#[cfg(feature = "tracing")]
use tracing::{Span, instrument};

use super::function_types::{ParameterType, ReturnType};
use crate::flatbuffers::hyperlight::generated::{
HostFunctionDefinition as FbHostFunctionDefinition,
HostFunctionDefinitionArgs as FbHostFunctionDefinitionArgs, ParameterType as FbParameterType,
};

/// The definition of a function exposed from the host to the guest
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct HostFunctionDefinition {
/// The function name
pub function_name: String,
/// The type of the parameter values for the host function call.
pub parameter_types: Option<Vec<ParameterType>>,
/// The type of the return value from the host function call
pub return_type: ReturnType,
}

impl HostFunctionDefinition {
/// Create a new `HostFunctionDefinition`.
#[cfg_attr(feature = "tracing", instrument(skip_all, parent = Span::current(), level= "Trace"))]
pub fn new(
function_name: String,
parameter_types: Option<Vec<ParameterType>>,
return_type: ReturnType,
) -> Self {
Self {
function_name,
parameter_types,
return_type,
}
}

/// Convert this `HostFunctionDefinition` into a `WIPOffset<FbHostFunctionDefinition>`.
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
pub(crate) fn convert_to_flatbuffer_def<'a>(
&self,
builder: &mut FlatBufferBuilder<'a>,
) -> Result<WIPOffset<FbHostFunctionDefinition<'a>>> {
let host_function_name = builder.create_string(&self.function_name);
let return_value_type = self.return_type.into();
let vec_parameters = match &self.parameter_types {
Some(vec_pvt) => {
let num_items = vec_pvt.len();
let mut parameters: Vec<FbParameterType> = Vec::with_capacity(num_items);
for pvt in vec_pvt {
let fb_pvt = pvt.clone().into();
parameters.push(fb_pvt);
}
Some(builder.create_vector(&parameters))
}
None => None,
};

let fb_host_function_definition: WIPOffset<FbHostFunctionDefinition> =
FbHostFunctionDefinition::create(
builder,
&FbHostFunctionDefinitionArgs {
function_name: Some(host_function_name),
return_type: return_value_type,
parameters: vec_parameters,
},
);

Ok(fb_host_function_definition)
}

/// Verify that the function call has the correct parameter types.
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
pub fn verify_equal_parameter_types(
&self,
function_call_parameter_types: &[ParameterType],
) -> Result<()> {
if let Some(parameter_types) = &self.parameter_types {
for (i, parameter_type) in parameter_types.iter().enumerate() {
if parameter_type != &function_call_parameter_types[i] {
return Err(anyhow!("Incorrect parameter type for parameter {}", i + 1));
}
}
}
Ok(())
}
}

impl TryFrom<&FbHostFunctionDefinition<'_>> for HostFunctionDefinition {
type Error = Error;
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
fn try_from(value: &FbHostFunctionDefinition) -> Result<Self> {
let function_name = value.function_name().to_string();
let return_type = value.return_type().try_into().map_err(|_| {
anyhow!(
"Failed to convert return type for function {}",
function_name
)
})?;
let parameter_types = match value.parameters() {
Some(pvt) => {
let len = pvt.len();
let mut pv: Vec<ParameterType> = Vec::with_capacity(len);
for fb_pvt in pvt {
let pvt: ParameterType = fb_pvt.try_into().map_err(|_| {
anyhow!(
"Failed to convert parameter type for function {}",
function_name
)
})?;
pv.push(pvt);
}
Some(pv)
}
None => None,
};

Ok(Self::new(function_name, parameter_types, return_type))
}
}

impl TryFrom<&[u8]> for HostFunctionDefinition {
type Error = Error;
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
fn try_from(value: &[u8]) -> Result<Self> {
let fb_host_function_definition = flatbuffers::root::<FbHostFunctionDefinition<'_>>(value)
.map_err(|e| anyhow!("Error while reading HostFunctionDefinition: {:?}", e))?;
Self::try_from(&fb_host_function_definition)
}
}

impl TryFrom<&HostFunctionDefinition> for Vec<u8> {
type Error = Error;
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
fn try_from(hfd: &HostFunctionDefinition) -> Result<Vec<u8>> {
let mut builder = flatbuffers::FlatBufferBuilder::new();
let host_function_definition = hfd.convert_to_flatbuffer_def(&mut builder)?;
builder.finish_size_prefixed(host_function_definition, None);
Ok(builder.finished_data().to_vec())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
Copyright 2025 The Hyperlight Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

use alloc::vec::Vec;

use anyhow::{Error, Result};
use flatbuffers::{WIPOffset, size_prefixed_root};
#[cfg(feature = "tracing")]
use tracing::{Span, instrument};

use super::host_function_definition::HostFunctionDefinition;
use crate::flatbuffers::hyperlight::generated::{
HostFunctionDefinition as FbHostFunctionDefinition,
HostFunctionDetails as FbHostFunctionDetails,
HostFunctionDetailsArgs as FbHostFunctionDetailsArgs,
};

/// `HostFunctionDetails` represents the set of functions that the host exposes to the guest.
#[derive(Debug, Default, Clone)]
pub struct HostFunctionDetails {
/// The host functions.
pub host_functions: Option<Vec<HostFunctionDefinition>>,
}

impl TryFrom<&[u8]> for HostFunctionDetails {
type Error = Error;
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
fn try_from(value: &[u8]) -> Result<Self> {
let host_function_details_fb = size_prefixed_root::<FbHostFunctionDetails>(value)
.map_err(|e| anyhow::anyhow!("Error while reading HostFunctionDetails: {:?}", e))?;

let host_function_definitions = match host_function_details_fb.functions() {
Some(hfd) => {
let len = hfd.len();
let mut vec_hfd: Vec<HostFunctionDefinition> = Vec::with_capacity(len);
for i in 0..len {
let fb_host_function_definition = hfd.get(i);
let hfdef = HostFunctionDefinition::try_from(&fb_host_function_definition)?;
vec_hfd.push(hfdef);
}

Some(vec_hfd)
}

None => None,
};

Ok(Self {
host_functions: host_function_definitions,
})
}
}

impl TryFrom<&HostFunctionDetails> for Vec<u8> {
type Error = Error;
#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
fn try_from(value: &HostFunctionDetails) -> Result<Vec<u8>> {
let mut builder = flatbuffers::FlatBufferBuilder::new();
let vec_host_function_definitions = match &value.host_functions {
Some(vec_hfd) => {
let num_items = vec_hfd.len();
let mut host_function_definitions: Vec<WIPOffset<FbHostFunctionDefinition>> =
Vec::with_capacity(num_items);

for hfd in vec_hfd {
let host_function_definition = hfd.convert_to_flatbuffer_def(&mut builder)?;
host_function_definitions.push(host_function_definition);
}

Some(host_function_definitions)
}
None => None,
};

let fb_host_function_definitions =
vec_host_function_definitions.map(|v| builder.create_vector(&v));

let host_function_details = FbHostFunctionDetails::create(
&mut builder,
&FbHostFunctionDetailsArgs {
functions: fb_host_function_definitions,
},
);
builder.finish_size_prefixed(host_function_details, None);
let res = builder.finished_data().to_vec();

Ok(res)
}
}
4 changes: 4 additions & 0 deletions src/hyperlight_common/src/flatbuffer_wrappers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ pub mod guest_error;
pub mod guest_log_data;
/// cbindgen:ignore
pub mod guest_log_level;
/// cbindgen:ignore
pub mod host_function_definition;
/// cbindgen:ignore
pub mod host_function_details;
pub mod util;
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,16 @@ impl<'a> flatbuffers::Follow<'a> for ErrorCode {
type Inner = Self;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe {
let b = flatbuffers::read_scalar_at::<u64>(buf, loc);
Self(b)
}
let b = flatbuffers::read_scalar_at::<u64>(buf, loc);
Self(b)
}
}

impl flatbuffers::Push for ErrorCode {
type Output = ErrorCode;
#[inline]
unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
unsafe {
flatbuffers::emplace_scalar::<u64>(dst, self.0);
}
flatbuffers::emplace_scalar::<u64>(dst, self.0);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCall<'a> {
type Inner = FunctionCall<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe {
Self {
_tab: flatbuffers::Table::new(buf, loc),
}
Self {
_tab: flatbuffers::Table::new(buf, loc),
}
}
}
Expand Down Expand Up @@ -292,14 +290,14 @@ pub fn size_prefixed_root_as_function_call_with_opts<'b, 'o>(
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `FunctionCall`.
pub unsafe fn root_as_function_call_unchecked(buf: &[u8]) -> FunctionCall {
unsafe { flatbuffers::root_unchecked::<FunctionCall>(buf) }
flatbuffers::root_unchecked::<FunctionCall>(buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed FunctionCall and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `FunctionCall`.
pub unsafe fn size_prefixed_root_as_function_call_unchecked(buf: &[u8]) -> FunctionCall {
unsafe { flatbuffers::size_prefixed_root_unchecked::<FunctionCall>(buf) }
flatbuffers::size_prefixed_root_unchecked::<FunctionCall>(buf)
}
#[inline]
pub fn finish_function_call_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCallResult<'a> {
type Inner = FunctionCallResult<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe {
Self {
_tab: flatbuffers::Table::new(buf, loc),
}
Self {
_tab: flatbuffers::Table::new(buf, loc),
}
}
}
Expand Down Expand Up @@ -515,7 +513,7 @@ pub fn size_prefixed_root_as_function_call_result_with_opts<'b, 'o>(
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `FunctionCallResult`.
pub unsafe fn root_as_function_call_result_unchecked(buf: &[u8]) -> FunctionCallResult {
unsafe { flatbuffers::root_unchecked::<FunctionCallResult>(buf) }
flatbuffers::root_unchecked::<FunctionCallResult>(buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed FunctionCallResult and returns it.
Expand All @@ -524,7 +522,7 @@ pub unsafe fn root_as_function_call_result_unchecked(buf: &[u8]) -> FunctionCall
pub unsafe fn size_prefixed_root_as_function_call_result_unchecked(
buf: &[u8],
) -> FunctionCallResult {
unsafe { flatbuffers::size_prefixed_root_unchecked::<FunctionCallResult>(buf) }
flatbuffers::size_prefixed_root_unchecked::<FunctionCallResult>(buf)
}
#[inline]
pub fn finish_function_call_result_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,16 @@ impl<'a> flatbuffers::Follow<'a> for FunctionCallType {
type Inner = Self;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe {
let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
Self(b)
}
let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
Self(b)
}
}

impl flatbuffers::Push for FunctionCallType {
type Output = FunctionCallType;
#[inline]
unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
unsafe {
flatbuffers::emplace_scalar::<u8>(dst, self.0);
}
flatbuffers::emplace_scalar::<u8>(dst, self.0);
}
}

Expand Down
Loading
Loading