use core::fmt;
pub const VDS_ALLOWED: &[char] = &[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9',
];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VDChar(pub(crate) u8);
impl VDChar {
pub fn new(c: char) -> Option<Self> {
VDS_ALLOWED.iter().position(|&x| x == c).map(|i| Self(i as u8))
}
pub fn as_char(self) -> char {
VDS_ALLOWED[self.0 as usize]
}
}
impl fmt::Display for VDChar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_char())
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::string::ToString;
#[test]
fn valid_vdchar_constructs() {
assert!(VDChar::new('A').is_some());
assert!(VDChar::new('Z').is_some());
assert!(VDChar::new('2').is_some());
assert!(VDChar::new('9').is_some());
}
#[test]
fn excluded_chars_are_rejected() {
assert!(VDChar::new('O').is_none()); assert!(VDChar::new('I').is_none()); assert!(VDChar::new('0').is_none()); assert!(VDChar::new('1').is_none()); }
#[test]
fn lowercase_chars_are_rejected() {
assert!(VDChar::new('a').is_none());
assert!(VDChar::new('z').is_none());
assert!(VDChar::new('o').is_none());
}
#[test]
fn as_char_returns_original_char() {
for &c in VDS_ALLOWED {
let vd = VDChar::new(c).expect("should be allowed");
assert_eq!(vd.as_char(), c);
}
}
#[test]
fn display_matches_as_char() {
let ch = VDChar::new('X').unwrap();
assert_eq!(ch.to_string(), "X");
}
}