Skip to content

Commit 736ff0e

Browse files
authored
Add wasm feature (#16)
♻️ refactor(examples/wasm):更新.gitignore,移除index.js文件,修改index.html结构,添加注释到lib.rs并重构结构体名 ✨ feat(examples/wasm): 在Cargo.toml中为button-driver添加wasm特性,简化lib.rs代码并修改Instant实现 ✨ feat: 在Cargo.toml中添加js-sys依赖;在src/instant.rs中为js_sys::Date实现InstantProvider trait ✨ feat(.github/workflows/rust.yml):添加Clippy wasm检查、rustup添加wasm32-unknown-unknown目标及wasm示例构建步骤 💡 feat(examples/wasm/src/lib.rs):添加注释说明使用`JsInstant`类型,更新依赖并替换`Date`为`JsInstant` ✨ feat: 在src/instant.rs中添加JsInstant结构体及相关实现,在src/lib.rs中导出JsInstant 💡 docs: 在src/instant.rs中添加JsInstant的注释说明
1 parent fb75747 commit 736ff0e

File tree

9 files changed

+345
-1
lines changed

9 files changed

+345
-1
lines changed

.github/workflows/rust.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,25 @@ jobs:
2727
run: |
2828
cargo clippy --features embedded_hal -- -D warnings
2929
cargo clippy --features embedded_hal_old -- -D warnings
30+
- name: Clippy wasm
31+
run: cargo clippy --features wasm -- -D warnings
3032
- name: Clippy default
3133
run: cargo clippy --no-default-features -- -D warnings
3234

3335
- name: Install dependencies
34-
run: rustup target add thumbv7m-none-eabi
36+
run: |
37+
rustup target add thumbv7m-none-eabi
38+
rustup target add wasm32-unknown-unknown
3539
3640
- name: Clippy example stm32
3741
working-directory: examples/stm32
3842
run: cargo clippy -- -D warnings
3943
- name: Clippy example stm32-embassy
4044
working-directory: examples/stm32-embassy
4145
run: cargo clippy -- -D warnings
46+
- name: Build example wasm
47+
working-directory: examples/wasm
48+
run: cargo build --target wasm32-unknown-unknown --release
4249

4350
- name: Tests
4451
run: cargo test tests --features std

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ features = ["std"]
2020
embassy-time = { version = "0.5.0", optional = true }
2121
embedded-hal-old = { package = "embedded-hal", version = "0.2.7", optional = true }
2222
embedded-hal = { version = "1.0.0", optional = true }
23+
js-sys = { version = "0.3", optional = true }
2324

2425
[dev-dependencies]
2526
parking_lot = "0.12.4"
@@ -31,3 +32,4 @@ embedded_hal_old = ["dep:embedded-hal-old", "embedded-hal-old/unproven"]
3132
esp = ["dep:embedded-hal"]
3233
embedded_hal = ["dep:embedded-hal"]
3334
std = []
35+
wasm = ["dep:js-sys", "std"]

examples/wasm/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
/dist

examples/wasm/Cargo.lock

Lines changed: 164 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/wasm/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "wasm"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
wasm-bindgen = { version = "0.2" }
8+
web-sys = { version = "0.3.69", features = ["Window", "Document", "Element", "MouseEvent"] }
9+
button-driver = { path = "../../", features = ["wasm"] }
10+
log = "0.4.22"
11+
wasm-logger = "0.2.0"
12+
13+
[lib]
14+
path = "src/lib.rs"
15+
crate-type = ["cdylib"]
16+
17+
[features]

examples/wasm/index.html

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8" />
4+
<title>Button example</title>
5+
<style>
6+
.clickable-area {
7+
display: flex;
8+
justify-content: center;
9+
align-items: center;
10+
width: 200px;
11+
height: 100px;
12+
}
13+
</style>
14+
</head>
15+
<body>
16+
<button class="clickable-area" type="button">Button</button>
17+
<br>
18+
<p>
19+
Please open developer tools console to view log.
20+
</p>
21+
</body>
22+
</html>

examples/wasm/src/lib.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//! A WebAssembly example demonstrating button driver usage in the browser.
2+
//! This example uses the built-in `JsInstant` type which wraps `js_sys::Date::now()`.
3+
//!
4+
//! To run this example:
5+
//! 1. Install trunk: `cargo install trunk`
6+
//! 2. Run: `trunk serve`
7+
//! 3. Open your browser at `http://localhost:8080`
8+
//!
9+
//! Required features: `wasm` (which includes `std` and `js-sys`).
10+
11+
use std::{cell::RefCell, rc::Rc};
12+
13+
use button_driver::{Button, ButtonConfig, JsInstant, Mode, PinWrapper};
14+
use log::info;
15+
use wasm_bindgen::{closure::Closure, JsCast};
16+
use web_sys::MouseEvent;
17+
18+
#[derive(Clone, Default)]
19+
struct ButtonInput(Rc<RefCell<bool>>);
20+
21+
impl PinWrapper for ButtonInput {
22+
fn is_high(&mut self) -> bool {
23+
*self.0.borrow()
24+
}
25+
}
26+
27+
#[wasm_bindgen::prelude::wasm_bindgen(start)]
28+
pub fn main() {
29+
wasm_logger::init(wasm_logger::Config::default());
30+
let document = web_sys::window().unwrap().document().unwrap();
31+
let clickable_area = document.query_selector(".clickable-area").unwrap().unwrap();
32+
let pin_state = ButtonInput::default();
33+
{
34+
let pin_state_ref = pin_state.clone();
35+
let mouse_down_handler = Closure::wrap(Box::new(move |_: MouseEvent| {
36+
*pin_state_ref.0.borrow_mut() = true;
37+
}) as Box<dyn FnMut(_)>);
38+
clickable_area
39+
.add_event_listener_with_callback(
40+
"mousedown",
41+
mouse_down_handler.as_ref().unchecked_ref(),
42+
)
43+
.unwrap();
44+
mouse_down_handler.forget();
45+
}
46+
{
47+
let pin_state_ref = pin_state.clone();
48+
let mouse_up_handler = Closure::wrap(Box::new(move |_: MouseEvent| {
49+
*pin_state_ref.0.borrow_mut() = false;
50+
}) as Box<dyn FnMut(_)>);
51+
52+
clickable_area
53+
.add_event_listener_with_callback("mouseup", mouse_up_handler.as_ref().unchecked_ref())
54+
.unwrap();
55+
mouse_up_handler.forget();
56+
}
57+
{
58+
let mut button = Button::<_, JsInstant>::new(
59+
pin_state,
60+
ButtonConfig {
61+
mode: Mode::PullDown,
62+
..Default::default()
63+
},
64+
);
65+
let callback = Closure::wrap(Box::new(move || {
66+
button.tick();
67+
68+
if let Some(dur) = button.held_time() {
69+
info!("Total holding time {:?}", dur);
70+
if button.is_clicked() {
71+
info!("Clicked + held");
72+
} else if button.is_double_clicked() {
73+
info!("Double clicked + held");
74+
} else if button.holds() == 2 && button.clicks() > 0 {
75+
info!("Held twice with {} clicks", button.clicks());
76+
} else if button.holds() == 2 {
77+
info!("Held twice");
78+
}
79+
} else {
80+
if button.is_clicked() {
81+
info!("Click");
82+
} else if button.is_double_clicked() {
83+
info!("Double click");
84+
} else if button.is_triple_clicked() {
85+
info!("Triple click");
86+
} else if let Some(dur) = button.current_holding_time() {
87+
info!("Held for {:?}", dur);
88+
}
89+
}
90+
91+
button.reset();
92+
}) as Box<dyn FnMut()>);
93+
94+
web_sys::window()
95+
.unwrap()
96+
.set_interval_with_callback_and_timeout_and_arguments_0(
97+
callback.as_ref().unchecked_ref(),
98+
20,
99+
)
100+
.unwrap();
101+
callback.forget();
102+
}
103+
}

src/instant.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,27 @@ impl InstantProvider<embassy_time::Duration> for embassy_time::Instant {
3131
embassy_time::Instant::now()
3232
}
3333
}
34+
35+
#[cfg(feature = "wasm")]
36+
/// A wrapper around `js_sys::Date` that implements `InstantProvider`.
37+
///
38+
/// This type stores the timestamp as milliseconds since the Unix epoch.
39+
#[derive(Clone, PartialEq)]
40+
pub struct JsInstant(f64);
41+
42+
#[cfg(feature = "wasm")]
43+
impl Sub for JsInstant {
44+
type Output = Duration;
45+
46+
fn sub(self, rhs: Self) -> Self::Output {
47+
let delta_ms = self.0 - rhs.0;
48+
Duration::from_millis(delta_ms as u64)
49+
}
50+
}
51+
52+
#[cfg(feature = "wasm")]
53+
impl InstantProvider<Duration> for JsInstant {
54+
fn now() -> Self {
55+
JsInstant(js_sys::Date::now())
56+
}
57+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ pub use config::{ButtonConfig, Mode};
88
pub use instant::InstantProvider;
99
pub use pin_wrapper::PinWrapper;
1010

11+
#[cfg(feature = "wasm")]
12+
pub use instant::JsInstant;
13+
1114
/// Button configuration.
1215
pub mod config;
1316
/// Different current global time sources.

0 commit comments

Comments
 (0)