Skip to content
Draft
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
36 changes: 35 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/hyperlight_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Hyperlight's components common to host and guest.
workspace = true

[dependencies]
flatbuffers = { version = "25.12.19", default-features = false }
postcard = { version = "1.1.3", default-features = false, features = ["alloc"] }
serde = { version = "1.0.228", default-features = false, features = ["derive", "alloc"] }
anyhow = { version = "1.0.100", default-features = false }
log = "0.4.29"
tracing = { version = "0.1.44", optional = true }
Expand Down
220 changes: 21 additions & 199 deletions src/hyperlight_common/src/flatbuffer_wrappers/function_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

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

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

use super::function_types::{ParameterValue, ReturnType};
use crate::flatbuffers::hyperlight::generated::{
FunctionCall as FbFunctionCall, FunctionCallArgs as FbFunctionCallArgs,
FunctionCallType as FbFunctionCallType, Parameter, ParameterArgs,
ParameterValue as FbParameterValue, hlbool, hlboolArgs, hldouble, hldoubleArgs, hlfloat,
hlfloatArgs, hlint, hlintArgs, hllong, hllongArgs, hlstring, hlstringArgs, hluint, hluintArgs,
hlulong, hlulongArgs, hlvecbytes, hlvecbytesArgs,
};
use crate::flatbuffer_wrappers::util::decode;

/// The type of function call.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FunctionCallType {
/// The function call is to a guest function.
Guest,
Expand All @@ -41,7 +35,7 @@ pub enum FunctionCallType {
}

/// `Functioncall` represents a call to a function in the guest or host.
#[derive(Clone)]
#[derive(Clone, Serialize, Deserialize)]
pub struct FunctionCall {
/// The function name
pub function_name: String,
Expand Down Expand Up @@ -72,154 +66,14 @@ impl FunctionCall {
pub fn function_call_type(&self) -> FunctionCallType {
self.function_call_type.clone()
}

/// Encodes self into the given builder and returns the encoded data.
///
/// # Notes
///
/// The builder should not be reused after a call to encode, since this function
/// does not reset the state of the builder. If you want to reuse the builder,
/// you'll need to reset it first.
pub fn encode<'a>(&self, builder: &'a mut FlatBufferBuilder) -> &'a [u8] {
let function_name = builder.create_string(&self.function_name);

let function_call_type = match self.function_call_type {
FunctionCallType::Guest => FbFunctionCallType::guest,
FunctionCallType::Host => FbFunctionCallType::host,
};

let expected_return_type = self.expected_return_type.into();

let parameters = match &self.parameters {
Some(p) if !p.is_empty() => {
let parameter_offsets: Vec<WIPOffset<Parameter>> = p
.iter()
.map(|param| match param {
ParameterValue::Int(i) => {
let hlint = hlint::create(builder, &hlintArgs { value: *i });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hlint,
value: Some(hlint.as_union_value()),
},
)
}
ParameterValue::UInt(ui) => {
let hluint = hluint::create(builder, &hluintArgs { value: *ui });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hluint,
value: Some(hluint.as_union_value()),
},
)
}
ParameterValue::Long(l) => {
let hllong = hllong::create(builder, &hllongArgs { value: *l });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hllong,
value: Some(hllong.as_union_value()),
},
)
}
ParameterValue::ULong(ul) => {
let hlulong = hlulong::create(builder, &hlulongArgs { value: *ul });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hlulong,
value: Some(hlulong.as_union_value()),
},
)
}
ParameterValue::Float(f) => {
let hlfloat = hlfloat::create(builder, &hlfloatArgs { value: *f });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hlfloat,
value: Some(hlfloat.as_union_value()),
},
)
}
ParameterValue::Double(d) => {
let hldouble = hldouble::create(builder, &hldoubleArgs { value: *d });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hldouble,
value: Some(hldouble.as_union_value()),
},
)
}
ParameterValue::Bool(b) => {
let hlbool = hlbool::create(builder, &hlboolArgs { value: *b });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hlbool,
value: Some(hlbool.as_union_value()),
},
)
}
ParameterValue::String(s) => {
let val = builder.create_string(s.as_str());
let hlstring =
hlstring::create(builder, &hlstringArgs { value: Some(val) });
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hlstring,
value: Some(hlstring.as_union_value()),
},
)
}
ParameterValue::VecBytes(v) => {
let vec_bytes = builder.create_vector(v);
let hlvecbytes = hlvecbytes::create(
builder,
&hlvecbytesArgs {
value: Some(vec_bytes),
},
);
Parameter::create(
builder,
&ParameterArgs {
value_type: FbParameterValue::hlvecbytes,
value: Some(hlvecbytes.as_union_value()),
},
)
}
})
.collect();
Some(builder.create_vector(&parameter_offsets))
}
_ => None,
};

let function_call = FbFunctionCall::create(
builder,
&FbFunctionCallArgs {
function_name: Some(function_name),
parameters,
function_call_type,
expected_return_type,
},
);
builder.finish_size_prefixed(function_call, None);
builder.finished_data()
}
}

#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
let guest_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
match guest_function_call_fb.function_call_type() {
FbFunctionCallType::guest => Ok(()),
let guest_function_call: FunctionCall =
decode(function_call_buffer).context("Error reading function call buffer")?;
match guest_function_call.function_call_type {
FunctionCallType::Guest => Ok(()),
other => {
bail!("Invalid function call type: {:?}", other);
}
Expand All @@ -228,61 +82,28 @@ pub fn validate_guest_function_call_buffer(function_call_buffer: &[u8]) -> Resul

#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
pub fn validate_host_function_call_buffer(function_call_buffer: &[u8]) -> Result<()> {
let host_function_call_fb = size_prefixed_root::<FbFunctionCall>(function_call_buffer)
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
match host_function_call_fb.function_call_type() {
FbFunctionCallType::host => Ok(()),
let host_function_call: FunctionCall =
decode(function_call_buffer).context("Error reading function call buffer")?;
match host_function_call.function_call_type {
FunctionCallType::Host => Ok(()),
other => {
bail!("Invalid function call type: {:?}", other);
}
}
}

impl TryFrom<&[u8]> for FunctionCall {
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 function_call_fb = size_prefixed_root::<FbFunctionCall>(value)
.map_err(|e| anyhow::anyhow!("Error reading function call buffer: {:?}", e))?;
let function_name = function_call_fb.function_name();
let function_call_type = match function_call_fb.function_call_type() {
FbFunctionCallType::guest => FunctionCallType::Guest,
FbFunctionCallType::host => FunctionCallType::Host,
other => {
bail!("Invalid function call type: {:?}", other);
}
};
let expected_return_type = function_call_fb.expected_return_type().try_into()?;

let parameters = function_call_fb
.parameters()
.map(|v| {
v.iter()
.map(|p| p.try_into())
.collect::<Result<Vec<ParameterValue>>>()
})
.transpose()?;

Ok(Self {
function_name: function_name.to_string(),
parameters,
function_call_type,
expected_return_type,
})
}
}

#[cfg(test)]
mod tests {
use alloc::string::ToString;
use alloc::vec;

use super::*;
use crate::flatbuffer_wrappers::function_types::ReturnType;
use crate::flatbuffer_wrappers::util::encode;

#[test]
fn read_from_flatbuffer() -> Result<()> {
let mut builder = FlatBufferBuilder::new();
let test_data = FunctionCall::new(
let value = FunctionCall::new(
"PrintTwelveArgs".to_string(),
Some(vec![
ParameterValue::String("1".to_string()),
Expand All @@ -300,10 +121,11 @@ mod tests {
]),
FunctionCallType::Guest,
ReturnType::Int,
)
.encode(&mut builder);
);

let test_data = encode(&value)?;

let function_call = FunctionCall::try_from(test_data)?;
let function_call: FunctionCall = decode(&test_data)?;
assert_eq!(function_call.function_name, "PrintTwelveArgs");
assert!(function_call.parameters.is_some());
let parameters = function_call.parameters.unwrap();
Expand Down
Loading