pub fn flatten(codings: &[(u8, u32)], speed: usize) -> Vec<Vec<(Option<usize>, Option<usize>, usize)>> {
let blank_transition = generate_blank_transition(speed);
let mut table: Vec<Vec<(Option<usize>, Option<usize>, usize)>> = Vec::new();
table.push(blank_transition.clone());
for (ascii, coding) in codings.iter().enumerate() {
let leftover = (coding.0 as f32 / speed as f32).ceil() as usize * speed - coding.0 as usize;
let mut id = 0;
for (path_index, keys) in generate_coding_paths(coding, speed).iter().enumerate() {
if path_index == 0 {
for key_index in 0..keys.len() - 1 {
let key = keys[key_index];
let target = &table[id][key];
let next_id = if let Some(next_id) = target.0 {
next_id
} else {
table.push(blank_transition.clone());
let next_id = table.len() - 1;
let transitions = table.get_mut(id).unwrap();
let target = transitions.get_mut(key).unwrap();
target.0 = Some(next_id);
next_id
};
id = next_id;
}
}
let key = keys.last().unwrap();
let transitions = table.get_mut(id).unwrap();
let target = transitions.get_mut(*key).unwrap();
target.1 = Some(ascii);
target.2 = leftover;
}
}
table
}
fn generate_blank_transition(speed: usize) -> Vec<(Option<usize>, Option<usize>, usize)> {
let mut transition = Vec::new();
for _ in 0..2u32.pow(speed as u32) {
transition.push((None, None, 0));
}
transition
}
fn generate_coding_paths(coding: &(u8, u32), speed: usize) -> Vec<Vec<usize>> {
let mut bits: u32 = 0;
let chunks_len = (coding.0 as f32 / speed as f32).ceil() as usize;
let chunk_max = 2u32.pow(speed as u32) as usize - 1;
let leftover = chunks_len * speed - coding.0 as usize;
bits |= coding.1;
bits <<= leftover;
let mut chunks = vec![];
for i in 0..chunks_len {
let mut chunk = (bits >> (chunks_len - i - 1) * speed) as usize;
chunk &= chunk_max;
chunks.push(chunk as usize);
}
let mut variants: Vec<Vec<usize>> = vec![];
let chunk_last = chunks.pop().unwrap();
let variants_len = 2u32.pow(leftover as u32) as usize;
for i in 0..variants_len {
let mut chunks = chunks.clone();
chunks.push(chunk_last + i);
variants.push(chunks);
}
variants
}
#[cfg(test)]
mod test {
use super::*;
fn sample_encoding_table() -> &'static [(u8, u32)] {
&[
(13, 0x1ff8),
(23, 0x7fffd8),
(28, 0xfffffe2),
(28, 0xfffffe3),
(28, 0xfffffe4),
(28, 0xfffffe5),
(28, 0xfffffe6),
(28, 0xfffffe7),
(28, 0xfffffe8),
]
}
#[test]
fn flattens_1bits() {
let table = flatten(&sample_encoding_table(), 1);
assert_eq!(table.len(), 41);
let target = &table[2][1];
assert_eq!(target.0, Some(3));
assert_eq!(target.1, None);
assert_eq!(target.2, 0);
}
#[test]
fn flattens_2bits() {
let table = flatten(&sample_encoding_table(), 2);
assert_eq!(table.len(), 20);
let target = &table[1][3];
assert_eq!(target.0, Some(2));
assert_eq!(target.1, None);
assert_eq!(target.2, 0);
}
#[test]
fn flattens_3bits() {
let table = flatten(&sample_encoding_table(), 3);
assert_eq!(table.len(), 16);
let target = &table[1][7];
assert_eq!(target.0, Some(2));
assert_eq!(target.1, None);
assert_eq!(target.2, 0);
}
#[test]
fn flattens_4bits() {
let table = flatten(&sample_encoding_table(), 4);
assert_eq!(table.len(), 9);
let target = &table[1][15];
assert_eq!(target.0, Some(2));
assert_eq!(target.1, None);
assert_eq!(target.2, 0);
}
#[test]
fn flattens_5bits() {
let table = flatten(&sample_encoding_table(), 5);
assert_eq!(table.len(), 8);
let target = &table[1][31];
assert_eq!(target.0, Some(2));
assert_eq!(target.1, None);
assert_eq!(target.2, 0);
}
#[test]
fn generates_coding_paths() {
assert_eq!(generate_coding_paths(&(14, 12345), 4), vec![
vec![12, 0, 14, 4],
vec![12, 0, 14, 5],
vec![12, 0, 14, 6],
vec![12, 0, 14, 7],
]);
assert_eq!(generate_coding_paths(&(13, 2616), 4), vec![
vec![5, 1, 12, 0],
vec![5, 1, 12, 1],
vec![5, 1, 12, 2],
vec![5, 1, 12, 3],
vec![5, 1, 12, 4],
vec![5, 1, 12, 5],
vec![5, 1, 12, 6],
vec![5, 1, 12, 7],
]);
}
}