Skip to main content

lib_q_core/
wasm_common.rs

1//! Common WASM patterns and utilities for lib-Q
2//!
3//! This module provides shared WASM structures and utilities to eliminate
4//! code duplication across the library.
5
6#[cfg(feature = "wasm")]
7use js_sys::Uint8Array;
8#[cfg(feature = "wasm")]
9use wasm_bindgen::prelude::*;
10
11#[cfg(feature = "alloc")]
12extern crate alloc;
13#[cfg(feature = "alloc")]
14#[allow(unused_imports)]
15use alloc::string::String;
16
17/// Common trait for WASM key pairs
18#[cfg(feature = "wasm")]
19pub trait WasmKeyPair {
20    fn public_key(&self) -> Uint8Array;
21    fn secret_key(&self) -> Uint8Array;
22}
23
24/// Generic WASM key pair implementation
25#[cfg(feature = "wasm")]
26#[wasm_bindgen]
27pub struct WasmKeyPairImpl {
28    public_key: Uint8Array,
29    secret_key: Uint8Array,
30}
31
32#[cfg(feature = "wasm")]
33#[wasm_bindgen]
34impl WasmKeyPairImpl {
35    #[wasm_bindgen(constructor)]
36    pub fn new(public_key: Uint8Array, secret_key: Uint8Array) -> WasmKeyPairImpl {
37        WasmKeyPairImpl {
38            public_key,
39            secret_key,
40        }
41    }
42
43    #[wasm_bindgen(getter)]
44    pub fn public_key(&self) -> Uint8Array {
45        self.public_key.clone()
46    }
47
48    #[wasm_bindgen(getter)]
49    pub fn secret_key(&self) -> Uint8Array {
50        self.secret_key.clone()
51    }
52}
53
54#[cfg(feature = "wasm")]
55impl WasmKeyPair for WasmKeyPairImpl {
56    fn public_key(&self) -> Uint8Array {
57        self.public_key.clone()
58    }
59
60    fn secret_key(&self) -> Uint8Array {
61        self.secret_key.clone()
62    }
63}
64
65/// WASM-compatible hash result
66#[cfg(feature = "wasm")]
67#[wasm_bindgen]
68pub struct HashResultWasm {
69    hash: Uint8Array,
70    algorithm: String,
71}
72
73#[cfg(feature = "wasm")]
74#[wasm_bindgen]
75impl HashResultWasm {
76    #[wasm_bindgen(constructor)]
77    pub fn new(hash: Uint8Array, algorithm: String) -> HashResultWasm {
78        HashResultWasm { hash, algorithm }
79    }
80
81    #[wasm_bindgen(getter)]
82    pub fn hash(&self) -> Uint8Array {
83        self.hash.clone()
84    }
85
86    #[wasm_bindgen(getter)]
87    pub fn algorithm(&self) -> String {
88        self.algorithm.clone()
89    }
90}
91
92/// Stable numeric category id for programmatic `switch` in JS (FNV-1a 32-bit of `code`).
93#[cfg(feature = "wasm")]
94fn wasm_error_code_numeric(code: &str) -> u32 {
95    const OFFSET_BASIS: u32 = 0x811C_9DC5;
96    const PRIME: u32 = 0x0100_0193;
97    let mut hash = OFFSET_BASIS;
98    for b in code.as_bytes() {
99        hash ^= u32::from(*b);
100        hash = hash.wrapping_mul(PRIME);
101    }
102    hash
103}
104
105/// Structured error for JavaScript callers: `{ "code", "codeNumeric", "message" }`.
106#[cfg(feature = "wasm")]
107pub fn wasm_js_error(code: &str, message: impl core::fmt::Display) -> JsValue {
108    use alloc::format;
109
110    let code_numeric = wasm_error_code_numeric(code);
111    let v = serde_json::json!({
112        "code": code,
113        "codeNumeric": code_numeric,
114        "message": format!("{message}"),
115    });
116    serde_wasm_bindgen::to_value(&v).unwrap_or_else(|_| {
117        JsValue::from_str("lib-q-core: failed to serialize structured WASM error")
118    })
119}
120
121/// Utility functions for WASM conversions
122#[cfg(feature = "wasm")]
123pub mod conversions {
124    use alloc::vec::Vec;
125
126    use js_sys::Uint8Array;
127
128    /// Convert Rust Vec<u8> to WASM Uint8Array
129    pub fn vec_to_uint8array(data: &[u8]) -> Uint8Array {
130        let array = Uint8Array::new_with_length(data.len() as u32);
131        array.copy_from(data);
132        array
133    }
134
135    /// Convert WASM Uint8Array to Rust Vec<u8>
136    pub fn uint8array_to_vec(array: &Uint8Array) -> Vec<u8> {
137        let length = array.length() as usize;
138        let mut vec = alloc::vec![0u8; length];
139        array.copy_to(&mut vec);
140        vec
141    }
142}
143
144#[cfg(test)]
145mod tests {
146
147    #[test]
148    fn test_wasm_common_structure() {
149        // Test that the module compiles correctly
150        // In a real WASM environment, these would be tested with wasm-bindgen-test
151        // This is a placeholder for WASM-specific initialization
152    }
153}