1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! This is an experimental implementation of a web-based async runtime. Web as
//! in "browser".
//!
//! Ideally, with this crate, the only JavaScript code you'll need to write
//! would be something like this:
//!
//! ```javascript
//! import * as wasm from "my-wasm-crate";
//! import * as style from "./style.css";
//!
//! wasm.main();
//! ```
//!
//! That's it (ignoring webpack configuration file, of course).
//!
//! # Examples
//!
//! ## Asynchronous "Is Prime" Test
//!
//! I know this is not the best example, because primality test is CPU-bound,
//! but I wanted to show an example of CPU-bound tasks running fast in WASM
//! without blocking the browser, i.e. by pausing periodically and giving
//! control back to browser by a few milliseconds.
//!
//! The full example can be seen in `examples/isprime` directory.
//!
//! A few numbers to try: `7399329281`, `2199023255551`, `9410454606139`,
//! `64954802446103`, `340845657750593`, `576460752303423487`,
//! `2305843009213693951`.
//!
//! ```no_run
//! use std::time::Duration;
//! use num::{BigUint, Zero};
//! use wasm_bindgen::JsValue;
//! use webio::event::{self, EventType};
//!
//! /// Number of steps before yielding control back to browser when testing
//! /// whether a number is prime or not, in order not to freeze the browser with
//! /// computations on large numbers. Of course, yielding back to the browser is
//! /// just a pause, so after a few milliseconds later, WASM can resume its job on
//! /// the current number.
//! ///
//! /// However, note that this applies only when a number is being tested,
//! /// otherwise WASM sleeps and won't wake up until the button is pressed.
//! const YIELD_STEPS: u16 = 20000;
//!
//! /// Tests if the given number is prime, asynchronous because it will pause the
//! /// execution after some steps.
//! async fn is_prime(number: &BigUint) -> bool {
//!     let two = BigUint::from(2u8);
//!     if *number < two {
//!         return false;
//!     }
//!     if *number == two {
//!         return true;
//!     }
//!     if (number % &two).is_zero() {
//!         return false;
//!     }
//!     let mut attempt = BigUint::from(3u8);
//!     let mut square = &attempt * &attempt;
//!
//!     while square <= *number {
//!         if (number % &attempt).is_zero() {
//!             return false;
//!         }
//!         if (&attempt / &two % YIELD_STEPS).is_zero() {
//!             webio::time::timeout(Duration::from_millis(10)).await;
//!         }
//!         attempt += &two;
//!         square = &attempt * &attempt;
//!     }
//!
//!     true
//! }
//!
//! /// Main function of this WASM application.
//! #[webio::main]
//! pub async fn app_main() {
//!     // Gets all necessary HTML elements.
//!     let document = web_sys::window().unwrap().document().unwrap();
//!     let input_raw = document.get_element_by_id("input").unwrap();
//!     let input = web_sys::HtmlInputElement::from(JsValue::from(input_raw));
//!     let button = document.get_element_by_id("button").unwrap();
//!     let answer_elem = document.get_element_by_id("answer").unwrap();
//!
//!     // Sets a listener for the click event on the button.
//!     let listener = event::Click.add_listener(&button);
//!
//!     loop {
//!         // No problem being an infinite loop because it is asynchronous.
//!         // It won't block the browser.
//!         //
//!         // This will sleep until the user press a button.
//!         listener.listen_next().await.unwrap();
//!
//!         // Cleans up previous message.
//!         answer_elem.set_text_content(Some("Loading..."));
//!         // Gets and validates input.
//!         let number: BigUint = match input.value().parse() {
//!             Ok(number) => number,
//!             Err(_) => {
//!                 answer_elem.set_text_content(Some("Invalid input!"));
//!                 continue;
//!             },
//!         };
//!
//!         // Runs and tells the user the correct answer.
//!         if is_prime(&number).await {
//!             answer_elem.set_text_content(Some("Yes"));
//!         } else {
//!             answer_elem.set_text_content(Some("No"));
//!         }
//!     }
//! }
//! ```

#![warn(missing_docs)]
#![cfg_attr(feature = "feature-doc-cfg", feature(doc_cfg))]

#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
extern crate self as webio;

#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use console_error_panic_hook::set_once as set_test_panic_hook;

#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use webio_macros::{console, join, main, select, test, try_join};

#[cfg(all(feature = "macros", feature = "event"))]
#[cfg_attr(
    feature = "feature-doc-cfg",
    doc(cfg(all(feature = "macros", feature = "event")))
)]
pub use webio_macros::EventType;

#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use js_sys;
#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use wasm_bindgen;
#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use wasm_bindgen_futures;
#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use wasm_bindgen_test;
#[doc(hidden)]
#[cfg(feature = "macros")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "macros")))]
pub use web_sys;

#[macro_use]
mod macros;

pub mod task;

pub mod callback;

pub mod sync;

#[cfg(feature = "time")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "time")))]
pub mod time;

#[cfg(feature = "event")]
#[cfg_attr(feature = "feature-doc-cfg", doc(cfg(feature = "event")))]
pub mod event;