1use std::collections::HashMap;
2use std::sync::RwLock;
3
4use once_cell::sync::Lazy;
5
6use crate::errors;
7
8pub type CallResult = Result<Vec<u8>, Box<dyn std::error::Error + Sync + Send>>;
10
11pub type HandlerResult<T> = Result<T, Box<dyn std::error::Error + Sync + Send>>;
13
14#[allow(unsafe_code)]
16#[no_mangle]
17pub extern "C" fn __guest_call(op_len: i32, req_len: i32) -> i32 {
18 let mut buf: Vec<u8> = Vec::with_capacity(req_len as _);
19 let mut opbuf: Vec<u8> = Vec::with_capacity(op_len as _);
20
21 unsafe {
22 __guest_request(opbuf.as_mut_ptr(), buf.as_mut_ptr());
23 buf.set_len(req_len as usize);
25 opbuf.set_len(op_len as usize);
26 };
27
28 REGISTRY.read().unwrap().get(&opbuf).map_or_else(
29 || {
30 let mut errmsg = b"No handler registered for function ".to_vec();
31 errmsg.append(&mut opbuf);
32 unsafe {
33 __guest_error(errmsg.as_ptr(), errmsg.len());
34 }
35 0
36 },
37 |handler| match handler(&buf) {
38 Ok(result) => {
39 unsafe {
40 __guest_response(result.as_ptr(), result.len());
41 }
42 1
43 }
44 Err(e) => {
45 let errmsg = e.to_string();
46 unsafe {
47 __guest_error(errmsg.as_ptr(), errmsg.len());
48 }
49 0
50 }
51 },
52 )
53}
54
55#[link(wasm_import_module = "wapc")]
56extern "C" {
57 pub(crate) fn __console_log(ptr: *const u8, len: usize);
59 pub(crate) fn __host_call(
61 bd_ptr: *const u8,
62 bd_len: usize,
63 ns_ptr: *const u8,
64 ns_len: usize,
65 op_ptr: *const u8,
66 op_len: usize,
67 ptr: *const u8,
68 len: usize,
69 ) -> usize;
70 pub(crate) fn __host_response(ptr: *mut u8);
72 pub(crate) fn __host_response_len() -> usize;
74 pub(crate) fn __host_error_len() -> usize;
76 pub(crate) fn __host_error(ptr: *mut u8);
78 pub(crate) fn __guest_response(ptr: *const u8, len: usize);
80 pub(crate) fn __guest_error(ptr: *const u8, len: usize);
82 pub(crate) fn __guest_request(op_ptr: *mut u8, ptr: *mut u8);
84}
85
86type HandlerSignature = fn(&[u8]) -> CallResult;
87
88static REGISTRY: Lazy<RwLock<HashMap<Vec<u8>, HandlerSignature>>> = Lazy::new(|| RwLock::new(HashMap::new()));
89
90pub fn register_function(name: &str, f: fn(&[u8]) -> CallResult) {
92 REGISTRY.write().unwrap().insert(name.as_bytes().to_vec(), f);
93}
94
95pub fn host_call(binding: &str, ns: &str, op: &str, msg: &[u8]) -> CallResult {
97 #[allow(unsafe_code)]
98 let callresult = unsafe {
99 __host_call(
100 binding.as_ptr(),
101 binding.len(),
102 ns.as_ptr(),
103 ns.len(),
104 op.as_ptr(),
105 op.len(),
106 msg.as_ptr(),
107 msg.len(),
108 )
109 };
110 if callresult != 1 {
111 #[allow(unsafe_code)]
113 let errlen = unsafe { __host_error_len() };
114
115 let mut buf = Vec::with_capacity(errlen);
116 let retptr = buf.as_mut_ptr();
117
118 #[allow(unsafe_code)]
119 unsafe {
120 __host_error(retptr);
121 buf.set_len(errlen);
122 }
123
124 Err(Box::new(errors::new(errors::ErrorKind::HostError(buf))))
125 } else {
126 #[allow(unsafe_code)]
128 let len = unsafe { __host_response_len() };
129
130 let mut buf = Vec::with_capacity(len);
131 let retptr = buf.as_mut_ptr();
132
133 #[allow(unsafe_code)]
134 unsafe {
135 __host_response(retptr);
136 buf.set_len(len);
137 }
138 Ok(buf)
139 }
140}
141
142#[cold]
144#[inline(never)]
145pub fn console_log(s: &str) {
146 #[allow(unsafe_code)]
147 unsafe {
148 __console_log(s.as_ptr(), s.len());
149 }
150}