wapc_guest/
protocol.rs

1use std::collections::HashMap;
2use std::sync::RwLock;
3
4use once_cell::sync::Lazy;
5
6use crate::errors;
7
8/// [CallResult] is the result for all waPC host and guest calls.
9pub type CallResult = Result<Vec<u8>, Box<dyn std::error::Error + Sync + Send>>;
10
11/// A generic type for the result of waPC operation handlers.
12pub type HandlerResult<T> = Result<T, Box<dyn std::error::Error + Sync + Send>>;
13
14/// The [__guest_call] function is required by waPC guests and should only be called by waPC hosts.
15#[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    // The two buffers have now been initialized
24    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  /// The host's exported __console_log function.
58  pub(crate) fn __console_log(ptr: *const u8, len: usize);
59  /// The host's exported __host_call function.
60  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  /// The host's exported __host_response function.
71  pub(crate) fn __host_response(ptr: *mut u8);
72  /// The host's exported __host_response_len function.
73  pub(crate) fn __host_response_len() -> usize;
74  /// The host's exported __host_error_len function.
75  pub(crate) fn __host_error_len() -> usize;
76  /// The host's exported __host_error function.
77  pub(crate) fn __host_error(ptr: *mut u8);
78  /// The host's exported __guest_response function.
79  pub(crate) fn __guest_response(ptr: *const u8, len: usize);
80  /// The host's exported __guest_error function.
81  pub(crate) fn __guest_error(ptr: *const u8, len: usize);
82  /// The host's exported __guest_request function.
83  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
90/// Register a handler for a waPC operation
91pub fn register_function(name: &str, f: fn(&[u8]) -> CallResult) {
92  REGISTRY.write().unwrap().insert(name.as_bytes().to_vec(), f);
93}
94
95/// The function through which all host calls take place.
96pub 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    // call was not successful
112    #[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    // call succeeded
127    #[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/// Log function that delegates to the host's __console_log function
143#[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}