#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Table {
Full, AlphanumSpaceSlash, AlphanumSpace, LettersSpace, Alphanum, Numeric, }
pub fn nchar(c: char, table: Table) -> Option<u8> {
let mut n: i32 = 0;
if table != Table::Alphanum && table != Table::Numeric {
if c == ' ' {
return Some(n as u8);
}
n += 1;
}
if table != Table::LettersSpace {
if c >= '0' && c <= '9' {
return Some((n + (c as i32 - '0' as i32)) as u8);
}
n += 10;
}
if table != Table::Numeric {
if c >= 'A' && c <= 'Z' {
return Some((n + (c as i32 - 'A' as i32)) as u8);
}
n += 26;
}
match table {
Table::Full => {
match c {
'+' => Some((n + 0) as u8),
'-' => Some((n + 1) as u8),
'.' => Some((n + 2) as u8),
'/' => Some((n + 3) as u8),
'?' => Some((n + 4) as u8),
_ => None,
}
}
Table::AlphanumSpaceSlash => {
if c == '/' { Some((n + 0) as u8) } else { None }
}
_ => None,
}
}
pub fn charn(n: u8, table: Table) -> char {
let mut n = n as i32;
if table != Table::Alphanum && table != Table::Numeric {
if n == 0 {
return ' ';
}
n -= 1;
}
if table != Table::LettersSpace {
if n < 10 {
return char::from_u32('0' as u32 + n as u32).unwrap();
}
n -= 10;
}
if table != Table::Numeric {
if n < 26 {
return char::from_u32('A' as u32 + n as u32).unwrap();
}
n -= 26;
}
match table {
Table::Full => {
"+-./?"
.chars()
.nth(n as usize)
.unwrap_or('_')
}
Table::AlphanumSpaceSlash => {
if n == 0 { '/' } else { '_' }
}
_ => '_',
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nchar_charn_roundtrip_full() {
let chars: &str = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./? ";
for c in " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?".chars() {
let idx = nchar(c, Table::Full).expect(&format!("nchar failed for '{}'", c));
assert_eq!(charn(idx, Table::Full), c);
}
let _ = chars;
}
#[test]
fn nchar_alphanum_space() {
assert_eq!(nchar(' ', Table::AlphanumSpace), Some(0));
assert_eq!(nchar('0', Table::AlphanumSpace), Some(1));
assert_eq!(nchar('Z', Table::AlphanumSpace), Some(36));
assert_eq!(nchar('/', Table::AlphanumSpace), None);
}
}