Rust_wasm/
lib.rs

1#![allow(non_snake_case)]
2#[warn(unused_imports)]
3#[warn(unused_must_use)]
4
5extern crate wasm_bindgen;
6extern crate serde_json;
7
8use js_sys::{Uint8Array, Number};
9use serde::{Serialize, Deserialize};
10use wasm_bindgen::prelude::*;
11mod rs;
12
13#[wasm_bindgen(module = "/src/js/greet.js")]
14extern "C"{
15    type Greet;
16    fn greet(a:&str)-> String;
17    #[wasm_bindgen(constructor)]
18    fn new() -> Greet;
19    #[wasm_bindgen(method,getter)]
20    fn get_number(this: &Greet) -> i32;
21    #[wasm_bindgen(method,setter)]
22    fn set_number(this: &Greet, val: i32);
23    #[wasm_bindgen(method)]
24    fn render(this:&Greet) -> String;
25}
26
27// =================== import js to rust
28#[wasm_bindgen(module = "/src/js/workerTest.js")]
29extern "C"{
30    type workerTest;
31    fn workerTest(a:&str)-> String;
32}
33
34#[wasm_bindgen(module = "/src/render/scene/render.test.js")]
35extern "C"{
36    type RenderTest;
37    fn renderTest(a:&str)-> String;
38    #[wasm_bindgen(constructor)]
39    fn new() -> RenderTest;
40    #[wasm_bindgen(method)]
41    fn render(this:&RenderTest)->String;
42}
43
44#[wasm_bindgen]
45pub fn action(input: &str) -> String {
46    let output = if input == "" {
47        "".to_string()
48    } else {
49        format!("Hello, {}!", input)
50    };
51
52    log!("Wasm in Worker says: {}",&output);
53
54    output
55}
56
57#[wasm_bindgen]
58pub fn wasm_add(num1:i32,num2:i32)-> i32 {
59
60    let output = num1+num2;
61    let greet1 = Greet::new();
62    greet1.set_number(33);
63    log!("render {}", greet1.render());
64    greet(&output.to_string());
65    output
66}
67
68// ================= rust future
69use std::future::Future;
70fn foo() ->impl Future<Output = u8> {
71    async {
72        5
73    }
74}
75
76#[wasm_bindgen]
77pub async fn test() -> u8 {
78   let x = foo().await;
79   x
80}
81
82// ================ thread(弃用,wasm暂时只支持单线程)
83#[wasm_bindgen]
84pub async fn addThreadTest(){
85        let h1 = thread::spawn(move|| async{
86          foo().await
87        });
88        h1.join().unwrap();
89}
90
91
92use std::io::{self, BufRead};
93use std::fs::File;
94use std::{thread};
95#[wasm_bindgen]
96pub fn sum_file_sync(file_path: &str) -> std::result::Result<f64,JsError> {
97    let f = File::open(file_path)?;
98    let reader = io::BufReader::new(f);
99    let mut sum = 0.0;
100    for line in reader.lines() {
101        if let Ok(n) = line?.parse::<f64>() {
102            println!("{}", n);
103            sum += n;
104        }
105    }
106    Ok(sum)
107}
108// =================== js_sys
109#[wasm_bindgen]
110pub fn run() -> u32{
111    let now = js_sys::Date::now();
112    let now_date = js_sys::Date::new(&JsValue::from_f64(now));
113    let x = now_date.get_milliseconds();
114    x
115}
116
117// =================== Promise
118#[wasm_bindgen]
119pub async fn get_from_js() -> Result<JsValue, JsValue> {
120    let promise = js_sys::Promise::resolve(&42.into());
121    let result = wasm_bindgen_futures::JsFuture::from(promise).await?;
122    Ok(result)
123}
124
125#[wasm_bindgen]
126pub async fn my_async_test() -> Result<JsValue, JsValue> {
127    // from & into 互为相反作用
128    let x = Number::from(64);
129    // into 转换必须写明转换类型
130    let y = "str";
131    let z : String = y.into();
132    // Create a promise that is ready on the next tick of the micro  task queue.
133    let promise = js_sys::Promise::resolve(&JsValue::from(32));
134    // Convert that promise into a future and make the test wait on it.
135    let x = wasm_bindgen_futures::JsFuture::from(promise).await?;
136    Ok(x)
137    // 自定义恐慌输出
138    //assert_eq!(x, 32);
139}
140// ===================== closure
141#[wasm_bindgen]
142extern "C"{
143    fn setInterval(closure: &Closure<dyn FnMut()>, millis: u32) -> f64;
144
145    fn clearInterval(token: f64);
146
147    #[wasm_bindgen(js_namespace = console)]
148    fn log(s: &str);
149}
150
151#[wasm_bindgen(module = "/src/js/interval.js")]
152extern "C"{
153    type JSInterval;
154    fn setToken(a:f64)-> f64;
155    #[wasm_bindgen(constructor)]
156    fn new() -> JSInterval;
157    #[wasm_bindgen(method,getter)]
158    fn get_token(this:&JSInterval)->f64;
159    #[wasm_bindgen(method,setter)]
160    fn set_token(this:&JSInterval,millis:f64);
161}
162
163#[wasm_bindgen]
164pub struct Interval {
165    closure: Closure<dyn FnMut()>,
166    token: f64,
167}
168
169impl Interval {
170    pub fn new<F: 'static>(millis: u32, f: F) -> Interval
171    where
172        F: FnMut()
173    {
174        // Construct a new closure.
175        let closure = Closure::new(f);
176
177        // Pass the closure to JS, to run every n milliseconds.
178        let token = setInterval(&closure, millis);
179
180        Interval {  closure , token }
181    }
182
183}
184
185// When the Interval is destroyed, cancel its `setInterval` timer.
186// impl Drop for Interval {
187//     fn drop(&mut self) {
188//         clearInterval(self.token);
189//     }
190// }
191
192// Keep logging "hello" every second until the resulting `Interval` is dropped.
193#[wasm_bindgen]
194pub fn hello() -> Interval {
195    Interval::new(1000, || log("hello"))
196}
197
198// ================== 将生命周期放置在rust中管理
199#[wasm_bindgen]
200pub fn createInterval(val: u32,str:String) -> Interval {
201    let mut count = 0;
202    Interval::new(val, move|| {
203        log(&format!("{}", str));
204        count += 1;
205    })
206}
207
208// #[wasm_bindgen]
209// pub fn createInterval(val: u32,str:String) -> Interval {
210//     let mut count = 0;
211//     let closure = Closure::wrap(Box::new(move || {
212//         log(&format!("{} {}",str,count));
213//         count+=1;
214//     }) as Box<dyn FnMut()>);
215//     //     // Pass the closure to JS, to run every n milliseconds.
216//     let token = setInterval(&closure, val);
217
218//     Interval { closure, token }
219// }
220
221
222#[wasm_bindgen]
223pub struct TestInterval {
224    content: Interval
225}
226
227#[derive(Serialize, Deserialize)]
228pub struct Example {
229    pub token: f64
230}
231
232#[wasm_bindgen]
233impl TestInterval {
234    #[wasm_bindgen(constructor)]
235    pub fn new(val: u32,str:String) -> TestInterval {
236        let content = createInterval(val,str);
237        // let mut jsInterval:Example = jsval.into_serde().unwrap();
238        // jsInterval.token = content.token;
239        setToken(content.token);
240        TestInterval{ content : content }
241    }
242
243    // pub fn cancel(&mut self) {
244    //     self.content.cancel();
245    // }
246
247}
248
249// ====================== websocket
250use wasm_bindgen::JsCast;
251use web_sys::{ErrorEvent, MessageEvent, WebSocket, XmlHttpRequest, ProgressEvent, XmlHttpRequestResponseType, DedicatedWorkerGlobalScope};
252
253
254// macro_rules! log {
255//     ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
256// }
257
258#[wasm_bindgen(start)]
259pub fn start_websocket() -> Result<(), JsValue> {
260    // Connect to an echo server
261    let ws = WebSocket::new("wss://echo.websocket.events")?;
262    // For small binary messages, like CBOR, Arraybuffer is more efficient than Blob handling
263    ws.set_binary_type(web_sys::BinaryType::Arraybuffer);
264    // create callback
265    let cloned_ws = ws.clone();
266    let onmessage_callback = Closure::<dyn FnMut(_)>::new(move |e: MessageEvent| {
267        // Handle difference Text/Binary,...
268        if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
269            log!("message event, received arraybuffer: {:?}", abuf);
270            let array = js_sys::Uint8Array::new(&abuf);
271            let len = array.byte_length() as usize;
272            log!("Arraybuffer received {}bytes: {:?}", len, array.to_vec());
273            // here you can for example use Serde Deserialize decode the message
274            // for demo purposes we switch back to Blob-type and send off another binary message
275            cloned_ws.set_binary_type(web_sys::BinaryType::Blob);
276            match cloned_ws.send_with_u8_array(&vec![5, 6, 7, 8]) {
277                Ok(_) => log!("binary message successfully sent"),
278                Err(err) => log!("error sending message: {:?}", err),
279            }
280        } else if let Ok(blob) = e.data().dyn_into::<web_sys::Blob>() {
281            log!("message event, received blob: {:?}", blob);
282            // better alternative to juggling with FileReader is to use https://crates.io/crates/gloo-file
283            let fr = web_sys::FileReader::new().unwrap();
284            let fr_c = fr.clone();
285            // create onLoadEnd callback
286            let onloadend_cb = Closure::<dyn FnMut(_)>::new(move |_e: web_sys::ProgressEvent| {
287                let array = js_sys::Uint8Array::new(&fr_c.result().unwrap());
288                let len = array.byte_length() as usize;
289                log!("Blob received {}bytes: {:?}", len, array.to_vec());
290                // here you can for example use the received image/png data
291            });
292            fr.set_onloadend(Some(onloadend_cb.as_ref().unchecked_ref()));
293            fr.read_as_array_buffer(&blob).expect("blob not readable");
294            onloadend_cb.forget();
295        } else if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
296            log!("message event, received Text: {:?}", txt);
297        } else {
298            log!("message event, received Unknown: {:?}", e.data());
299        }
300    });
301    // set message event handler on WebSocket
302    ws.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
303    // forget the callback to keep it alive
304    onmessage_callback.forget();
305
306    let onerror_callback = Closure::<dyn FnMut(_)>::new(move |e: ErrorEvent| {
307        log!("error event: {:?}", e);
308    });
309    ws.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
310    onerror_callback.forget();
311
312    let cloned_ws = ws.clone();
313    let onopen_callback = Closure::<dyn FnMut()>::new(move || {
314        log!("socket opened");
315        match cloned_ws.send_with_str("ping") {
316            Ok(_) => log!("message successfully sent"),
317            Err(err) => log!("error sending message: {:?}", err),
318        }
319        // send off binary message
320        match cloned_ws.send_with_u8_array(&vec![0, 1, 2, 3]) {
321            Ok(_) => log!("binary message successfully sent"),
322            Err(err) => log!("error sending message: {:?}", err),
323        }
324    });
325    ws.set_onopen(Some(onopen_callback.as_ref().unchecked_ref()));
326    onopen_callback.forget();
327
328    Ok(())
329}
330
331// ================= 通过字节数组加载图片
332#[wasm_bindgen]
333pub async fn loadImageByUint8Array(bytes: Uint8Array) -> Result<JsValue, JsValue>{
334    let bytes: &Vec<u8> = &bytes.to_vec();
335    let b = rs::image::image::load(bytes,0);
336    let _b =Uint8Array::from(&b[..]).buffer(); 
337    let promise = js_sys::Promise::resolve(&_b.into());
338    let result = wasm_bindgen_futures::JsFuture::from(promise).await?;
339    Ok(result)
340}
341
342// ================= rust内部调用通过u8数组加载图片
343pub async fn loadImageByU8(bytes: &[u8]) -> Result<JsValue, JsValue>{
344    let b = rs::image::image::load(bytes,0);
345    let _b =Uint8Array::from(&b[..]).buffer(); 
346    let promise = js_sys::Promise::resolve(&_b.into());
347    let result = wasm_bindgen_futures::JsFuture::from(promise).await?;
348    Ok(result)
349}
350
351// ================ httprequest by url
352#[wasm_bindgen]
353pub async fn loadTest(url: String,f: js_sys::Function)->Result<XmlHttpRequest,JsValue> {
354    let mut request = rs::xmlHttpRequest::xmlHttpPostRequest::PostRequest::new_from_default();
355    request.set_header(
356        "Authorization".to_string(),
357        "Bearer".to_string(),
358    );
359    workerTest(&url.to_string());
360    renderTest("loadTest");
361    let promise = js_sys::Promise::resolve(&f);
362    let result = wasm_bindgen_futures::JsFuture::from(promise).await?;
363    request.set_request_onload(Some(result));
364    let val = rs::xmlHttpRequest::xmlHttpPostRequest::PostRequest::send(request, &url)?;
365    Ok(val.request)
366}
367
368#[wasm_bindgen]
369pub async fn loadTest1(url: String,f: js_sys::Function)->Result<XmlHttpRequest,JsValue> {
370    let mut request = rs::xmlHttpRequest::xmlHttpPostRequest::PostRequest::new_from_default();
371    request.set_header(
372        "Authorization".to_string(),
373        "Bearer".to_string(),
374    );
375    let jsValue_Url = JsValue::from_str(&url);
376    log!("jsvalue {:?}",&url);
377    let callResult = f.call1(&JsValue::NULL,&jsValue_Url);
378    match callResult {
379        Ok(u)=>{
380            let t = JsValue::js_typeof(&u).as_string().unwrap();
381            log!("ok {:?}",t);
382            request.set_request_onload(Some(u));
383        }
384        Err(v)=>{
385            log!("error");
386            request.set_request_onerror(Some(v));
387        }
388    };
389    let val = rs::xmlHttpRequest::xmlHttpPostRequest::PostRequest::send(request, &url)?;
390    Ok(val.request)
391}
392
393// ============== serde 序列化&&反序列化&&js《-》rust传输数据
394#[derive(Serialize, Deserialize)]
395pub struct Element {
396    name: String,
397    id: String,
398    parent: String,
399}
400
401#[derive(Debug)]
402enum ElementFoo<'a> {
403    Value(&'a str),
404    Nothing,
405}
406
407#[wasm_bindgen]
408pub fn wasmSerde(value:&JsValue) {
409    let element:Element = value.into_serde().unwrap();
410    log(&element.name); 
411}
412
413#[wasm_bindgen]
414pub fn wasmSerde1(value:&JsValue) -> JsValue{
415    let elements:Vec<Element> = value.into_serde().unwrap();
416    let iter = elements.iter();
417    let mut tempStr = String::new();
418    let foos = iter.map(|val|{
419        // let str = String::new();
420        let str = val.id.as_str();
421        tempStr+=str;
422        ElementFoo::Value(str)
423    }).collect::<Vec<ElementFoo>>();
424   let jsStr = JsValue::from_str(&tempStr);
425   jsStr
426}
427
428#[derive(Debug)]
429enum Foo {
430    Value(i32),
431    Nothing,
432}
433
434fn main() {
435    let bar = [1, 2, 3];
436    let foos = bar.iter().map(|&x| Foo::Value(x)).collect::<Vec<Foo>>();
437    println!("{:?}", foos);
438}
439
440
441