Masked to string
This commit is contained in:
@@ -0,0 +1,114 @@
|
|||||||
|
use crate::configotron::fsm::TransitionMask;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn mask_to_string(mask: TransitionMask) -> String {
|
||||||
|
let mut last_bit: bool = false;
|
||||||
|
let mut range_start: Option<u32> = None;
|
||||||
|
let mut parts: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
fn num_to_string(i: u8) -> String {
|
||||||
|
match i {
|
||||||
|
0x00 => "NUL".to_string(),
|
||||||
|
0x09 => "TAB".to_string(),
|
||||||
|
0x1B => "ESC".to_string(),
|
||||||
|
0x20 => "SP".to_string(),
|
||||||
|
0x7F => "DEL".to_string(),
|
||||||
|
0x21..=0x7E => format!("\'{}\'", (i as char).to_string()),
|
||||||
|
_ => format!("0x{:02X}", i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..=0x7F {
|
||||||
|
let current_bit = (mask & (1 << i)) > 0;
|
||||||
|
|
||||||
|
match (current_bit, last_bit, range_start) {
|
||||||
|
(true, false, None) => {
|
||||||
|
// Start of a new range
|
||||||
|
range_start = Some(i);
|
||||||
|
last_bit = true;
|
||||||
|
}
|
||||||
|
(true, true, Some(_)) => {
|
||||||
|
// Continue current range
|
||||||
|
last_bit = true;
|
||||||
|
}
|
||||||
|
(false, true, Some(start)) => {
|
||||||
|
// End of a range
|
||||||
|
if start == i - 1 {
|
||||||
|
parts.push(num_to_string(start as u8));
|
||||||
|
} else if start == i - 2 {
|
||||||
|
parts.push(num_to_string(start as u8));
|
||||||
|
parts.push(num_to_string((i - 1) as u8));
|
||||||
|
} else {
|
||||||
|
parts.push(format!("{}..{}", num_to_string(start as u8), num_to_string((i - 1) as u8)));
|
||||||
|
}
|
||||||
|
range_start = None;
|
||||||
|
last_bit = false;
|
||||||
|
}
|
||||||
|
(false, false, None) => {
|
||||||
|
// Nothing to do
|
||||||
|
last_bit = false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (last_bit, range_start) {
|
||||||
|
(_, None) => {},
|
||||||
|
(_, Some(start)) => {
|
||||||
|
if start == 0x7f {
|
||||||
|
parts.push(num_to_string(start as u8));
|
||||||
|
} else if start == 0x7e {
|
||||||
|
parts.push(num_to_string(start as u8));
|
||||||
|
parts.push(num_to_string((0x7f) as u8));
|
||||||
|
} else {
|
||||||
|
parts.push(format!("{}..{}", num_to_string(start as u8), num_to_string((0x7f - 1) as u8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.join(",")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::configotron::fsm::{display::mask_to_string, masks::{mask_all, mask_char, mask_char_range}};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_to_string_test() {
|
||||||
|
mask_to_string(mask_char('\x7F'));
|
||||||
|
assert_eq!(mask_to_string(mask_char('A')), "'A'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_all()), "NUL..'~'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('z')), "'z'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('0')), "'0'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char_range('0', '9')), "'0'..'9'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char_range('x', 'z')), "'x'..'z'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('a') | mask_char('c')), "'a','c'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('a') | mask_char('b') | mask_char('c')), "'a'..'c'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char_range('a', 'c') | mask_char('e')), "'a'..'c','e'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('\t')), "TAB".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('\x7F')), "DEL".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('\x00')), "NUL".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char_range('A', 'A')), "'A'".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char(' ')), "SP".to_string());
|
||||||
|
assert_eq!(mask_to_string(mask_char('\x1B')), "ESC".to_string());
|
||||||
|
assert_eq!(
|
||||||
|
mask_to_string(
|
||||||
|
mask_char('a')
|
||||||
|
| mask_char('c')
|
||||||
|
| mask_char_range('e', 'g')
|
||||||
|
| mask_char('i')
|
||||||
|
| mask_char_range('k', 'm')
|
||||||
|
| mask_char('o')
|
||||||
|
| mask_char('q')
|
||||||
|
| mask_char('s')
|
||||||
|
| mask_char('u')
|
||||||
|
| mask_char('w')
|
||||||
|
| mask_char('y')
|
||||||
|
| mask_char('z')
|
||||||
|
),
|
||||||
|
"'a','c','e'..'g','i','k'..'m','o','q','s','u','w','y','z'".to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ pub fn mask_number_range(start: u8, end: u8) -> TransitionMask {
|
|||||||
mask
|
mask
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mask_number_char(c: char) -> TransitionMask {
|
pub fn mask_char(c: char) -> TransitionMask {
|
||||||
if c.is_ascii() && (c as u8) <= 0x7F {
|
if c.is_ascii() && (c as u8) <= 0x7F {
|
||||||
1 << (c as u8)
|
1 << (c as u8)
|
||||||
} else {
|
} else {
|
||||||
@@ -48,6 +48,18 @@ pub fn mask_all() -> TransitionMask {
|
|||||||
u128::MAX
|
u128::MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mask_char_range(start: char, end: char) -> TransitionMask {
|
||||||
|
let mut mask: TransitionMask = 0;
|
||||||
|
let start_u8 = start as u32;
|
||||||
|
let end_u8 = end as u32;
|
||||||
|
for c in start_u8..=end_u8 {
|
||||||
|
if c <= 0x7F {
|
||||||
|
mask |= 1 << (c as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mask
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::configotron::fsm::masks::decompose_transition;
|
use crate::configotron::fsm::masks::decompose_transition;
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ pub fn run_fsm(fsm: &FiniteStateMachine, input: &String) -> StateType {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::configotron::fsm::{masks::{mask_all, mask_number_char}, run_fsm, Action, FSMBuilder, StateType};
|
use crate::configotron::fsm::{masks::{mask_all, mask_char}, run_fsm, Action, FSMBuilder, StateType};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn basic_fsm_build() {
|
pub fn basic_fsm_build() {
|
||||||
@@ -181,13 +181,13 @@ mod test {
|
|||||||
// u5: * -> u5
|
// u5: * -> u5
|
||||||
// Error/Default: z3
|
// Error/Default: z3
|
||||||
|
|
||||||
fsm_builder.add_link(&z0, &z1, Action::None, mask_number_char('a')).unwrap();
|
fsm_builder.add_link(&z0, &z1, Action::None, mask_char('a')).unwrap();
|
||||||
fsm_builder.add_link(&z0, &z2, Action::None, mask_number_char('b')).unwrap();
|
fsm_builder.add_link(&z0, &z2, Action::None, mask_char('b')).unwrap();
|
||||||
|
|
||||||
fsm_builder.add_link(&z1, &z1, Action::None, mask_number_char('a')).unwrap();
|
fsm_builder.add_link(&z1, &z1, Action::None, mask_char('a')).unwrap();
|
||||||
fsm_builder.add_link(&z1, &z2, Action::None, mask_number_char('b')).unwrap();
|
fsm_builder.add_link(&z1, &z2, Action::None, mask_char('b')).unwrap();
|
||||||
|
|
||||||
fsm_builder.add_link(&z2, &z2, Action::None, mask_number_char('a')).unwrap();
|
fsm_builder.add_link(&z2, &z2, Action::None, mask_char('a')).unwrap();
|
||||||
|
|
||||||
let res_fsm = fsm_builder.finish(&z3, Action::None, &z0);
|
let res_fsm = fsm_builder.finish(&z3, Action::None, &z0);
|
||||||
assert!(res_fsm.is_ok());
|
assert!(res_fsm.is_ok());
|
||||||
|
|||||||
Reference in New Issue
Block a user