hyperlight_host/sandbox/
host_funcs.rs1use std::collections::HashMap;
5use std::io::{IsTerminal, Write};
6
7use hyperlight_common::flatbuffer_wrappers::function_types::{
8 ParameterType, ParameterValue, ReturnType, ReturnValue,
9};
10use hyperlight_common::flatbuffer_wrappers::host_function_definition::HostFunctionDefinition;
11use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails;
12use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
13use tracing::{Span, instrument};
14
15use crate::HyperlightError::HostFunctionNotFound;
16use crate::Result;
17use crate::func::host_functions::TypeErasedHostFunction;
18
19#[derive(Default)]
20pub struct FunctionRegistry {
22 functions_map: HashMap<String, FunctionEntry>,
23}
24
25pub struct HostFunctions(FunctionRegistry);
48
49impl HostFunctions {
50 pub fn empty() -> Self {
60 Self(FunctionRegistry::default())
61 }
62
63 pub(crate) fn into_iter(self) -> impl Iterator<Item = (String, FunctionEntry)> {
64 self.0.functions_map.into_iter()
65 }
66
67 pub(crate) fn into_inner(self) -> FunctionRegistry {
69 self.0
70 }
71
72 pub(crate) fn inner_mut(&mut self) -> &mut FunctionRegistry {
74 &mut self.0
75 }
76
77 pub(crate) fn inner(&self) -> &FunctionRegistry {
79 &self.0
80 }
81}
82
83impl Default for HostFunctions {
84 fn default() -> Self {
96 Self(FunctionRegistry::with_default_host_print())
97 }
98}
99
100impl From<&FunctionRegistry> for HostFunctionDetails {
101 fn from(registry: &FunctionRegistry) -> Self {
102 let host_functions = registry
103 .functions_map
104 .iter()
105 .map(|(name, entry)| HostFunctionDefinition {
106 function_name: name.clone(),
107 parameter_types: Some(entry.parameter_types.to_vec()),
108 return_type: entry.return_type,
109 })
110 .collect();
111
112 HostFunctionDetails {
113 host_functions: Some(host_functions),
114 }
115 }
116}
117
118pub struct FunctionEntry {
119 pub function: TypeErasedHostFunction,
120 pub parameter_types: &'static [ParameterType],
121 pub return_type: ReturnType,
122}
123
124impl FunctionRegistry {
125 #[instrument(skip_all, parent = Span::current(), level = "Trace")]
127 pub(crate) fn register_host_function(&mut self, name: String, func: FunctionEntry) {
128 self.functions_map.insert(name, func);
129 }
130
131 pub(crate) fn function_signature(
133 &self,
134 name: &str,
135 ) -> Option<(&'static [ParameterType], ReturnType)> {
136 self.functions_map
137 .get(name)
138 .map(|entry| (entry.parameter_types, entry.return_type))
139 }
140
141 pub(crate) fn with_default_host_print() -> Self {
144 use crate::func::host_functions::HostFunction;
145 use crate::func::{ParameterTuple, SupportedReturnType};
146
147 let mut registry = Self::default();
148 let hf: HostFunction<i32, (String,)> = default_writer_func.into();
149 let entry = FunctionEntry {
150 function: hf.into(),
151 parameter_types: <(String,)>::TYPE,
152 return_type: <i32 as SupportedReturnType>::TYPE,
153 };
154 registry.register_host_function("HostPrint".to_string(), entry);
155 registry
156 }
157
158 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
164 #[allow(dead_code)]
165 pub(super) fn host_print(&mut self, msg: String) -> Result<i32> {
166 let res = self.call_host_func_impl("HostPrint", vec![ParameterValue::String(msg)])?;
167 res.try_into()
168 .map_err(|_| HostFunctionNotFound("HostPrint".to_string()))
169 }
170 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
178 pub(super) fn call_host_function(
179 &self,
180 name: &str,
181 args: Vec<ParameterValue>,
182 ) -> Result<ReturnValue> {
183 self.call_host_func_impl(name, args)
184 }
185
186 #[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
187 fn call_host_func_impl(&self, name: &str, args: Vec<ParameterValue>) -> Result<ReturnValue> {
188 let FunctionEntry {
189 function,
190 parameter_types: _,
191 return_type: _,
192 } = self
193 .functions_map
194 .get(name)
195 .ok_or_else(|| HostFunctionNotFound(name.to_string()))?;
196
197 crate::metrics::maybe_time_and_emit_host_call(name, || function.call(args))
199 }
200}
201
202#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
204fn default_writer_func(s: String) -> Result<i32> {
205 match std::io::stdout().is_terminal() {
206 false => {
207 print!("{}", s);
208 Ok(s.len() as i32)
209 }
210 true => {
211 let mut stdout = StandardStream::stdout(ColorChoice::Auto);
212 let mut color_spec = ColorSpec::new();
213 color_spec.set_fg(Some(Color::Green));
214 stdout.set_color(&color_spec)?;
215 stdout.write_all(s.as_bytes())?;
216 stdout.reset()?;
217 Ok(s.len() as i32)
218 }
219 }
220}