pub mod allocation;
pub extern crate holochain_serialized_bytes;
pub use holochain_wasmer_common::*;
use crate::allocation::consume_bytes;
use crate::allocation::write_bytes;
pub use paste::paste;
#[macro_export]
macro_rules! host_externs {
( $( $func_name:ident:$version:literal ),* ) => {
$crate::paste! {
#[no_mangle]
extern "C" {
$( pub fn [<__hc__ $func_name _ $version>](guest_allocation_ptr: usize, len: usize) -> $crate::DoubleUSize; )*
}
}
};
}
#[inline(always)]
pub fn host_args<O>(ptr: usize, len: usize) -> Result<O, DoubleUSize>
where
O: serde::de::DeserializeOwned + std::fmt::Debug,
{
let bytes = consume_bytes(ptr, len);
match holochain_serialized_bytes::decode(&bytes) {
Ok(v) => Ok(v),
Err(e) => {
tracing::error!(input_type = std::any::type_name::<O>(), bytes = ?bytes, "{}", e);
Err(return_err_ptr(wasm_error!(WasmErrorInner::Deserialize(
bytes
))))
}
}
}
#[inline(always)]
pub fn host_call<I, O>(
f: unsafe extern "C" fn(usize, usize) -> DoubleUSize,
input: I,
) -> Result<O, crate::WasmError>
where
I: serde::Serialize + std::fmt::Debug,
O: serde::de::DeserializeOwned + std::fmt::Debug,
{
let input_bytes = holochain_serialized_bytes::encode(&input).map_err(|e| wasm_error!(e))?;
let input_len: usize = input_bytes.len();
let input_guest_ptr = crate::allocation::write_bytes(input_bytes);
let (output_guest_ptr, output_len): (usize, usize) = split_usize(unsafe {
f(input_guest_ptr, input_len)
})?;
let bytes = crate::allocation::consume_bytes(output_guest_ptr, output_len);
match holochain_serialized_bytes::decode::<[u8], Result<O, WasmError>>(&bytes) {
Ok(output) => Ok(output?),
Err(e) => {
tracing::error!(output_type = std::any::type_name::<O>(), ?bytes, "{}", e);
Err(wasm_error!(WasmErrorInner::Deserialize(bytes)))
}
}
}
#[inline(always)]
pub fn return_ptr<R>(return_value: R) -> DoubleUSize
where
R: Serialize + std::fmt::Debug,
{
match holochain_serialized_bytes::encode::<Result<R, WasmError>>(&Ok(return_value)) {
Ok(bytes) => {
let len: usize = bytes.len();
match merge_usize(write_bytes(bytes), len) {
Ok(v) => v,
Err(e) => return_err_ptr(e),
}
}
Err(e) => return_err_ptr(wasm_error!(WasmErrorInner::Serialize(e))),
}
}
#[inline(always)]
pub fn return_err_ptr(wasm_error: WasmError) -> DoubleUSize {
let bytes = match holochain_serialized_bytes::encode::<Result<(), WasmError>>(&Err(wasm_error))
{
Ok(bytes) => bytes,
Err(e) => match holochain_serialized_bytes::encode::<Result<(), WasmError>>(&Err(
wasm_error!(WasmErrorInner::Serialize(e)),
)) {
Ok(bytes) => bytes,
Err(_) => match holochain_serialized_bytes::encode::<Result<(), WasmError>>(&Err(
wasm_error!(WasmErrorInner::ErrorWhileError),
)) {
Ok(bytes) => bytes,
Err(_) => panic!("Failed to error"),
},
},
};
let len = bytes.len();
merge_usize(write_bytes(bytes), len).expect("Failed to build return value")
}
#[macro_export]
macro_rules! try_ptr {
( $e:expr, $fail:expr ) => {{
match $e {
Ok(v) => v,
Err(e) => return return_err_ptr(wasm_error!("{}: {:?}", $fail, e)),
}
}};
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn wasm_error_macro_guest() {
assert_eq!(
wasm_error!("foo").error,
WasmErrorInner::Guest("foo".into()),
);
assert_eq!(
wasm_error!("{} {}", "foo", "bar").error,
WasmErrorInner::Guest("foo bar".into())
);
assert_eq!(
wasm_error!(WasmErrorInner::Host("foo".into())).error,
WasmErrorInner::Host("foo".into()),
);
}
}