#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
pub enum State {
CsiEntry = 0,
CsiIgnore = 1,
CsiIntermediate = 2,
CsiParam = 3,
DcsEntry = 4,
DcsIgnore = 5,
DcsIntermediate = 6,
DcsParam = 7,
DcsPassthrough = 8,
Error = 9,
Escape = 10,
EscapeIntermediate = 11,
Ground = 12,
OscString = 13,
SosPmApcString = 14,
}
static STATES: &'static [State] = &[
State::CsiEntry,
State::CsiIgnore,
State::CsiIntermediate,
State::CsiParam,
State::DcsEntry,
State::DcsIgnore,
State::DcsIntermediate,
State::DcsParam,
State::DcsPassthrough,
State::Error,
State::Escape,
State::EscapeIntermediate,
State::Ground,
State::OscString,
State::SosPmApcString,
];
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u8)]
pub enum Action {
None = 0,
Clear = 1,
Collect = 2,
CsiDispatch = 3,
EscDispatch = 4,
Execute = 5,
Hook = 6,
Ignore = 7,
OscEnd = 8,
OscPut = 9,
OscStart = 10,
Param = 11,
Print = 12,
Put = 13,
Unhook = 14,
}
pub static ENTRY_ACTIONS: &'static [Action] = &[
Action::Clear, Action::None, Action::None, Action::None, Action::Clear, Action::None, Action::None, Action::None, Action::Hook, Action::None, Action::Clear, Action::None, Action::None, Action::OscStart, Action::None, ];
pub static EXIT_ACTIONS: &'static [Action] = &[
Action::None, Action::None, Action::None, Action::None, Action::None, Action::None, Action::None, Action::None, Action::Unhook, Action::None, Action::None, Action::None, Action::None, Action::OscEnd, Action::None, ];
#[rustfmt::skip]
pub static UTF8_CHAR_WIDTH: [u8; 256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, ];
fn state_table_fn(state: State, byte: u8) -> (Action, State) {
match byte {
0x18 => return (Action::Execute, State::Ground),
0x1A => return (Action::Execute, State::Ground),
0x80...0x8F => return (Action::Execute, State::Ground),
0x91...0x97 => return (Action::Execute, State::Ground),
0x99 => return (Action::Execute, State::Ground),
0x9A => return (Action::Execute, State::Ground),
0x9C => return (Action::None, State::Ground),
0x1B => return (Action::None, State::Escape),
0x98 => return (Action::None, State::SosPmApcString),
0x9E => return (Action::None, State::SosPmApcString),
0x9F => return (Action::None, State::SosPmApcString),
0x90 => return (Action::None, State::DcsEntry),
0x9D => return (Action::None, State::OscString),
0x9B => return (Action::None, State::CsiEntry),
_ => {}
};
match state {
State::CsiEntry => match byte {
0x00...0x17 => (Action::Execute, State::CsiEntry),
0x19 => (Action::Execute, State::CsiEntry),
0x1C...0x1F => (Action::Execute, State::CsiEntry),
0x7F => (Action::Ignore, State::CsiEntry),
0x30...0x39 => (Action::Param, State::CsiParam),
0x3C...0x3F => (Action::Collect, State::CsiParam),
0x3A => (Action::None, State::CsiIgnore),
0x20...0x2F => (Action::Collect, State::CsiIntermediate),
0x40...0x7E => (Action::CsiDispatch, State::Ground),
_ => (Action::None, State::Error),
},
State::CsiIgnore => match byte {
0x00...0x17 => (Action::Execute, State::CsiIgnore),
0x19 => (Action::Execute, State::CsiIgnore),
0x1C...0x1F => (Action::Execute, State::CsiIgnore),
0x20...0x3F => (Action::Ignore, State::CsiIgnore),
0x7F => (Action::Ignore, State::CsiIgnore),
0x40...0x7E => (Action::None, State::Ground),
_ => (Action::None, State::Error),
},
State::CsiIntermediate => match byte {
0x00...0x17 => (Action::Execute, State::CsiIntermediate),
0x19 => (Action::Execute, State::CsiIntermediate),
0x1C...0x1F => (Action::Execute, State::CsiIntermediate),
0x20...0x2F => (Action::Collect, State::CsiIntermediate),
0x7F => (Action::Ignore, State::CsiIntermediate),
0x40...0x7E => (Action::CsiDispatch, State::Ground),
_ => (Action::None, State::Error),
},
State::CsiParam => match byte {
0x00...0x17 => (Action::Execute, State::CsiParam),
0x19 => (Action::Execute, State::CsiParam),
0x1C...0x1F => (Action::Execute, State::CsiParam),
0x30...0x39 => (Action::Param, State::CsiParam),
0x3B => (Action::Param, State::CsiParam),
0x7F => (Action::Ignore, State::CsiParam),
0x40...0x7E => (Action::CsiDispatch, State::Ground),
0x20...0x2F => (Action::Collect, State::CsiIntermediate),
0x3A => (Action::None, State::CsiIgnore),
0x3C...0x3F => (Action::None, State::CsiIgnore),
_ => (Action::None, State::Error),
},
State::DcsEntry => match byte {
0x00...0x17 => (Action::Ignore, State::DcsEntry),
0x19 => (Action::Ignore, State::DcsEntry),
0x1C...0x1F => (Action::Ignore, State::DcsEntry),
0x7F => (Action::Ignore, State::DcsEntry),
0x20...0x2F => (Action::Collect, State::DcsIntermediate),
0x3A => (Action::None, State::DcsIgnore),
0x30...0x39 => (Action::Param, State::DcsParam),
0x3C...0x3F => (Action::Collect, State::DcsParam),
0x40...0x7E => (Action::None, State::DcsPassthrough),
_ => (Action::None, State::Error),
},
State::DcsIgnore => match byte {
0x00...0x17 => (Action::Ignore, State::DcsIgnore),
0x19 => (Action::Ignore, State::DcsIgnore),
0x1C...0x1F => (Action::Ignore, State::DcsIgnore),
0x20...0x7F => (Action::Ignore, State::DcsIgnore),
_ => (Action::None, State::Error),
},
State::DcsIntermediate => match byte {
0x00...0x17 => (Action::Ignore, State::DcsIntermediate),
0x19 => (Action::Ignore, State::DcsIntermediate),
0x1C...0x1F => (Action::Ignore, State::DcsIntermediate),
0x20...0x2F => (Action::Collect, State::DcsIntermediate),
0x7F => (Action::Ignore, State::DcsIntermediate),
0x40...0x7E => (Action::None, State::DcsPassthrough),
0x30...0x3F => (Action::None, State::DcsIgnore),
_ => (Action::None, State::Error),
},
State::DcsParam => match byte {
0x00...0x17 => (Action::Ignore, State::DcsParam),
0x19 => (Action::Ignore, State::DcsParam),
0x1C...0x1F => (Action::Ignore, State::DcsParam),
0x30...0x39 => (Action::Param, State::DcsParam),
0x3B => (Action::Param, State::DcsParam),
0x7F => (Action::Ignore, State::DcsParam),
0x3A => (Action::None, State::DcsIgnore),
0x3C...0x3F => (Action::None, State::DcsIgnore),
0x20...0x2F => (Action::Collect, State::DcsIntermediate),
0x40...0x7E => (Action::None, State::DcsPassthrough),
_ => (Action::None, State::Error),
},
State::DcsPassthrough => match byte {
0x00...0x17 => (Action::Put, State::DcsPassthrough),
0x19 => (Action::Put, State::DcsPassthrough),
0x1C...0x1F => (Action::Put, State::DcsPassthrough),
0x20...0x7E => (Action::Put, State::DcsPassthrough),
0x7F => (Action::Ignore, State::DcsPassthrough),
_ => (Action::None, State::Error),
},
State::Error => (Action::None, State::Error),
State::Escape => match byte {
0x00...0x17 => (Action::Execute, State::Escape),
0x19 => (Action::Execute, State::Escape),
0x1C...0x1F => (Action::Execute, State::Escape),
0x7F => (Action::Ignore, State::Escape),
0x20...0x2F => (Action::Collect, State::EscapeIntermediate),
0x30...0x4F => (Action::EscDispatch, State::Ground),
0x51...0x57 => (Action::EscDispatch, State::Ground),
0x59 => (Action::EscDispatch, State::Ground),
0x5A => (Action::EscDispatch, State::Ground),
0x5C => (Action::EscDispatch, State::Ground),
0x60...0x7E => (Action::EscDispatch, State::Ground),
0x5B => (Action::None, State::CsiEntry),
0x5D => (Action::None, State::OscString),
0x50 => (Action::None, State::DcsEntry),
0x58 => (Action::None, State::SosPmApcString),
0x5E => (Action::None, State::SosPmApcString),
0x5F => (Action::None, State::SosPmApcString),
_ => (Action::None, State::Error),
},
State::EscapeIntermediate => match byte {
0x00...0x17 => (Action::Execute, State::EscapeIntermediate),
0x19 => (Action::Execute, State::EscapeIntermediate),
0x1C...0x1F => (Action::Execute, State::EscapeIntermediate),
0x20...0x2F => (Action::Collect, State::EscapeIntermediate),
0x7F => (Action::Ignore, State::EscapeIntermediate),
0x30...0x7E => (Action::EscDispatch, State::Ground),
_ => (Action::None, State::Error),
},
State::Ground => match byte {
0x00...0x17 => (Action::Execute, State::Ground),
0x19 => (Action::Execute, State::Ground),
0x1C...0x1F => (Action::Execute, State::Ground),
0x20...0x7F => (Action::Print, State::Ground),
0xC0...0xDF => (Action::Print, State::Ground),
0xE0...0xEF => (Action::Print, State::Ground),
0xF0...0xF7 => (Action::Print, State::Ground),
_ => (Action::None, State::Error),
},
State::OscString => match byte {
0x00...0x17 => (Action::Ignore, State::OscString),
0x19 => (Action::Ignore, State::OscString),
0x1C...0x1F => (Action::Ignore, State::OscString),
0x20...0x7F => (Action::OscPut, State::OscString),
_ => (Action::None, State::Error),
},
State::SosPmApcString => match byte {
0x00...0x17 => (Action::Ignore, State::SosPmApcString),
0x19 => (Action::Ignore, State::SosPmApcString),
0x1C...0x1F => (Action::Ignore, State::SosPmApcString),
0x20...0x7F => (Action::Ignore, State::SosPmApcString),
_ => (Action::None, State::Error),
},
}
}
use lazy_static::lazy_static;
lazy_static! {
pub static ref STATE_TABLE: [[u8; 256]; 16] = build_state_table();
}
fn build_state_table() -> [[u8; 256]; 16] {
let mut state_table = [[0; 256]; 16];
for &from_state in STATES {
for byte in 0..0xFF {
let (to_action, to_state) = state_table_fn(from_state, byte);
let value = ((to_action as u8) << 4) | (to_state as u8);
state_table[from_state as usize][byte as usize] = value;
}
}
return state_table;
}
pub fn query(from_state: State, byte: u8) -> (Action, State) {
let table_value = STATE_TABLE[from_state as usize][byte as usize];
let to_action: Action = unsafe { std::mem::transmute((table_value & 0xF0) >> 4) };
let to_state: State = unsafe { std::mem::transmute(table_value & 0x0F) };
(to_action, to_state)
}