Skip to content
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

Generic guest/host result API #259

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
223 changes: 119 additions & 104 deletions src/hyperlight_common/src/flatbuffer_wrappers/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,141 +16,156 @@ limitations under the License.

use alloc::vec::Vec;

use flatbuffers::{FlatBufferBuilder, UnionWIPOffset, WIPOffset};
use flatbuffers::FlatBufferBuilder;

use crate::flatbuffers::hyperlight::generated::{
hldouble as Fbhldouble, hldoubleArgs as FbhldoubleArgs, hlfloat as Fbhlfloat,
hlfloatArgs as FbhlfloatArgs, hlint as Fbhlint, hlintArgs as FbhlintArgs, hllong as Fbhllong,
hllongArgs as FbhllongArgs, hlsizeprefixedbuffer as Fbhlsizeprefixedbuffer,
hlbool as Fbhlbool, hlboolArgs as FbhlboolArgs, hldouble as Fbhldouble,
hldoubleArgs as FbhldoubleArgs, hlfloat as Fbhlfloat, hlfloatArgs as FbhlfloatArgs,
hlint as Fbhlint, hlintArgs as FbhlintArgs, hllong as Fbhllong, hllongArgs as FbhllongArgs,
hlsizeprefixedbuffer as Fbhlsizeprefixedbuffer,
hlsizeprefixedbufferArgs as FbhlsizeprefixedbufferArgs, hlstring as Fbhlstring,
hlstringArgs as FbhlstringArgs, hluint as Fbhluint, hluintArgs as FbhluintArgs,
hlulong as Fbhlulong, hlulongArgs as FbhlulongArgs, hlvoid as Fbhlvoid,
hlvoidArgs as FbhlvoidArgs, FunctionCallResult as FbFunctionCallResult,
FunctionCallResultArgs as FbFunctionCallResultArgs, ReturnValue as FbReturnValue,
};

pub fn get_flatbuffer_result_from_double(value: f64) -> Vec<u8> {
/// Flatbuffer-encodes the given value
pub fn get_flatbuffer_result<T: FlatbufferSerializable>(val: T) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hldouble = Fbhldouble::create(&mut builder, &FbhldoubleArgs { value });
let res = &T::serialize(&val, &mut builder);
let result_offset = FbFunctionCallResult::create(&mut builder, res);

let rt = FbReturnValue::hldouble;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hldouble.as_union_value());
builder.finish_size_prefixed(result_offset, None);

get_flatbuffer_result(&mut builder, rt, rv)
builder.finished_data().to_vec()
}

pub fn get_flatbuffer_result_from_float(value: f32) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hlfloat = Fbhlfloat::create(&mut builder, &FbhlfloatArgs { value });

let rt = FbReturnValue::hlfloat;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlfloat.as_union_value());

get_flatbuffer_result(&mut builder, rt, rv)
pub trait FlatbufferSerializable {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs;
}

pub fn get_flatbuffer_result_from_int(value: i32) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hlint = Fbhlint::create(&mut builder, &FbhlintArgs { value });

let rt = FbReturnValue::hlint;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlint.as_union_value());
/// Implementations for basic types below

get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for () {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(Fbhlvoid::create(builder, &FbhlvoidArgs {}).as_union_value()),
return_value_type: FbReturnValue::hlvoid,
}
}
}

pub fn get_flatbuffer_result_from_uint(value: u32) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hluint = Fbhluint::create(&mut builder, &FbhluintArgs { value });

let rt = FbReturnValue::hluint;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hluint.as_union_value());

get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for &str {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
let string_offset = builder.create_string(self);
FbFunctionCallResultArgs {
return_value: Some(
Fbhlstring::create(
builder,
&FbhlstringArgs {
value: Some(string_offset),
},
)
.as_union_value(),
),
return_value_type: FbReturnValue::hlstring,
}
}
}

pub fn get_flatbuffer_result_from_long(value: i64) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hllong = Fbhllong::create(&mut builder, &FbhllongArgs { value });

let rt = FbReturnValue::hllong;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hllong.as_union_value());

get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for &[u8] {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
let vec_offset = builder.create_vector(self);
FbFunctionCallResultArgs {
return_value: Some(
Fbhlsizeprefixedbuffer::create(
builder,
&FbhlsizeprefixedbufferArgs {
size_: self.len() as i32,
value: Some(vec_offset),
},
)
.as_union_value(),
),
return_value_type: FbReturnValue::hlsizeprefixedbuffer,
}
}
}

pub fn get_flatbuffer_result_from_ulong(value: u64) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hlulong = Fbhlulong::create(&mut builder, &FbhlulongArgs { value });

let rt = FbReturnValue::hlulong;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlulong.as_union_value());

get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for f32 {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhlfloat::create(builder, &FbhlfloatArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hlfloat,
}
}
}

pub fn get_flatbuffer_result_from_void() -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let hlvoid = Fbhlvoid::create(&mut builder, &FbhlvoidArgs {});

let rt = FbReturnValue::hlvoid;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlvoid.as_union_value());

get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for f64 {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhldouble::create(builder, &FbhldoubleArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hldouble,
}
}
}

pub fn get_flatbuffer_result_from_string(value: &str) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();

let string_offset = builder.create_string(value);
let hlstring = Fbhlstring::create(
&mut builder,
&FbhlstringArgs {
value: Some(string_offset),
},
);

let rt = FbReturnValue::hlstring;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlstring.as_union_value());

get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for i32 {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhlint::create(builder, &FbhlintArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hlint,
}
}
}

pub fn get_flatbuffer_result_from_vec(data: &[u8]) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();

let vec_offset = builder.create_vector(data);

let hlsizeprefixedbuffer = Fbhlsizeprefixedbuffer::create(
&mut builder,
&FbhlsizeprefixedbufferArgs {
size_: data.len() as i32,
value: Some(vec_offset),
},
);

// Indicate that the return value is a size-prefixed buffer.
let rt = FbReturnValue::hlsizeprefixedbuffer;
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlsizeprefixedbuffer.as_union_value());

// Get the FlatBuffer result.
get_flatbuffer_result(&mut builder, rt, rv)
impl FlatbufferSerializable for i64 {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhllong::create(builder, &FbhllongArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hllong,
}
}
}

fn get_flatbuffer_result(
builder: &mut FlatBufferBuilder,
return_value_type: FbReturnValue,
return_value: Option<WIPOffset<UnionWIPOffset>>,
) -> Vec<u8> {
let result_offset = FbFunctionCallResult::create(
builder,
&FbFunctionCallResultArgs {
return_value,
return_value_type,
},
);
impl FlatbufferSerializable for u32 {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhluint::create(builder, &FbhluintArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hluint,
}
}
}

builder.finish_size_prefixed(result_offset, None);
impl FlatbufferSerializable for u64 {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhlulong::create(builder, &FbhlulongArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hlulong,
}
}
}

builder.finished_data().to_vec()
impl FlatbufferSerializable for bool {
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
FbFunctionCallResultArgs {
return_value: Some(
Fbhlbool::create(builder, &FbhlboolArgs { value: *self }).as_union_value(),
),
return_value_type: FbReturnValue::hluint,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be fbReturnValue::hlbool ?

}
}
}
101 changes: 13 additions & 88 deletions src/hyperlight_guest/src/host_function_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

use alloc::format;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::arch::global_asm;
Expand All @@ -23,7 +24,7 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{
ParameterValue, ReturnType, ReturnValue,
};
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result_from_int;
use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result;
use hyperlight_common::mem::RunMode;

use crate::error::{HyperlightGuestError, Result};
Expand All @@ -39,94 +40,18 @@ pub enum OutBAction {
Abort = 102,
}

pub fn get_host_value_return_as_void() -> Result<()> {
pub fn get_host_value_return_as<T: TryFrom<ReturnValue>>() -> Result<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just call this get_return_value ?

let return_value = try_pop_shared_input_data_into::<ReturnValue>()
.expect("Unable to deserialize a return value from host");
if let ReturnValue::Void = return_value {
Ok(())
} else {
Err(HyperlightGuestError::new(
ErrorCode::GuestError,
"Host return value was not void as expected".to_string(),
))
}
}

pub fn get_host_value_return_as_int() -> Result<i32> {
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
.expect("Unable to deserialize return value from host");

// check that return value is an int and return
if let ReturnValue::Int(i) = return_value {
Ok(i)
} else {
Err(HyperlightGuestError::new(
ErrorCode::GuestError,
"Host return value was not an int as expected".to_string(),
))
}
}

pub fn get_host_value_return_as_uint() -> Result<u32> {
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
.expect("Unable to deserialize return value from host");

// check that return value is an int and return
if let ReturnValue::UInt(ui) = return_value {
Ok(ui)
} else {
Err(HyperlightGuestError::new(
ErrorCode::GuestError,
"Host return value was not a uint as expected".to_string(),
))
}
}

pub fn get_host_value_return_as_long() -> Result<i64> {
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
.expect("Unable to deserialize return value from host");

// check that return value is an int and return
if let ReturnValue::Long(l) = return_value {
Ok(l)
} else {
Err(HyperlightGuestError::new(
ErrorCode::GuestError,
"Host return value was not a long as expected".to_string(),
))
}
}

pub fn get_host_value_return_as_ulong() -> Result<u64> {
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
.expect("Unable to deserialize return value from host");

// check that return value is an int and return
if let ReturnValue::ULong(ul) = return_value {
Ok(ul)
} else {
Err(HyperlightGuestError::new(
T::try_from(return_value).map_err(|_| {
HyperlightGuestError::new(
ErrorCode::GuestError,
"Host return value was not a ulong as expected".to_string(),
))
}
}

// TODO: Make this generic, return a Result<T, ErrorCode>

pub fn get_host_value_return_as_vecbytes() -> Result<Vec<u8>> {
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
.expect("Unable to deserialize return value from host");

// check that return value is an Vec<u8> and return
if let ReturnValue::VecBytes(v) = return_value {
Ok(v)
} else {
Err(HyperlightGuestError::new(
ErrorCode::GuestError,
"Host return value was not an VecBytes as expected".to_string(),
))
}
format!(
"Host return value was not a {} as expected",
core::any::type_name::<T>()
),
)
})
}

// TODO: Make this generic, return a Result<T, ErrorCode> this should allow callers to call this function and get the result type they expect
Expand Down Expand Up @@ -194,8 +119,8 @@ pub fn print_output_as_guest_function(function_call: &FunctionCall) -> Result<Ve
Some(Vec::from(&[ParameterValue::String(message.to_string())])),
ReturnType::Int,
)?;
let res_i = get_host_value_return_as_int()?;
Ok(get_flatbuffer_result_from_int(res_i))
let res_i = get_host_value_return_as::<i32>()?;
Ok(get_flatbuffer_result(res_i))
} else {
Err(HyperlightGuestError::new(
ErrorCode::GuestError,
Expand Down
Loading
Loading