chsm8-tokenizer / src /lib.rs
LegumMagister's picture
Initial commit
a59a6d0
Raw History Blame Contribute Delete
2.84 kB
//! 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<Vec<u16>> {
crate::core::tokenize(text).map_err(PyValueError::new_err)
}
/// Any notation -> canonical UCI moves.
#[pyfunction]
fn to_uci(text: &str) -> PyResult<Vec<String>> {
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<Vec<u16>, 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<String, JsError> {
let a = crate::core::analyze(text).map_err(|e| JsError::new(&e))?;
let rows: Vec<String> = a.rows.iter().map(|r| format!("{:?}", r)).collect();
let uci: Vec<String> = a.uci.iter().map(|u| format!("\"{u}\"")).collect();
let legal: Vec<String> = 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
))
}
}