wasm_message_passing_3nweb/wasm_mp1.rs
1// Copyright(c) 2021 3NSoft Inc.
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU Lesser General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16//! This module provide rust implementation for WASM module to talk with the
17//! outside according to version 1 of 3nweb's message passing api (should be
18//! called abi?).
19//!
20//! Process of this message passing version is following.
21//!
22//! - To send messages outside, WASM uses imported `_3nweb_mp1_send_out_msg`
23//! during which call embeddder must read message from identified memory area.
24//!
25//! - To send messages inside, embedder uses exported from WASM
26//! `_3nweb_mp1_accept_msg`. During this call, WASM calls back embedder's
27//! imported `_3nweb_mp1_write_msg_into`, where embedder actually copies data
28//! into provided memory area.
29//!
30
31mod internals {
32
33 use wasm_bindgen::prelude::*;
34
35 /// Sends given binary message to the outside. This is implementation.
36 ///
37 pub fn send_msg_out(msg: &Vec<u8>) -> () {
38 unsafe {
39 _3nweb_mp1_send_out_msg(msg.as_ptr() as usize, msg.len());
40 }
41 }
42
43 #[allow(dead_code)]
44 static mut MSG_PROCESSOR: Option<&dyn Fn(Vec<u8>) -> ()> = None;
45
46 /// Sets a message `processor` function/closure that will be called with
47 /// binary messages from the outside. This is implementation.
48 ///
49 /// Messages are given to `processor` as `Vec<u8>` completely separated from
50 /// workings of message exchange buffer(s).
51 ///
52 pub fn set_msg_processor(processor: &'static dyn Fn(Vec<u8>) -> ()) -> () {
53 unsafe {
54 MSG_PROCESSOR = Some(processor);
55 }
56 }
57
58 /// This simple classic externing expects to find these functions in `env`
59 /// object/namespace imported to WASM by embedding.
60 ///
61 extern {
62
63 /// Don't use this directly.
64 /// WASM embedding is expected to provide this function in accordance with
65 /// 3nweb's message passing api, version 1, indicated be `_3nweb_mp1_`
66 /// prefix in the name.
67 ///
68 /// This function is called to tell embedding that a message for the
69 /// outside with length `len` can be copied from given pointer `ptr`.
70 ///
71 /// Embedder provides this callback in `env` namespace of imports.
72 ///
73 fn _3nweb_mp1_send_out_msg(ptr: usize, len: usize);
74
75 /// Don't use this directly.
76 /// WASM embedding is expected to provide this function in accordance with
77 /// 3nweb's message passing api, version 1, indicated be `_3nweb_mp1_`
78 /// prefix in the name.
79 ///
80 /// This function is a callback invoked during passing message into WASM.
81 /// Embedding calls exported `_3nweb_mp1_accept_msg`, which itself
82 /// prepairs memory for message, and calls this imported function so that
83 /// embedding writes its message into the buffer.
84 ///
85 /// Embedder provides this callback in `env` namespace of imports.
86 ///
87 fn _3nweb_mp1_write_msg_into(ptr: usize);
88
89 }
90
91 /// Don't use this directly.
92 /// This function is exported from WASM in accordance with 3nweb's message
93 /// passing api, version 1, indicated be `_3nweb_mp1_` prefix in the name.
94 ///
95 /// This is called by WASM embedding with `len` size of the message.
96 /// Implementation prepares buffer for writing message bytes and calls back
97 /// imported `_3nweb_mp1_write_msg_into`. When callback returns, message is
98 /// given to processor.
99 ///
100 #[wasm_bindgen]
101 pub fn _3nweb_mp1_accept_msg(len: usize) -> () {
102 let mut msg = Vec::with_capacity(len);
103 unsafe {
104 _3nweb_mp1_write_msg_into(msg.as_ptr() as usize);
105 msg.set_len(len);
106 if MSG_PROCESSOR.is_some() {
107 (MSG_PROCESSOR.as_ref().unwrap())(msg);
108 }
109 }
110 }
111
112}
113
114/// Sends given binary message to the outside.
115///
116#[inline]
117pub fn send_msg_out(msg: &Vec<u8>) -> () {
118 internals::send_msg_out(msg);
119}
120
121/// Sets a message `processor` function/closure that will be called with binary
122/// messages from the outside.
123///
124/// Messages are given to `processor` as `Vec<u8>` completely separated from
125/// workings of message exchange buffer(s).
126///
127#[inline]
128pub fn set_msg_processor(processor: &'static dyn Fn(Vec<u8>) -> ()) -> () {
129 internals::set_msg_processor(processor);
130}