mod cluster;
mod dataset;
pub use cluster::SquishyBall;
#[allow(clippy::module_name_repetitions)]
pub use dataset::CodecData;
use distances::{
number::UInt,
strings::{
needleman_wunsch::{apply_edits, compute_table, trace_back_recursive, unaligned_x_to_y, Edit},
Penalties,
},
};
pub type EncoderFn<I> = fn(&I, &I) -> Result<Box<[u8]>, String>;
pub type DecoderFn<I> = fn(&I, &[u8]) -> Result<I, String>;
#[allow(dead_code, clippy::ptr_arg)]
pub fn encode_general<U: UInt>(reference: &String, target: &String) -> Result<Box<[u8]>, String> {
let table = compute_table::<U>(reference, target, Penalties::default());
let (aligned_x, aligned_y) = trace_back_recursive(&table, [reference, target]);
Ok(serialize_edits(&unaligned_x_to_y(&aligned_x, &aligned_y)))
}
#[allow(dead_code, clippy::ptr_arg)]
pub fn decode_general(reference: &String, encoding: &[u8]) -> Result<String, String> {
Ok(apply_edits(reference, &deserialize_edits(encoding)?))
}
fn serialize_edits(edits: &[Edit]) -> Box<[u8]> {
let bytes = edits.iter().flat_map(edit_to_bin).collect::<Vec<_>>();
bytes.into_boxed_slice()
}
fn deserialize_edits(bytes: &[u8]) -> Result<Vec<Edit>, String> {
let mut edits = Vec::new();
let mut i = 0;
let mask_edit = 0b11;
while i < bytes.len() {
let index = u16::from_be_bytes([bytes[i] & !mask_edit, bytes[i + 1]]);
let edit_bits = bytes[i] & mask_edit;
let edit = match edit_bits {
0b10 => {
i += 2;
Edit::Del(index as usize)
}
0b01 => {
let c = bytes[i + 2];
i += 3;
Edit::Ins(index as usize, c as char)
}
0b11 => {
let c = bytes[i + 2];
i += 3;
Edit::Sub(index as usize, c as char)
}
_ => return Err(format!("Invalid edit type: {edit_bits:b}.")),
};
edits.push(edit);
}
Ok(edits)
}
#[allow(clippy::cast_possible_truncation)]
fn edit_to_bin(edit: &Edit) -> Vec<u8> {
let mask_6 = 0b0011_1111;
let mask_del = 0b10;
let mask_ins = 0b01;
let mask_sub = 0b11;
match edit {
Edit::Del(i) => {
let mut bytes = (*i as u16).to_be_bytes().to_vec();
bytes[0] &= mask_6;
bytes[0] |= mask_del;
bytes
}
Edit::Ins(i, c) => {
let mut bytes = (*i as u16).to_be_bytes().to_vec();
bytes[0] &= mask_6;
bytes[0] |= mask_ins;
bytes.push(*c as u8);
bytes
}
Edit::Sub(i, c) => {
let mut bytes = (*i as u16).to_be_bytes().to_vec();
bytes[0] &= mask_6;
bytes[0] |= mask_sub;
bytes.push(*c as u8);
bytes
}
}
}