wasmy_abi/
wasm.rs

1use std::marker::PhantomData;
2
3pub use protobuf::{well_known_types::Any, CodedOutputStream, Message, ProtobufEnum};
4
5use crate::{abi::*, types::*};
6
7// The ABI interaction functions of the virtual machine.
8extern "C" {
9    pub(crate) fn _wasmy_vm_recall(is_ctx: i32, offset: i32);
10    pub(crate) fn _wasmy_vm_restore(offset: i32, size: i32);
11    pub(crate) fn _wasmy_vm_invoke(offset: i32, size: i32) -> i32;
12}
13
14const NON_CTX: i32 = 0;
15const IS_CTX: i32 = 1;
16
17/// The underlying function of wasm to handle requests.
18pub fn wasm_handle<F, W, Value>(ctx_size: i32, args_size: i32, handle: F)
19where
20    F: Fn(W, InArgs) -> Result<Any>,
21    W: WasmContext<Value>,
22    Value: Message,
23{
24    if args_size <= 0 {
25        return;
26    }
27    let mut buffer = vec![0u8; args_size as usize];
28    unsafe { _wasmy_vm_recall(NON_CTX, buffer.as_ptr() as i32) };
29    let res: OutRets = match InArgs::parse_from_bytes(&buffer) {
30        Ok(args) => handle(W::from_size(ctx_size as usize), args).into(),
31        Err(err) => CodeMsg::new(CODE_PROTO, err).into(),
32    };
33    let size = res.compute_size() as usize;
34    if size > buffer.capacity() {
35        buffer.resize(size, 0);
36    } else {
37        unsafe { buffer.set_len(size) };
38    }
39    let mut os = CodedOutputStream::bytes(&mut buffer);
40    res.write_to_with_cached_sizes(&mut os).unwrap();
41    os.flush().unwrap();
42    unsafe { _wasmy_vm_restore(buffer.as_ptr() as i32, buffer.len() as i32) };
43}
44
45/// WasmContext is wasm context abstraction.
46pub trait WasmContext<Value: Message = Empty> {
47    fn from_size(size: usize) -> Self;
48    fn size(&self) -> usize;
49    fn try_value(&self) -> Result<Value> {
50        if self.size() == 0 {
51            CodeMsg::result(CODE_NONE, "the value of the context is not passed")
52            // Ok(C::new())
53        } else {
54            let buffer = vec![0u8; self.size()];
55            unsafe { _wasmy_vm_recall(IS_CTX, buffer.as_ptr() as i32) };
56            match Value::parse_from_bytes(&buffer) {
57                Ok(ctx) => Ok(ctx),
58                Err(err) => CodeMsg::result(CODE_PROTO, err),
59            }
60        }
61    }
62    fn call_vm<M: Message, R: Message>(&self, method: VmMethod, data: M) -> Result<R> {
63        let args = InArgs::try_new(method, data)?;
64        let mut buffer = args.write_to_bytes().unwrap();
65        let size = unsafe { _wasmy_vm_invoke(buffer.as_ptr() as i32, buffer.len() as i32) };
66        if size <= 0 {
67            return Ok(R::new());
68        }
69        buffer.resize(size as usize, 0);
70        unsafe { _wasmy_vm_recall(NON_CTX, buffer.as_ptr() as i32) };
71        OutRets::parse_from_bytes(buffer.as_slice())?.into()
72    }
73}
74
75impl<Value: Message> WasmContext<Value> for WasmCtx<Value> {
76    fn from_size(size: usize) -> Self {
77        Self { size, _priv: PhantomData }
78    }
79    fn size(&self) -> usize {
80        self.size
81    }
82}