1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
pub use holochain_wasmer_common::allocation;
pub use holochain_wasmer_common::bytes;
pub use holochain_wasmer_common::json;
pub use holochain_wasmer_common::*;

#[macro_export]
macro_rules! memory_externs {
    () => {
        extern "C" {
            // memory stuff
            fn __import_allocation(
                guest_allocation_ptr: AllocationPtr,
                host_allocation_ptr: AllocationPtr,
            );
            fn __import_bytes(host_allocation_ptr: AllocationPtr, guest_bytes_ptr: Ptr);
        }
    };
}
memory_externs!();

#[macro_export]
macro_rules! host_externs {
    ( $( $func_name:ident ),* ) => {
        extern "C" {
            $( fn $func_name(guest_allocation_ptr: $crate::AllocationPtr) -> $crate::AllocationPtr; )*
        }
    };
}

/// given a pointer to an allocation on the host, copy the allocation into the guest and return the
/// guest's pointer to it
pub fn map_bytes(host_allocation_ptr: Ptr) -> AllocationPtr {
    let tmp_allocation_ptr = allocation::allocate(allocation::ALLOCATION_BYTES_ITEMS as Len);
    unsafe {
        __import_allocation(tmp_allocation_ptr, host_allocation_ptr);
    };
    // this allocation has the correct length but host bytes ptr
    let [_, len] = allocation::from_allocation_ptr(tmp_allocation_ptr);
    allocation::deallocate(tmp_allocation_ptr, len);
    let guest_bytes_ptr = allocation::allocate(len);
    unsafe {
        __import_bytes(host_allocation_ptr, guest_bytes_ptr);
    };
    allocation::to_allocation_ptr([guest_bytes_ptr, len])
}

#[macro_export]
/// given a host allocation pointer and a type that implements TryFrom<JsonString>
/// - map bytes from the host into the guest
/// - restore a JsonString from the mapped bytes
/// - try to deserialize the given type from the restored JsonString
/// - if the deserialization fails, short circuit (return early) with a WasmError
/// - if everything is Ok, return the restored data as a native rust type inside the guest
macro_rules! host_args {
    ( $ptr:ident ) => {{
        use core::convert::TryInto;

        match $crate::json::from_allocation_ptr(holochain_wasmer_guest::map_bytes($ptr)).try_into()
        {
            Ok(v) => v,
            Err(_) => {
                $crate::allocation::deallocate_from_allocation_ptr($ptr);
                return $crate::json::to_allocation_ptr(
                    $crate::result::WasmResult::Err(
                        $crate::result::WasmError::ArgumentDeserializationFailed,
                    )
                    .into(),
                );
            }
        }
    }};
}

#[macro_export]
macro_rules! host_bytes {
    ( $ptr:ident ) => {{
        $crate::bytes::from_allocation_ptr($crate::map_bytes($ptr))
    }};
}

#[macro_export]
macro_rules! host_call_bytes {
    ( $func_name:ident, $input:expr ) => {{
        let result_host_allocation_ptr =
            unsafe { $func_name($crate::bytes::to_allocation_ptr($input)) };
        $crate::host_bytes!(result_host_allocation_ptr)
    }};
}

#[macro_export]
macro_rules! host_call {
    ( $func_name:ident, $input:expr ) => {{
        use core::convert::TryInto;
        let json: $crate::JsonString = $input.into();
        let bytes = json.to_bytes();
        let result_bytes = $crate::host_call_bytes!($func_name, bytes);
        $crate::JsonString::from_bytes(result_bytes).try_into()
    }};
}

#[macro_export]
macro_rules! ret {
    ( $e: expr) => {{
        let json_string: $crate::JsonString = ($e).into();
        return $crate::json::to_allocation_ptr($crate::WasmResult::Ok(json_string).into());
    }};
}

#[macro_export]
macro_rules! ret_err {
    ( $fail:literal ) => {{
        return $crate::json::to_allocation_ptr(
            $crate::WasmResult::Err($crate::WasmError::Zome($fail.into())).into(),
        );
    }};
}

#[macro_export]
macro_rules! try_result {
    ( $e:expr, $fail:literal ) => {{
        match $e {
            Ok(v) => v,
            Err(_) => $crate::ret_err!($fail),
        }
    }};
}