diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 540 |
1 files changed, 392 insertions, 148 deletions
@@ -35,13 +35,10 @@ use core::str; #[cfg(feature = "no_std")] use arrayvec::ArrayVec; -mod definitions; mod params; -mod table; #[cfg(feature = "ansi")] pub mod ansi; -use definitions::{unpack, Action, State}; pub use params::{Params, ParamsIter}; const MAX_INTERMEDIATES: usize = 2; @@ -113,7 +110,7 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { let mut i = 0; // Handle partial codepoints from previous calls to `advance`. - if self.partial_utf8_len > 0 { + if self.partial_utf8_len != 0 { i += self.advance_partial_utf8(performer, bytes); } @@ -121,12 +118,9 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { match self.state { State::Ground => i += self.advance_ground(performer, &bytes[i..]), _ => { + // Inlining it results in worse codegen. let byte = bytes[i]; - let change = table::STATE_CHANGES[self.state as usize][byte as usize]; - let (state, action) = unpack(change); - - self.perform_state_change(performer, state, action, byte); - + self.change_state(performer, byte); i += 1; }, } @@ -159,12 +153,9 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { match self.state { State::Ground => i += self.advance_ground(performer, &bytes[i..]), _ => { + // Inlining it results in worse codegen. let byte = bytes[i]; - let change = table::STATE_CHANGES[self.state as usize][byte as usize]; - let (state, action) = unpack(change); - - self.perform_state_change(performer, state, action, byte); - + self.change_state(performer, byte); i += 1; }, } @@ -173,164 +164,398 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { i } - #[inline] - fn perform_state_change<P>(&mut self, performer: &mut P, state: State, action: Action, byte: u8) - where - P: Perform, - { - if state == State::Anywhere { - self.perform_action(performer, action, byte); - return; + #[inline(always)] + fn change_state<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match self.state { + State::CsiEntry => self.advance_csi_entry(performer, byte), + State::CsiIgnore => self.advance_csi_ignore(performer, byte), + State::CsiIntermediate => self.advance_csi_intermediate(performer, byte), + State::CsiParam => self.advance_csi_param(performer, byte), + State::DcsEntry => self.advance_dcs_entry(performer, byte), + State::DcsIgnore => self.anywhere(performer, byte), + State::DcsIntermediate => self.advance_dcs_intermediate(performer, byte), + State::DcsParam => self.advance_dcs_param(performer, byte), + State::DcsPassthrough => self.advance_dcs_passthrough(performer, byte), + State::Escape => self.advance_esc(performer, byte), + State::EscapeIntermediate => self.advance_esc_intermediate(performer, byte), + State::OscString => self.advance_osc_string(performer, byte), + State::SosPmApcString => self.anywhere(performer, byte), + State::Ground => unreachable!(), } + } - match self.state { - State::DcsPassthrough => performer.unhook(), - State::OscString => { - let param_idx = self.osc_num_params; - let idx = self.osc_raw.len(); - - match param_idx { - // Finish last parameter if not already maxed - MAX_OSC_PARAMS => (), - - // First param is special - 0 to current byte index - 0 => { - self.osc_params[param_idx] = (0, idx); - self.osc_num_params += 1; - }, + #[inline(always)] + fn advance_csi_entry<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::CsiIntermediate + }, + 0x30..=0x39 => { + self.action_paramnext(byte); + self.state = State::CsiParam + }, + 0x3A => { + self.action_subparam(); + self.state = State::CsiParam + }, + 0x3B => { + self.action_param(); + self.state = State::CsiParam + }, + 0x3C..=0x3F => { + self.action_collect(byte); + self.state = State::CsiParam + }, + 0x40..=0x7E => self.action_csi_dispatch(performer, byte), + _ => self.anywhere(performer, byte), + } + } - // All other params depend on previous indexing - _ => { - let prev = self.osc_params[param_idx - 1]; - let begin = prev.1; - self.osc_params[param_idx] = (begin, idx); - self.osc_num_params += 1; - }, - } - self.osc_dispatch(performer, byte); + #[inline(always)] + fn advance_csi_ignore<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x3F => (), + 0x40..=0x7E => self.state = State::Ground, + 0x7F => (), + _ => self.anywhere(performer, byte), + } + } + + #[inline(always)] + fn advance_csi_intermediate<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => self.action_collect(byte), + 0x30..=0x3F => self.state = State::CsiIgnore, + 0x40..=0x7E => self.action_csi_dispatch(performer, byte), + _ => self.anywhere(performer, byte), + } + } + + #[inline(always)] + fn advance_csi_param<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::CsiIntermediate }, - _ => (), + 0x30..=0x39 => self.action_paramnext(byte), + 0x3A => self.action_subparam(), + 0x3B => self.action_param(), + 0x3C..=0x3F => self.state = State::CsiIgnore, + 0x40..=0x7E => self.action_csi_dispatch(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), } + } - if action == Action::None { - match state { - State::CsiEntry | State::DcsEntry | State::Escape => self.reset_params(), - State::DcsPassthrough => { - if self.params.is_full() { - self.ignoring = true; - } else { - self.params.push(self.param); - } + #[inline(always)] + fn advance_dcs_entry<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::DcsIntermediate + }, + 0x30..=0x39 => { + self.action_paramnext(byte); + self.state = State::DcsParam + }, + 0x3A => { + self.action_subparam(); + self.state = State::DcsParam + }, + 0x3B => { + self.action_param(); + self.state = State::DcsParam + }, + 0x3C..=0x3F => { + self.action_collect(byte); + self.state = State::DcsParam + }, + 0x40..=0x7E => self.action_hook(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), + } + } - performer.hook( - self.params(), - self.intermediates(), - self.ignoring, - byte as char, - ); - }, - State::OscString => { - self.osc_raw.clear(); - self.osc_num_params = 0; - }, - _ => (), - } - } else { - self.perform_action(performer, action, byte); + #[inline(always)] + fn advance_dcs_intermediate<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x20..=0x2F => self.action_collect(byte), + 0x30..=0x3F => self.state = State::DcsIgnore, + 0x40..=0x7E => self.action_hook(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), } + } - self.state = state; + #[inline(always)] + fn advance_dcs_param<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::DcsIntermediate + }, + 0x30..=0x39 => self.action_paramnext(byte), + 0x3A => self.action_subparam(), + 0x3B => self.action_param(), + 0x3C..=0x3F => self.state = State::DcsIgnore, + 0x40..=0x7E => self.action_hook(performer, byte), + 0x7F => (), + _ => self.anywhere(performer, byte), + } } - #[inline] - fn perform_action<P: Perform>(&mut self, performer: &mut P, action: Action, byte: u8) { - match action { - Action::Execute => performer.execute(byte), - Action::Put => performer.put(byte), - Action::OscPut => { + #[inline(always)] + fn advance_dcs_passthrough<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x7E => performer.put(byte), + 0x18 | 0x1A => { + performer.unhook(); + performer.execute(byte); + self.state = State::Ground + }, + 0x1B => { + performer.unhook(); + self.reset_params(); + self.state = State::Escape + }, + 0x7F => (), + 0x9C => { + performer.unhook(); + self.state = State::Ground + }, + _ => (), + } + } + + #[inline(always)] + fn advance_esc<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => { + self.action_collect(byte); + self.state = State::EscapeIntermediate + }, + 0x30..=0x4F => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x50 => { + self.reset_params(); + self.state = State::DcsEntry + }, + 0x51..=0x57 => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x58 => self.state = State::SosPmApcString, + 0x59..=0x5A => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x5B => { + self.reset_params(); + self.state = State::CsiEntry + }, + 0x5C => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x5D => { + self.osc_raw.clear(); + self.osc_num_params = 0; + self.state = State::OscString + }, + 0x5E..=0x5F => self.state = State::SosPmApcString, + 0x60..=0x7E => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + // Anywhere. + 0x18 | 0x1A => { + performer.execute(byte); + self.state = State::Ground + }, + 0x1B => (), + _ => (), + } + } + + #[inline(always)] + fn advance_esc_intermediate<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => performer.execute(byte), + 0x20..=0x2F => self.action_collect(byte), + 0x30..=0x7E => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + self.state = State::Ground + }, + 0x7F => (), + _ => self.anywhere(performer, byte), + } + } + + #[inline(always)] + fn advance_osc_string<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x00..=0x06 | 0x08..=0x17 | 0x19 | 0x1C..=0x1F => (), + 0x07 => { + self.osc_end(performer, byte); + self.state = State::Ground + }, + 0x18 | 0x1A => { + self.osc_end(performer, byte); + performer.execute(byte); + self.state = State::Ground + }, + 0x1B => { + self.osc_end(performer, byte); + self.reset_params(); + self.state = State::Escape + }, + 0x3B => { #[cfg(feature = "no_std")] { if self.osc_raw.is_full() { return; } } - - let idx = self.osc_raw.len(); - - // Param separator - if byte == b';' { - let param_idx = self.osc_num_params; - match param_idx { - // Only process up to MAX_OSC_PARAMS - MAX_OSC_PARAMS => return, - - // First param is special - 0 to current byte index - 0 => { - self.osc_params[param_idx] = (0, idx); - }, - - // All other params depend on previous indexing - _ => { - let prev = self.osc_params[param_idx - 1]; - let begin = prev.1; - self.osc_params[param_idx] = (begin, idx); - }, - } - - self.osc_num_params += 1; - } else { - self.osc_raw.push(byte); - } + self.action_osc_put_param() }, - Action::CsiDispatch => { - if self.params.is_full() { - self.ignoring = true; - } else { - self.params.push(self.param); - } + _ => self.action_osc_put(byte), + } + } - performer.csi_dispatch( - self.params(), - self.intermediates(), - self.ignoring, - byte as char, - ); - }, - Action::EscDispatch => { - performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + #[inline(always)] + fn anywhere<P: Perform>(&mut self, performer: &mut P, byte: u8) { + match byte { + 0x18 | 0x1A => { + performer.execute(byte); + self.state = State::Ground }, - Action::Collect => { - if self.intermediate_idx == MAX_INTERMEDIATES { - self.ignoring = true; - } else { - self.intermediates[self.intermediate_idx] = byte; - self.intermediate_idx += 1; - } + 0x1B => { + self.reset_params(); + self.state = State::Escape }, - Action::Param => { - if self.params.is_full() { - self.ignoring = true; - return; - } + _ => (), + } + } - match byte { - b';' => { - self.params.push(self.param); - self.param = 0; - }, - b':' => { - self.params.extend(self.param); - self.param = 0; - }, - _ => { - // Continue collecting bytes into param - self.param = self.param.saturating_mul(10); - self.param = self.param.saturating_add((byte - b'0') as u16); - }, - } + #[inline] + fn action_csi_dispatch<P: Perform>(&mut self, performer: &mut P, byte: u8) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + } + performer.csi_dispatch(self.params(), self.intermediates(), self.ignoring, byte as char); + + self.state = State::Ground + } + + #[inline] + fn action_hook<P: Perform>(&mut self, performer: &mut P, byte: u8) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + } + performer.hook(self.params(), self.intermediates(), self.ignoring, byte as char); + self.state = State::DcsPassthrough; + } + + #[inline] + fn action_collect(&mut self, byte: u8) { + if self.intermediate_idx == MAX_INTERMEDIATES { + self.ignoring = true; + } else { + self.intermediates[self.intermediate_idx] = byte; + self.intermediate_idx += 1; + } + } + + /// Advance to the next subparameter. + #[inline] + fn action_subparam(&mut self) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.extend(self.param); + self.param = 0; + } + } + + /// Advance to the next parameter. + #[inline] + fn action_param(&mut self) { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + self.param = 0; + } + } + + /// Advance inside the parameter without terminating it. + #[inline] + fn action_paramnext(&mut self, byte: u8) { + if self.params.is_full() { + self.ignoring = true; + } else { + // Continue collecting bytes into param. + self.param = self.param.saturating_mul(10); + self.param = self.param.saturating_add((byte - b'0') as u16); + } + } + + /// Add OSC param separator. + #[inline] + fn action_osc_put_param(&mut self) { + let idx = self.osc_raw.len(); + + let param_idx = self.osc_num_params; + match param_idx { + // First param is special - 0 to current byte index. + 0 => self.osc_params[param_idx] = (0, idx), + + // Only process up to MAX_OSC_PARAMS. + MAX_OSC_PARAMS => return, + + // All other params depend on previous indexing. + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); }, - _ => (), } + + self.osc_num_params += 1; + } + + #[inline(always)] + fn action_osc_put(&mut self, byte: u8) { + #[cfg(feature = "no_std")] + { + if self.osc_raw.is_full() { + return; + } + } + self.osc_raw.push(byte); + } + + fn osc_end<P: Perform>(&mut self, performer: &mut P, byte: u8) { + self.action_osc_put_param(); + self.osc_dispatch(performer, byte); + self.osc_raw.clear(); + self.osc_num_params = 0; } /// Reset escape sequence parameters and intermediates. @@ -504,6 +729,25 @@ impl<const OSC_RAW_BUF_SIZE: usize> Parser<OSC_RAW_BUF_SIZE> { } } +#[derive(PartialEq, Eq, Debug, Default, Copy, Clone)] +enum State { + CsiEntry, + CsiIgnore, + CsiIntermediate, + CsiParam, + DcsEntry, + DcsIgnore, + DcsIntermediate, + DcsParam, + DcsPassthrough, + Escape, + EscapeIntermediate, + OscString, + SosPmApcString, + #[default] + Ground, +} + /// Performs actions requested by the Parser /// /// Actions in this case mean, for example, handling a CSI escape sequence |