Skip to content

Commit 137457c

Browse files
authored
Generic guest/host result API (#259)
* Make `get_flatbuffer_result` generic Signed-off-by: Ludvig Liljenberg <lliljenberg@microsoft.com> * Make `get_host_value_return_as` generic Signed-off-by: Ludvig Liljenberg <lliljenberg@microsoft.com> * fix broken rebase Signed-off-by: Ludvig Liljenberg <lliljenberg@microsoft.com> --------- Signed-off-by: Ludvig Liljenberg <lliljenberg@microsoft.com>
1 parent fe18e45 commit 137457c

File tree

5 files changed

+191
-267
lines changed

5 files changed

+191
-267
lines changed

src/hyperlight_common/src/flatbuffer_wrappers/util.rs

Lines changed: 119 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -16,141 +16,156 @@ limitations under the License.
1616

1717
use alloc::vec::Vec;
1818

19-
use flatbuffers::{FlatBufferBuilder, UnionWIPOffset, WIPOffset};
19+
use flatbuffers::FlatBufferBuilder;
2020

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

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

36-
let rt = FbReturnValue::hldouble;
37-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hldouble.as_union_value());
39+
builder.finish_size_prefixed(result_offset, None);
3840

39-
get_flatbuffer_result(&mut builder, rt, rv)
41+
builder.finished_data().to_vec()
4042
}
4143

42-
pub fn get_flatbuffer_result_from_float(value: f32) -> Vec<u8> {
43-
let mut builder = FlatBufferBuilder::new();
44-
let hlfloat = Fbhlfloat::create(&mut builder, &FbhlfloatArgs { value });
45-
46-
let rt = FbReturnValue::hlfloat;
47-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlfloat.as_union_value());
48-
49-
get_flatbuffer_result(&mut builder, rt, rv)
44+
pub trait FlatbufferSerializable {
45+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs;
5046
}
5147

52-
pub fn get_flatbuffer_result_from_int(value: i32) -> Vec<u8> {
53-
let mut builder = FlatBufferBuilder::new();
54-
let hlint = Fbhlint::create(&mut builder, &FbhlintArgs { value });
55-
56-
let rt = FbReturnValue::hlint;
57-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlint.as_union_value());
48+
/// Implementations for basic types below
5849
59-
get_flatbuffer_result(&mut builder, rt, rv)
50+
impl FlatbufferSerializable for () {
51+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
52+
FbFunctionCallResultArgs {
53+
return_value: Some(Fbhlvoid::create(builder, &FbhlvoidArgs {}).as_union_value()),
54+
return_value_type: FbReturnValue::hlvoid,
55+
}
56+
}
6057
}
6158

62-
pub fn get_flatbuffer_result_from_uint(value: u32) -> Vec<u8> {
63-
let mut builder = FlatBufferBuilder::new();
64-
let hluint = Fbhluint::create(&mut builder, &FbhluintArgs { value });
65-
66-
let rt = FbReturnValue::hluint;
67-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hluint.as_union_value());
68-
69-
get_flatbuffer_result(&mut builder, rt, rv)
59+
impl FlatbufferSerializable for &str {
60+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
61+
let string_offset = builder.create_string(self);
62+
FbFunctionCallResultArgs {
63+
return_value: Some(
64+
Fbhlstring::create(
65+
builder,
66+
&FbhlstringArgs {
67+
value: Some(string_offset),
68+
},
69+
)
70+
.as_union_value(),
71+
),
72+
return_value_type: FbReturnValue::hlstring,
73+
}
74+
}
7075
}
7176

72-
pub fn get_flatbuffer_result_from_long(value: i64) -> Vec<u8> {
73-
let mut builder = FlatBufferBuilder::new();
74-
let hllong = Fbhllong::create(&mut builder, &FbhllongArgs { value });
75-
76-
let rt = FbReturnValue::hllong;
77-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hllong.as_union_value());
78-
79-
get_flatbuffer_result(&mut builder, rt, rv)
77+
impl FlatbufferSerializable for &[u8] {
78+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
79+
let vec_offset = builder.create_vector(self);
80+
FbFunctionCallResultArgs {
81+
return_value: Some(
82+
Fbhlsizeprefixedbuffer::create(
83+
builder,
84+
&FbhlsizeprefixedbufferArgs {
85+
size_: self.len() as i32,
86+
value: Some(vec_offset),
87+
},
88+
)
89+
.as_union_value(),
90+
),
91+
return_value_type: FbReturnValue::hlsizeprefixedbuffer,
92+
}
93+
}
8094
}
8195

82-
pub fn get_flatbuffer_result_from_ulong(value: u64) -> Vec<u8> {
83-
let mut builder = FlatBufferBuilder::new();
84-
let hlulong = Fbhlulong::create(&mut builder, &FbhlulongArgs { value });
85-
86-
let rt = FbReturnValue::hlulong;
87-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlulong.as_union_value());
88-
89-
get_flatbuffer_result(&mut builder, rt, rv)
96+
impl FlatbufferSerializable for f32 {
97+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
98+
FbFunctionCallResultArgs {
99+
return_value: Some(
100+
Fbhlfloat::create(builder, &FbhlfloatArgs { value: *self }).as_union_value(),
101+
),
102+
return_value_type: FbReturnValue::hlfloat,
103+
}
104+
}
90105
}
91106

92-
pub fn get_flatbuffer_result_from_void() -> Vec<u8> {
93-
let mut builder = FlatBufferBuilder::new();
94-
let hlvoid = Fbhlvoid::create(&mut builder, &FbhlvoidArgs {});
95-
96-
let rt = FbReturnValue::hlvoid;
97-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlvoid.as_union_value());
98-
99-
get_flatbuffer_result(&mut builder, rt, rv)
107+
impl FlatbufferSerializable for f64 {
108+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
109+
FbFunctionCallResultArgs {
110+
return_value: Some(
111+
Fbhldouble::create(builder, &FbhldoubleArgs { value: *self }).as_union_value(),
112+
),
113+
return_value_type: FbReturnValue::hldouble,
114+
}
115+
}
100116
}
101117

102-
pub fn get_flatbuffer_result_from_string(value: &str) -> Vec<u8> {
103-
let mut builder = FlatBufferBuilder::new();
104-
105-
let string_offset = builder.create_string(value);
106-
let hlstring = Fbhlstring::create(
107-
&mut builder,
108-
&FbhlstringArgs {
109-
value: Some(string_offset),
110-
},
111-
);
112-
113-
let rt = FbReturnValue::hlstring;
114-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlstring.as_union_value());
115-
116-
get_flatbuffer_result(&mut builder, rt, rv)
118+
impl FlatbufferSerializable for i32 {
119+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
120+
FbFunctionCallResultArgs {
121+
return_value: Some(
122+
Fbhlint::create(builder, &FbhlintArgs { value: *self }).as_union_value(),
123+
),
124+
return_value_type: FbReturnValue::hlint,
125+
}
126+
}
117127
}
118128

119-
pub fn get_flatbuffer_result_from_vec(data: &[u8]) -> Vec<u8> {
120-
let mut builder = FlatBufferBuilder::new();
121-
122-
let vec_offset = builder.create_vector(data);
123-
124-
let hlsizeprefixedbuffer = Fbhlsizeprefixedbuffer::create(
125-
&mut builder,
126-
&FbhlsizeprefixedbufferArgs {
127-
size_: data.len() as i32,
128-
value: Some(vec_offset),
129-
},
130-
);
131-
132-
// Indicate that the return value is a size-prefixed buffer.
133-
let rt = FbReturnValue::hlsizeprefixedbuffer;
134-
let rv: Option<WIPOffset<UnionWIPOffset>> = Some(hlsizeprefixedbuffer.as_union_value());
135-
136-
// Get the FlatBuffer result.
137-
get_flatbuffer_result(&mut builder, rt, rv)
129+
impl FlatbufferSerializable for i64 {
130+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
131+
FbFunctionCallResultArgs {
132+
return_value: Some(
133+
Fbhllong::create(builder, &FbhllongArgs { value: *self }).as_union_value(),
134+
),
135+
return_value_type: FbReturnValue::hllong,
136+
}
137+
}
138138
}
139139

140-
fn get_flatbuffer_result(
141-
builder: &mut FlatBufferBuilder,
142-
return_value_type: FbReturnValue,
143-
return_value: Option<WIPOffset<UnionWIPOffset>>,
144-
) -> Vec<u8> {
145-
let result_offset = FbFunctionCallResult::create(
146-
builder,
147-
&FbFunctionCallResultArgs {
148-
return_value,
149-
return_value_type,
150-
},
151-
);
140+
impl FlatbufferSerializable for u32 {
141+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
142+
FbFunctionCallResultArgs {
143+
return_value: Some(
144+
Fbhluint::create(builder, &FbhluintArgs { value: *self }).as_union_value(),
145+
),
146+
return_value_type: FbReturnValue::hluint,
147+
}
148+
}
149+
}
152150

153-
builder.finish_size_prefixed(result_offset, None);
151+
impl FlatbufferSerializable for u64 {
152+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
153+
FbFunctionCallResultArgs {
154+
return_value: Some(
155+
Fbhlulong::create(builder, &FbhlulongArgs { value: *self }).as_union_value(),
156+
),
157+
return_value_type: FbReturnValue::hlulong,
158+
}
159+
}
160+
}
154161

155-
builder.finished_data().to_vec()
162+
impl FlatbufferSerializable for bool {
163+
fn serialize(&self, builder: &mut FlatBufferBuilder) -> FbFunctionCallResultArgs {
164+
FbFunctionCallResultArgs {
165+
return_value: Some(
166+
Fbhlbool::create(builder, &FbhlboolArgs { value: *self }).as_union_value(),
167+
),
168+
return_value_type: FbReturnValue::hlbool,
169+
}
170+
}
156171
}

src/hyperlight_guest/src/host_function_call.rs

Lines changed: 15 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
use alloc::format;
1718
use alloc::string::ToString;
1819
use alloc::vec::Vec;
1920
use core::arch::global_asm;
@@ -23,7 +24,7 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{
2324
ParameterValue, ReturnType, ReturnValue,
2425
};
2526
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
26-
use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result_from_int;
27+
use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result;
2728
use hyperlight_common::mem::RunMode;
2829

2930
use crate::error::{HyperlightGuestError, Result};
@@ -39,94 +40,20 @@ pub enum OutBAction {
3940
Abort = 102,
4041
}
4142

42-
pub fn get_host_value_return_as_void() -> Result<()> {
43+
/// Get a return value from a host function call.
44+
/// This usually requires a host function to be called first using `call_host_function`.
45+
pub fn get_host_return_value<T: TryFrom<ReturnValue>>() -> Result<T> {
4346
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
4447
.expect("Unable to deserialize a return value from host");
45-
if let ReturnValue::Void = return_value {
46-
Ok(())
47-
} else {
48-
Err(HyperlightGuestError::new(
49-
ErrorCode::GuestError,
50-
"Host return value was not void as expected".to_string(),
51-
))
52-
}
53-
}
54-
55-
pub fn get_host_value_return_as_int() -> Result<i32> {
56-
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
57-
.expect("Unable to deserialize return value from host");
58-
59-
// check that return value is an int and return
60-
if let ReturnValue::Int(i) = return_value {
61-
Ok(i)
62-
} else {
63-
Err(HyperlightGuestError::new(
64-
ErrorCode::GuestError,
65-
"Host return value was not an int as expected".to_string(),
66-
))
67-
}
68-
}
69-
70-
pub fn get_host_value_return_as_uint() -> Result<u32> {
71-
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
72-
.expect("Unable to deserialize return value from host");
73-
74-
// check that return value is an int and return
75-
if let ReturnValue::UInt(ui) = return_value {
76-
Ok(ui)
77-
} else {
78-
Err(HyperlightGuestError::new(
79-
ErrorCode::GuestError,
80-
"Host return value was not a uint as expected".to_string(),
81-
))
82-
}
83-
}
84-
85-
pub fn get_host_value_return_as_long() -> Result<i64> {
86-
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
87-
.expect("Unable to deserialize return value from host");
88-
89-
// check that return value is an int and return
90-
if let ReturnValue::Long(l) = return_value {
91-
Ok(l)
92-
} else {
93-
Err(HyperlightGuestError::new(
94-
ErrorCode::GuestError,
95-
"Host return value was not a long as expected".to_string(),
96-
))
97-
}
98-
}
99-
100-
pub fn get_host_value_return_as_ulong() -> Result<u64> {
101-
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
102-
.expect("Unable to deserialize return value from host");
103-
104-
// check that return value is an int and return
105-
if let ReturnValue::ULong(ul) = return_value {
106-
Ok(ul)
107-
} else {
108-
Err(HyperlightGuestError::new(
48+
T::try_from(return_value).map_err(|_| {
49+
HyperlightGuestError::new(
10950
ErrorCode::GuestError,
110-
"Host return value was not a ulong as expected".to_string(),
111-
))
112-
}
113-
}
114-
115-
// TODO: Make this generic, return a Result<T, ErrorCode>
116-
117-
pub fn get_host_value_return_as_vecbytes() -> Result<Vec<u8>> {
118-
let return_value = try_pop_shared_input_data_into::<ReturnValue>()
119-
.expect("Unable to deserialize return value from host");
120-
121-
// check that return value is an Vec<u8> and return
122-
if let ReturnValue::VecBytes(v) = return_value {
123-
Ok(v)
124-
} else {
125-
Err(HyperlightGuestError::new(
126-
ErrorCode::GuestError,
127-
"Host return value was not an VecBytes as expected".to_string(),
128-
))
129-
}
51+
format!(
52+
"Host return value was not a {} as expected",
53+
core::any::type_name::<T>()
54+
),
55+
)
56+
})
13057
}
13158

13259
// TODO: Make this generic, return a Result<T, ErrorCode> this should allow callers to call this function and get the result type they expect
@@ -194,8 +121,8 @@ pub fn print_output_as_guest_function(function_call: &FunctionCall) -> Result<Ve
194121
Some(Vec::from(&[ParameterValue::String(message.to_string())])),
195122
ReturnType::Int,
196123
)?;
197-
let res_i = get_host_value_return_as_int()?;
198-
Ok(get_flatbuffer_result_from_int(res_i))
124+
let res_i = get_host_return_value::<i32>()?;
125+
Ok(get_flatbuffer_result(res_i))
199126
} else {
200127
Err(HyperlightGuestError::new(
201128
ErrorCode::GuestError,

0 commit comments

Comments
 (0)