use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use bomboni_wasm::{Wasm, console_log, console_error};
use std::collections::HashMap;
// Standard struct with automatic conversion
#[derive(Serialize, Deserialize, Wasm)]
#[wasm(into_wasm_abi, from_wasm_abi)]
pub struct User {
pub id: u32,
pub name: String,
}
// String-backed ID type
#[derive(Clone, Wasm)]
#[wasm(js_value(convert_string))]
pub struct UserId(String);
impl std::fmt::Display for UserId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::str::FromStr for UserId {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(UserId(s.to_string()))
}
}
// Custom JsValue conversion
#[derive(Wasm)]
#[wasm(js_value(
into = Timestamp::to_js,
try_from = Timestamp::from_js,
))]
pub struct Timestamp(i64);
impl Timestamp {
fn to_js(self) -> JsValue {
js_sys::Date::new(&JsValue::from_f64(self.0 as f64)).into()
}
fn from_js(js: JsValue) -> Result<Self, JsValue> {
if let Some(date) = js.dyn_ref::<js_sys::Date>() {
Ok(Timestamp(date.get_time() as i64))
} else {
Err(JsValue::from_str("Expected a Date object"))
}
}
}
// WASM API functions
#[wasm_bindgen]
pub fn create_user(id: u32, name: String) -> Result<User, JsValue> {
console_log!("Creating user: {} ({})", name, id);
Ok(User { id, name })
}
#[wasm_bindgen]
pub fn get_user_by_id(user_id: UserId) -> Result<User, JsValue> {
console_log!("Looking up user: {}", user_id);
// Lookup logic...
Ok(User {
id: 1,
name: "Alice".to_string(),
})
}
#[wasm_bindgen]
pub fn process_users(users: Vec<User>) -> Result<JsValue, JsValue> {
console_log!("Processing {} users", users.len());
let mut map = HashMap::new();
for user in users {
map.insert(user.id.to_string(), user.name);
}
serde_wasm_bindgen::to_value(&map)
.map_err(|e| {
console_error!("Serialization error: {}", e);
JsValue::from_str(&e.to_string())
})
}