pub mod huffman_codes;
pub mod openings;
pub mod score_move;
use crate::pgn_data::{PgnData, PgnHeaders};
use anyhow::{anyhow, Result};
use bincode::serialize_into;
use bit_vec::BitVec;
use flate2::{read::ZlibDecoder, write::ZlibEncoder, Compression};
#[macro_export]
macro_rules! export_to_wasm {
($module_name:literal, $compress_pgn_data:ident, $decompress_pgn_data:ident) => {
::paste::paste! {
#[wasm_bindgen]
pub fn [<$module_name _compress_pgn_str>](pgn_str: &str) -> Vec<u8> {
let pgn_data = match PgnData::from_str(pgn_str) {
Ok(pgn_data) => pgn_data,
Err(_) => return Vec::new(),
};
if pgn_data.is_empty() {
return Vec::new();
}
match $compress_pgn_data(&pgn_data) {
Ok(compressed_data) => compressed_data.to_bytes(),
Err(_) => Vec::new(),
}
}
#[wasm_bindgen]
pub fn [<$module_name _decompress_pgn_str>](compressed_data: &[u8]) -> String {
match $decompress_pgn_data(&BitVec::from_bytes(compressed_data)) {
Ok(pgn_data) => pgn_data.to_string(),
Err(_) => String::new(),
}
}
}
};
}
pub(crate) use export_to_wasm;
pub fn i8_to_bit_vec(i: i8) -> BitVec {
let mut bit_vec = BitVec::new();
for j in (0..8).rev() {
bit_vec.push((i >> j) & 1 == 1);
}
bit_vec
}
pub fn get_bitvec_slice(bit_vec: &BitVec, start: usize, end: usize) -> Result<BitVec> {
let len = bit_vec.len();
if (start > end) || (start > len) || (end > len) {
return Err(anyhow!(
"get_bitvec_slice() - Invalid indices found, start: {}, end: {}, len: {}",
start,
end,
len
));
}
let mut result = BitVec::with_capacity(end - start);
for i in start..end {
result.push(bit_vec[i]);
}
Ok(result)
}
pub fn compress_headers(pgn: &PgnData) -> Result<BitVec> {
if pgn.headers.is_empty() {
return Ok(BitVec::new());
}
let mut compressed_headers = Vec::new();
let mut encoder = ZlibEncoder::new(&mut compressed_headers, Compression::best());
serialize_into(&mut encoder, &pgn.headers)?;
encoder.finish()?;
Ok(BitVec::from_bytes(&compressed_headers))
}
pub fn decompress_headers(bit_vec: &BitVec) -> Result<(PgnHeaders, usize)> {
if bit_vec[0] {
return Ok((PgnHeaders::new(), 0));
}
let header_bytes_len =
bit_vec.iter().take(8).enumerate().fold(
0,
|byte, (i, bit)| {
if bit {
byte | 1 << (7 - i)
} else {
byte
}
},
);
let headers_bytes = get_bitvec_slice(bit_vec, 8, (header_bytes_len + 1) * 8)?.to_bytes();
let headers_slice = headers_bytes.as_slice();
let mut decoder = ZlibDecoder::new(headers_slice);
let headers: PgnHeaders = bincode::deserialize_from(&mut decoder)?;
Ok((headers, (header_bytes_len + 1) * 8))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_i8_to_bit_vec_0() {
let x = 0;
let mut expected = BitVec::new();
for _ in 0..8 {
expected.push(false);
}
assert_eq!(i8_to_bit_vec(x), expected);
}
#[test]
fn test_i8_to_bit_vec_1() {
let x = 1;
let mut expected = BitVec::new();
for _ in 0..7 {
expected.push(false);
}
expected.push(true);
assert_eq!(i8_to_bit_vec(x), expected);
}
#[test]
fn test_i8_to_bit_vec_10() {
let x = 10;
let mut expected = BitVec::new();
expected.push(false); expected.push(false); expected.push(false); expected.push(false); expected.push(true); expected.push(false); expected.push(true); expected.push(false); assert_eq!(i8_to_bit_vec(x), expected);
}
#[test]
fn test_get_bitvec_slice() {
let mut bit_vec = BitVec::new();
bit_vec.push(true);
bit_vec.push(false);
bit_vec.push(true);
bit_vec.push(false);
assert_eq!(get_bitvec_slice(&bit_vec, 0, 4).unwrap(), bit_vec);
}
#[test]
fn test_get_bitvec_slice_subslice() {
let mut bit_vec = BitVec::new();
bit_vec.push(true);
bit_vec.push(false);
bit_vec.push(true);
bit_vec.push(false);
let mut expected = BitVec::new();
expected.push(false);
expected.push(true);
assert_eq!(get_bitvec_slice(&bit_vec, 1, 3).unwrap(), expected);
}
#[test]
fn test_get_bitvec_slice_invalid_start() {
let mut bit_vec = BitVec::new();
bit_vec.push(true);
bit_vec.push(false);
bit_vec.push(true);
bit_vec.push(false);
assert!(get_bitvec_slice(&bit_vec, 5, 8).is_err());
}
#[test]
fn test_get_bitvec_slice_invalid_end() {
let mut bit_vec = BitVec::new();
bit_vec.push(true);
bit_vec.push(false);
bit_vec.push(true);
bit_vec.push(false);
assert!(get_bitvec_slice(&bit_vec, 0, 5).is_err());
}
#[test]
fn test_get_bitvec_slice_invalid_start_and_end() {
let mut bit_vec = BitVec::new();
bit_vec.push(true);
bit_vec.push(false);
bit_vec.push(true);
bit_vec.push(false);
assert!(get_bitvec_slice(&bit_vec, 5, 8).is_err());
}
#[test]
fn test_get_bitvec_slice_start_greater_than_end() {
let mut bit_vec = BitVec::new();
bit_vec.push(true);
bit_vec.push(false);
bit_vec.push(true);
bit_vec.push(false);
assert!(get_bitvec_slice(&bit_vec, 3, 2).is_err());
}
}