use core::mem; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(u8)] pub enum State { Anywhere = 0, CsiEntry = 1, CsiIgnore = 2, CsiIntermediate = 3, CsiParam = 4, DcsEntry = 5, DcsIgnore = 6, DcsIntermediate = 7, DcsParam = 8, DcsPassthrough = 9, Escape = 10, EscapeIntermediate = 11, Ground = 12, OscString = 13, SosPmApcString = 14, Utf8 = 15, } impl Default for State { #[inline] fn default() -> State { State::Ground } } impl TryFrom for State { type Error = u8; #[inline(always)] fn try_from(raw: u8) -> Result { STATES.get(raw as usize).ok_or(raw).copied() } } const STATES: [State; 16] = [ State::Anywhere, State::CsiEntry, State::CsiIgnore, State::CsiIntermediate, State::CsiParam, State::DcsEntry, State::DcsIgnore, State::DcsIntermediate, State::DcsParam, State::DcsPassthrough, State::Escape, State::EscapeIntermediate, State::Ground, State::OscString, State::SosPmApcString, State::Utf8, ]; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum Action { Nop = 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, BeginUtf8 = 15, } impl Default for Action { #[inline] fn default() -> Action { Action::Nop } } impl TryFrom for Action { type Error = u8; #[inline(always)] fn try_from(raw: u8) -> Result { ACTIONS.get(raw as usize).ok_or(raw).copied() } } const ACTIONS: [Action; 16] = [ Action::Nop, Action::Clear, Action::Collect, Action::CsiDispatch, Action::EscDispatch, Action::Execute, Action::Hook, Action::Ignore, Action::OscEnd, Action::OscPut, Action::OscStart, Action::Param, Action::Print, Action::Put, Action::Unhook, Action::BeginUtf8, ]; /// Unpack a u8 into a State and Action /// /// The implementation of this assumes that there are *precisely* 16 variants for both Action and /// State. Furthermore, it assumes that the enums are tag-only; that is, there is no data in any /// variant. /// /// Bad things will happen if those invariants are violated. #[inline(always)] pub const fn unpack(delta: u8) -> (State, Action) { unsafe { ( // State is stored in bottom 4 bits mem::transmute(delta & 0x0f), // Action is stored in top 4 bits mem::transmute(delta >> 4), ) } } #[inline(always)] #[cfg(test)] pub const fn pack(state: State, action: Action) -> u8 { (action as u8) << 4 | state as u8 } #[cfg(test)] mod tests { use super::*; #[test] fn unpack_state_action() { match unpack(0xee) { (State::SosPmApcString, Action::Unhook) => (), _ => panic!("unpack failed"), } match unpack(0x0f) { (State::Utf8, Action::Nop) => (), _ => panic!("unpack failed"), } match unpack(0xff) { (State::Utf8, Action::BeginUtf8) => (), _ => panic!("unpack failed"), } } #[test] fn pack_state_action() { match unpack(0xee) { (State::SosPmApcString, Action::Unhook) => (), _ => panic!("unpack failed"), } match unpack(0x0f) { (State::Utf8, Action::Nop) => (), _ => panic!("unpack failed"), } match unpack(0xff) { (State::Utf8, Action::BeginUtf8) => (), _ => panic!("unpack failed"), } } }