aboutsummaryrefslogtreecommitdiff
path: root/src/definitions.rs
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2025-01-09 06:27:15 +0000
committerGitHub <noreply@github.com>2025-01-09 06:27:15 +0000
commit7321a442a6fc0fc5b6d6ed7af364477d25e706fd (patch)
tree11ff2608e63a160b8b204b6f78ec3977f019d081 /src/definitions.rs
parent89c12df969145ffb5084d1122627d7292c2c638f (diff)
downloadr-alacritty-vte-7321a442a6fc0fc5b6d6ed7af364477d25e706fd.tar.gz
r-alacritty-vte-7321a442a6fc0fc5b6d6ed7af364477d25e706fd.tar.bz2
r-alacritty-vte-7321a442a6fc0fc5b6d6ed7af364477d25e706fd.zip
Switch parser to multi-byte processing
This patch overhauls the `Parser::advance` API to operate on byte slices instead of individual bytes, which allows for additional performance optimizations. VTE does not support C1 escapes and C0 escapes always start with an escape character. This makes it possible to simplify processing if a byte stream is determined to not contain any escapes. The `memchr` crate provides a battle-tested implementation for SIMD-accelerated byte searches, which is why this implementation makes use of it. VTE also only supports UTF8 characters in the ground state, which means that the new non-escape parsing path is able to rely completely on STD's `str::from_utf8` since `memchr` gives us the full length of the plain text character buffer. This allows us to completely remove `utf8parse` and all related code. We also make use of `memchr` in the synchronized escape handling in `ansi.rs`, since it relies heavily on scanning large amounts of text for the extension/termination escape sequences.
Diffstat (limited to 'src/definitions.rs')
-rw-r--r--src/definitions.rs104
1 files changed, 46 insertions, 58 deletions
diff --git a/src/definitions.rs b/src/definitions.rs
index 568a8a8..694c783 100644
--- a/src/definitions.rs
+++ b/src/definitions.rs
@@ -2,54 +2,53 @@ use core::mem;
#[allow(dead_code)]
#[repr(u8)]
-#[derive(Debug, Default, Copy, Clone)]
+#[derive(PartialEq, Eq, Debug, Default, Copy, Clone)]
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,
+ CsiEntry,
+ CsiIgnore,
+ CsiIntermediate,
+ CsiParam,
+ DcsEntry,
+ DcsIgnore,
+ DcsIntermediate,
+ DcsParam,
+ DcsPassthrough,
+ Escape,
+ EscapeIntermediate,
+ OscString,
+ SosPmApcString,
+ Anywhere,
#[default]
- Ground = 12,
- OscString = 13,
- SosPmApcString = 14,
- Utf8 = 15,
+ Ground,
}
+// NOTE: Removing the unused actions prefixed with `_` will reduce performance.
#[allow(dead_code)]
#[repr(u8)]
-#[derive(Debug, Clone, Copy)]
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
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,
- BeginUtf8 = 15,
+ None,
+ _Clear,
+ Collect,
+ CsiDispatch,
+ EscDispatch,
+ Execute,
+ _Hook,
+ _Ignore,
+ _OscEnd,
+ OscPut,
+ _OscStart,
+ Param,
+ _Print,
+ Put,
+ _Unhook,
}
/// 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.
+/// 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)]
@@ -57,7 +56,7 @@ pub fn unpack(delta: u8) -> (State, Action) {
unsafe {
(
// State is stored in bottom 4 bits
- mem::transmute::<u8, State>(delta & 0x0f),
+ mem::transmute::<u8, State>(delta & 0x0F),
// Action is stored in top 4 bits
mem::transmute::<u8, Action>(delta >> 4),
)
@@ -75,37 +74,26 @@ mod tests {
#[test]
fn unpack_state_action() {
- match unpack(0xee) {
- (State::SosPmApcString, Action::Unhook) => (),
+ match unpack(0xEE) {
+ (State::Ground, Action::_Unhook) => (),
_ => panic!("unpack failed"),
}
- match unpack(0x0f) {
- (State::Utf8, Action::None) => (),
+ match unpack(0x0E) {
+ (State::Ground, Action::None) => (),
_ => panic!("unpack failed"),
}
- match unpack(0xff) {
- (State::Utf8, Action::BeginUtf8) => (),
+ match unpack(0xE0) {
+ (State::CsiEntry, Action::_Unhook) => (),
_ => panic!("unpack failed"),
}
}
#[test]
fn pack_state_action() {
- match unpack(0xee) {
- (State::SosPmApcString, Action::Unhook) => (),
- _ => panic!("unpack failed"),
- }
-
- match unpack(0x0f) {
- (State::Utf8, Action::None) => (),
- _ => panic!("unpack failed"),
- }
-
- match unpack(0xff) {
- (State::Utf8, Action::BeginUtf8) => (),
- _ => panic!("unpack failed"),
- }
+ assert_eq!(pack(State::Ground, Action::_Unhook), 0xEE);
+ assert_eq!(pack(State::Ground, Action::None), 0x0E);
+ assert_eq!(pack(State::CsiEntry, Action::_Unhook), 0xE0);
}
}