//! CHSM8 move tokenizer. Rust core, with optional Python (`--features python`) and //! WebAssembly (`--features wasm`) bindings, so the server and the browser tokenize identically. mod core; pub use crate::core::*; #[cfg(feature = "python")] mod python { use pyo3::exceptions::PyValueError; use pyo3::prelude::*; /// Any notation -> uint16 move tokens. #[pyfunction] fn tokenize(text: &str) -> PyResult> { crate::core::tokenize(text).map_err(PyValueError::new_err) } /// Any notation -> canonical UCI moves. #[pyfunction] fn to_uci(text: &str) -> PyResult> { crate::core::to_uci(text).map_err(PyValueError::new_err) } /// uint16 token -> UCI move. #[pyfunction] fn token_to_uci(t: u16) -> String { crate::core::token_to_uci(t) } /// Any notation -> (rows, legal) where rows = BOS + one row per move and /// legal = [(uci, san, row)] for the side to move. #[pyfunction] #[allow(clippy::type_complexity)] fn analyze(text: &str) -> PyResult<(Vec<[u16; 5]>, Vec<(String, String, [u16; 5])>)> { let a = crate::core::analyze(text).map_err(PyValueError::new_err)?; let wide = |r: [u8; 5]| r.map(u16::from); // ints in Python, not bytes Ok((a.rows.into_iter().map(wide).collect(), a.legal.into_iter().map(|l| (l.uci, l.san, wide(l.row))).collect())) } #[pymodule] fn chsm8_tok(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(tokenize, m)?)?; m.add_function(wrap_pyfunction!(to_uci, m)?)?; m.add_function(wrap_pyfunction!(token_to_uci, m)?)?; m.add_function(wrap_pyfunction!(analyze, m)?)?; Ok(()) } } #[cfg(feature = "wasm")] mod wasm { use wasm_bindgen::prelude::*; /// Any notation -> space-separated tokens (throws on illegal input). #[wasm_bindgen] pub fn tokenize(text: &str) -> Result, JsError> { crate::core::tokenize(text).map_err(|e| JsError::new(&e)) } /// Any notation -> JSON {rows: [[k,f,t,p,q]..], uci: [..], legal: [{uci, san, row}], fen}. #[wasm_bindgen] pub fn analyze(text: &str) -> Result { let a = crate::core::analyze(text).map_err(|e| JsError::new(&e))?; let rows: Vec = a.rows.iter().map(|r| format!("{:?}", r)).collect(); let uci: Vec = a.uci.iter().map(|u| format!("\"{u}\"")).collect(); let legal: Vec = a .legal .iter() .map(|l| format!("{{\"uci\":\"{}\",\"san\":\"{}\",\"row\":{:?}}}", l.uci, l.san, l.row)) .collect(); Ok(format!( "{{\"rows\":[{}],\"uci\":[{}],\"legal\":[{}],\"fen\":\"{}\"}}", rows.join(","), uci.join(","), legal.join(","), a.fen )) } }