use wasm_bindgen::prelude::*;
use wubi::{L0Snapshot, LAYER_COUNT, Layer as CoreLayer, WubiDict};
#[wasm_bindgen]
pub enum Layer {
Auto = 0,
Phrase = 1,
Zigen = 2,
Jianma3 = 3,
Jianma2 = 4,
Jianma1 = 5,
}
impl From<Layer> for CoreLayer {
fn from(l: Layer) -> Self {
match l {
Layer::Auto => CoreLayer::Auto,
Layer::Phrase => CoreLayer::Phrase,
Layer::Zigen => CoreLayer::Zigen,
Layer::Jianma3 => CoreLayer::Jianma3,
Layer::Jianma2 => CoreLayer::Jianma2,
Layer::Jianma1 => CoreLayer::Jianma1,
}
}
}
#[wasm_bindgen]
pub struct WubiEngine {
dict: WubiDict,
}
#[wasm_bindgen]
impl WubiEngine {
#[wasm_bindgen(constructor)]
pub fn new() -> WubiEngine {
Self {
dict: WubiDict::embedded(),
}
}
#[wasm_bindgen(getter)]
pub fn len(&self) -> usize {
self.dict.len()
}
#[wasm_bindgen(getter, js_name = isEmpty)]
pub fn is_empty(&self) -> bool {
self.dict.is_empty()
}
pub fn lookup(&self, code: &str) -> js_sys::Array {
let arr = js_sys::Array::new();
for word in self.dict.lookup(code) {
arr.push(&JsValue::from_str(&word));
}
arr
}
#[wasm_bindgen(js_name = prefix)]
pub fn prefix_lookup(&self, prefix: &str) -> js_sys::Array {
let arr = js_sys::Array::new();
for (code, word) in self.dict.prefix(prefix) {
let obj = js_sys::Object::new();
let _ = js_sys::Reflect::set(&obj, &"code".into(), &JsValue::from_str(&code));
let _ = js_sys::Reflect::set(&obj, &"word".into(), &JsValue::from_str(&word));
arr.push(&obj);
}
arr
}
#[wasm_bindgen(js_name = recordPick)]
pub fn record_pick(&self, code: &str, word: &str) -> bool {
self.dict.record_pick(code, word)
}
pub fn pin(&self, code: &str, word: &str) -> bool {
self.dict.pin(code, word)
}
pub fn forget(&self, code: &str) -> bool {
self.dict.forget(code)
}
#[wasm_bindgen(js_name = setLayerPref)]
pub fn set_layer_pref(&self, layer: Layer, multiplier: f64) {
self.dict.set_layer_pref(layer.into(), multiplier);
}
#[wasm_bindgen(js_name = layerPref)]
pub fn layer_pref(&self, layer: Layer) -> f64 {
self.dict.layer_pref(layer.into())
}
#[wasm_bindgen(js_name = l0PinCount, getter)]
pub fn l0_pin_count(&self) -> usize {
self.dict.l0_pin_count()
}
#[wasm_bindgen(js_name = l0PendingCount, getter)]
pub fn l0_pending_count(&self) -> usize {
self.dict.l0_pending_count()
}
#[wasm_bindgen(js_name = exportL0)]
pub fn export_l0(&self) -> JsValue {
let snap = self.dict.export_l0();
let obj = js_sys::Object::new();
let pins = js_sys::Array::new();
for (c, w) in &snap.pins {
let pair = js_sys::Array::new();
pair.push(&JsValue::from_str(c));
pair.push(&JsValue::from_str(w));
pins.push(&pair);
}
let _ = js_sys::Reflect::set(&obj, &"pins".into(), &pins);
let counts = js_sys::Array::new();
for (c, w, n) in &snap.pick_counts {
let triple = js_sys::Array::new();
triple.push(&JsValue::from_str(c));
triple.push(&JsValue::from_str(w));
triple.push(&JsValue::from_f64(*n as f64));
counts.push(&triple);
}
let _ = js_sys::Reflect::set(&obj, &"pickCounts".into(), &counts);
let prefs = js_sys::Array::new();
for p in snap.layer_prefs {
prefs.push(&JsValue::from_f64(p));
}
let _ = js_sys::Reflect::set(&obj, &"layerPrefs".into(), &prefs);
obj.into()
}
#[wasm_bindgen(js_name = importL0)]
pub fn import_l0(&self, state: JsValue) -> usize {
let Some(obj) = state.dyn_ref::<js_sys::Object>() else {
return 0;
};
let snap = parse_snapshot(obj);
self.dict.import_l0(snap)
}
}
impl Default for WubiEngine {
fn default() -> Self {
Self::new()
}
}
fn parse_snapshot(obj: &js_sys::Object) -> L0Snapshot {
let pins = js_sys::Reflect::get(obj, &"pins".into())
.ok()
.and_then(|v| v.dyn_into::<js_sys::Array>().ok())
.map(|arr| {
arr.iter()
.filter_map(|pair| {
let pair: js_sys::Array = pair.dyn_into().ok()?;
let c = pair.get(0).as_string()?;
let w = pair.get(1).as_string()?;
Some((c, w))
})
.collect()
})
.unwrap_or_default();
let pick_counts = js_sys::Reflect::get(obj, &"pickCounts".into())
.ok()
.and_then(|v| v.dyn_into::<js_sys::Array>().ok())
.map(|arr| {
arr.iter()
.filter_map(|triple| {
let triple: js_sys::Array = triple.dyn_into().ok()?;
let c = triple.get(0).as_string()?;
let w = triple.get(1).as_string()?;
let n = triple.get(2).as_f64()? as u32;
Some((c, w, n))
})
.collect()
})
.unwrap_or_default();
let mut layer_prefs = wubi::DEFAULT_LAYER_PREFS;
if let Ok(arr) = js_sys::Reflect::get(obj, &"layerPrefs".into()) {
if let Ok(arr) = arr.dyn_into::<js_sys::Array>() {
for i in 0..LAYER_COUNT.min(arr.length() as usize) {
if let Some(v) = arr.get(i as u32).as_f64() {
layer_prefs[i] = v;
}
}
}
}
L0Snapshot {
pins,
pick_counts,
layer_prefs,
}
}