pub fn indices_create(max_length: u32, min_length: u32) -> Box<[isize]> {
if min_length > max_length {
panic!("max_length must be >= min_length")
}
let mut slice = vec![-1; max_length as usize].into_boxed_slice();
for i in 0..min_length {
let index = (max_length - 1 - i) as usize;
slice[index] = 0; }
slice
}
#[inline] pub fn indices_to_string(buf: &mut String, alphabet: &[char], indices: &[isize]) {
buf.clear();
indices
.iter()
.filter(|index| **index != -1)
.map(|index| alphabet[*index as usize])
.for_each(|char| buf.push(char))
}
#[inline]
pub fn indices_increment_by(
alphabet: &[char],
indices: &mut [isize],
add_value: usize,
) -> Result<(), &'static str> {
if add_value == 0 {
return Ok(());
}
let mut carry = add_value;
for index in (0..indices.len()).rev() {
if carry == 0 {
break;
}
let current_value = indices[index];
let mut new_value = current_value + carry as isize;
if new_value >= alphabet.len() as isize {
carry = new_value as usize / alphabet.len();
new_value %= alphabet.len() as isize;
} else {
carry = 0;
}
indices[index] = new_value;
}
if carry == 0 {
Ok(())
} else {
Err("Overflow detected! Data/state is now invalid and no longer reliable!")
}
}
#[cfg(test)]
mod tests {
use crate::symbols::combination_count;
use super::*;
#[test]
fn test_create_indices_arr() {
let arr = indices_create(3, 0);
assert_eq!(arr[0], -1);
assert_eq!(arr[1], -1);
assert_eq!(arr[2], -1);
let arr = indices_create(3, 2);
assert_eq!(arr[0], -1);
assert_eq!(arr[1], 0);
assert_eq!(arr[2], 0);
let arr = indices_create(3, 3);
assert_eq!(arr[0], 0);
assert_eq!(arr[1], 0);
assert_eq!(arr[2], 0);
}
#[test]
#[should_panic]
fn test_create_indices_arr_panic() {
indices_create(0, 1);
}
#[test]
fn test_get_word_as_string_1() {
let alphabet: Box<[char]> = Box::from(['a', 'b', 'c']);
let mut arr = indices_create(5, 0);
arr[2] = 1;
arr[3] = 2;
arr[4] = 0;
let mut str_buf = String::new();
indices_to_string(&mut str_buf, &alphabet, &arr);
assert_eq!(str_buf, "bca", "Strings should equal")
}
#[test]
fn test_get_word_as_string_2() {
let alphabet: Box<[char]> = Box::from(['a', 'b', 'c']);
let mut arr = indices_create(5, 0);
arr[0] = 1;
arr[1] = 1;
arr[2] = 1;
arr[3] = 2;
arr[4] = 0;
let mut str_buf = String::new();
indices_to_string(&mut str_buf, &alphabet, &arr);
assert_eq!(str_buf, "bbbca", "Strings should equal")
}
#[test]
fn test_increment_indices_array_add1_overflow() {
let alphabet: Box<[char]> = Box::from(['0', '1']);
let mut arr = indices_create(5, 0);
arr[3] = 1;
arr[4] = 1;
indices_increment_by(&alphabet, &mut arr, 1).unwrap();
assert_eq!(arr[0], -1, "after '11' comes '000'");
assert_eq!(arr[1], -1, "after '11' comes '000'");
assert_eq!(arr[2], 0, "after '11' comes '000'");
assert_eq!(arr[3], 0, "after '11' comes '000'");
assert_eq!(arr[4], 0, "after '11' comes '000'");
}
#[test]
fn test_increment_indices_array_add1() {
let alphabet: Box<[char]> = Box::from(['a', 'b', 'c', 'd', 'e', 'f']);
let mut arr = indices_create(5, 0);
arr[2] = 3;
arr[3] = 5;
arr[4] = 5;
indices_increment_by(&alphabet, &mut arr, 1).unwrap();
assert_eq!(arr[2], 4, "after 'ffd' comes 'ffe'");
assert_eq!(arr[3], 0, "after 'ffd' comes 'ffe'");
assert_eq!(arr[4], 0, "after 'ffd' comes 'ffe'");
}
#[test]
fn test_increment_indices_array_add1_initial() {
let alphabet: Box<[char]> = Box::from(['a', 'b']);
let mut arr = indices_create(5, 0);
indices_increment_by(&alphabet, &mut arr, 1).unwrap();
assert_eq!(arr[4], 0, "after () comes 'a'");
}
#[test]
fn test_increment_indices_array_total_overflow() {
let alphabet: Box<[char]> = Box::from(['a', 'b', 'c', 'd', 'e', 'f']);
let mut arr = indices_create(3, 0);
arr[0] = 5;
arr[1] = 5;
arr[2] = 5;
assert!(
indices_increment_by(&alphabet, &mut arr, 1).is_err(),
"fff with length 3 should not be incrementable!"
)
}
#[test]
fn test_increment_indices_to_upper_bound() {
let len = 3;
let alphabet: Box<[char]> = Box::from(['a', 'b', 'c']);
let mut indices = indices_create(len, 0);
let steps = combination_count(&alphabet, len, 0) - 1;
indices_increment_by(&alphabet, &mut indices, steps).unwrap();
for i in 0..len {
assert_eq!(indices[i as usize], (alphabet.len() - 1) as isize)
}
}
}