1use std::marker::PhantomData;
2
3pub use protobuf::{well_known_types::Any, CodedOutputStream, Message, ProtobufEnum};
4
5use crate::{abi::*, types::*};
6
7extern "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
17pub 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
45pub 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 } 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}