Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit a17f0c1

Browse files
author
Flori
authored
wasm-bindgen setup (#53)
* Expand ignored file patterns * add wasm_bindgen feature * add wasm_bindgen related optimizations and module * add mod.rs * reconcile lib feature * cargo wasm setup * add wasm-pack-helper script * add files from polyproto-js * reformat file * update wasm settings * bindgen headaches galore!!!!!!!! * add description for wasm module * add no_wee_alloc feature to disable wee_alloc if wasm_bindgen is instrumented through another crate * add license headers
1 parent fffd68b commit a17f0c1

File tree

11 files changed

+170
-5
lines changed

11 files changed

+170
-5
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77
cert.csr
88
cert.der
99
/firedbg
10-
.vscode/ltex.*
10+
.vscode/ltex.*
11+
pkg/
12+
wasm-pack.log

.vscode/settings.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
{
22
"markiscodecoverage.searchCriteria": ".coverage/lcov*.info",
3-
"rust-analyzer.cargo.features": ["types", "reqwest", "gateway", "serde"]
3+
// "rust-analyzer.cargo.features": ["types", "reqwest", "gateway", "serde"]
4+
"rust-analyzer.cargo.features": [
5+
"_wasm_bindgen",
6+
"wasm",
7+
"types",
8+
"reqwest",
9+
"gateway",
10+
"serde"
11+
],
12+
"rust-analyzer.cargo.noDefaultFeatures": true,
13+
"rust-analyzer.cargo.target": "wasm32-unknown-unknown"
414
}

Cargo.toml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repository = "https://github.com/polyphony-chat/polyproto"
88
rust-version = "1.85.0"
99

1010
[lib]
11-
crate-type = ["rlib", "cdylib", "staticlib"]
11+
crate-type = ["cdylib", "rlib"]
1212

1313
[features]
1414
default = ["types", "serde", "gateway", "tokio/net"]
@@ -20,6 +20,8 @@ serde = ["dep:serde", "serde_json", "serde_with", "url/serde"]
2020
serde_with = ["dep:serde_with"]
2121
serde_json = ["dep:serde_json"]
2222
gateway = ["serde", "types"]
23+
_wasm_bindgen = ["wasm", "dep:wasm-bindgen", "dep:js-sys", "dep:wee_alloc"]
24+
__no_wee_alloc = []
2325

2426
[dependencies]
2527
der = { version = "0.7.9", features = ["pem"] }
@@ -50,6 +52,11 @@ futures-util = "0.3.31"
5052
urlencoding = "2.1.3"
5153
ws_stream_wasm = { version = "*", optional = true }
5254

55+
[target.'cfg(target_arch = "wasm32")'.dependencies]
56+
wasm-bindgen = { version = "0.2.100", optional = true }
57+
js-sys = { version = "0.3.77", optional = true }
58+
wee_alloc = { version = "0.4.5", optional = true }
59+
5360
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
5461
rustls = "0.23.25"
5562
tokio-tungstenite = { version = "0.26.2", features = [
@@ -73,7 +80,18 @@ httptest = "0.16.3"
7380

7481
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
7582
wasm-bindgen-test = "0.3.50"
76-
wasm-bindgen = "0.2.100"
83+
# The `console_error_panic_hook` crate provides better debugging of panics by
84+
# logging them with `console.error`. This is great for development, but requires
85+
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
86+
# code size when deploying.
87+
console_error_panic_hook = { version = "0.1.7" }
88+
89+
[target.'cfg(target_arch = "wasm32")'.release]
90+
# Tell `rustc` to optimize for small code size.
91+
opt-level = "s"
92+
lto = true
93+
codegen-units = 1
94+
panic = "abort"
7795

7896
[lints.rust]
7997
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }

headaches.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Headaches involving `wasm-bindgen` and overall Rust ⇾ TS/JS bindgen
2+
3+
- `wasm-bindgen` does not support traits, or struct generics with trait bounds like `struct X<S: TraitImplementer>`
4+
- Crates like `ts_rs` might help but would require a more complex build process to assemble a finished TS/JS project
5+
- Worst case: Manually write JS/TS code to bridge the things unsupported by other bindgen libs
6+
- Would be immensely painful
7+
- Other idea: LOADS of handwritten wrappers for Rust functions, also written in Rust but `wasm-bindgen` compatible.
8+
- For traits like signature, we need to make an extremely generic impl that can be somehow instantiated from js/ts

scripts/wasm-pack-helper

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
# This Source Code Form is subject to the terms of the Mozilla Public
3+
# License, v. 2.0. If a copy of the MPL was not distributed with this
4+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
6+
# check number of arguments
7+
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
8+
echo "Error: Invalid number of arguments. Usage: $0 <build|pack|publish> [release|debug]"
9+
exit 1
10+
fi
11+
12+
command=$1
13+
mode=${2:-"debug"}
14+
15+
# validate if arg #1 is valid
16+
if [[ "$command" != "build" && "$command" != "pack" && "$command" != "publish" ]]; then
17+
echo "Error: First argument must be one of 'build', 'pack', or 'publish'."
18+
exit 1
19+
fi
20+
21+
# same for arg #2
22+
if [[ "$mode" != "release" && "$mode" != "debug" ]]; then
23+
echo "Error: Second argument must be either 'release' or 'debug'. Defaulting to 'debug'."
24+
mode="debug"
25+
fi
26+
27+
# wasm-pack check
28+
if ! command -v wasm-pack &> /dev/null; then
29+
# prompt user to install wasm-pack
30+
read -p "wasm-pack could not be found. Do you want to install it? (y/n): " install_wasm_pack
31+
if [[ "$install_wasm_pack" == [Yy]* ]]; then
32+
cargo install wasm-pack --force
33+
else
34+
echo "Error: wasm-pack is required for this script."
35+
exit 1
36+
fi
37+
fi
38+
39+
# Execute the wasm-pack command
40+
wasm-pack $command --$mode --no-default-features --features=wasm,reqwest,serde,types,_wasm_bindgen

src/key.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,7 @@ pub trait PublicKey<S: Signature>: PartialEq + Eq + Clone {
3636
S::algorithm_identifier()
3737
}
3838
/// Creates a new [Self] from a [PublicKeyInfo].
39-
fn try_from_public_key_info(public_key_info: PublicKeyInfo) -> Result<Self, CertificateConversionError>;
39+
fn try_from_public_key_info(
40+
public_key_info: PublicKeyInfo,
41+
) -> Result<Self, CertificateConversionError>;
4042
}

src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ of this project.
139139
clippy::todo
140140
)]
141141

142+
#[cfg(all(
143+
target_arch = "wasm32",
144+
feature = "_wasm_bindgen",
145+
not(feature = "__no_wee_alloc")
146+
))]
147+
#[global_allocator]
148+
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
149+
142150
/// The OID for the `domainComponent` RDN
143151
pub const OID_RDN_DOMAIN_COMPONENT: &str = "0.9.2342.19200300.100.1.25";
144152
/// The OID for the `commonName` RDN
@@ -168,6 +176,10 @@ pub mod signature;
168176
/// Types used in polyproto and the polyproto HTTP/REST APIs
169177
pub mod types;
170178

179+
#[cfg(all(target_arch = "wasm32", feature = "_wasm_bindgen"))]
180+
/// 🚧 Under construction! 👷 Module for exporting polyproto to JS/TS.
181+
pub mod wasm_bindgen;
182+
171183
mod constraints;
172184

173185
pub use der;

src/wasm_bindgen/errors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use wasm_bindgen::prelude::*;
6+
7+
#[derive(Debug, Clone, Copy)]
8+
#[wasm_bindgen(js_name = "PolyprotoError")]
9+
pub enum JsConstraintError {
10+
InvalidInput,
11+
}

src/wasm_bindgen/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
pub mod errors;
6+
pub mod types;
7+
8+
mod utils;

src/wasm_bindgen/types.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use crate::types::DomainName as RDomainName;
6+
use crate::types::FederationId as RFederationId;
7+
use wasm_bindgen::prelude::*;
8+
9+
use super::errors::JsConstraintError;
10+
11+
#[derive(Clone, Debug)]
12+
#[wasm_bindgen(inspectable)]
13+
/// A `FederationId` is a globally unique identifier for an actor in the context of polyproto.
14+
pub struct FederationId {
15+
#[wasm_bindgen(skip)]
16+
_inner: RFederationId,
17+
}
18+
19+
#[wasm_bindgen]
20+
impl FederationId {
21+
#[wasm_bindgen(constructor)]
22+
/// Validates input, then creates a new `FederationId`. Throws an error if input validation fails.
23+
pub fn new(id: &str) -> Result<FederationId, JsConstraintError> {
24+
Ok(FederationId {
25+
_inner: RFederationId::new(id).map_err(|_| JsConstraintError::InvalidInput)?,
26+
})
27+
}
28+
29+
#[wasm_bindgen(js_name = "toJSON")]
30+
pub fn js_to_json(&self) -> String {
31+
self._inner.to_string()
32+
}
33+
}
34+
35+
#[derive(Debug, Clone)]
36+
#[wasm_bindgen(inspectable)]
37+
pub struct DomainName {
38+
#[wasm_bindgen(skip)]
39+
_inner: RDomainName,
40+
}

0 commit comments

Comments
 (0)