anstyle_parse/state/
definitions.rs

1#![allow(clippy::exhaustive_enums)]
2
3use core::mem;
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6#[repr(u8)]
7#[derive(Default)]
8pub enum State {
9    Anywhere = 0,
10    CsiEntry = 1,
11    CsiIgnore = 2,
12    CsiIntermediate = 3,
13    CsiParam = 4,
14    DcsEntry = 5,
15    DcsIgnore = 6,
16    DcsIntermediate = 7,
17    DcsParam = 8,
18    DcsPassthrough = 9,
19    Escape = 10,
20    EscapeIntermediate = 11,
21    #[default]
22    Ground = 12,
23    OscString = 13,
24    SosPmApcString = 14,
25    Utf8 = 15,
26}
27
28impl TryFrom<u8> for State {
29    type Error = u8;
30
31    #[inline(always)]
32    fn try_from(raw: u8) -> Result<Self, Self::Error> {
33        STATES.get(raw as usize).ok_or(raw).copied()
34    }
35}
36
37const STATES: [State; 16] = [
38    State::Anywhere,
39    State::CsiEntry,
40    State::CsiIgnore,
41    State::CsiIntermediate,
42    State::CsiParam,
43    State::DcsEntry,
44    State::DcsIgnore,
45    State::DcsIntermediate,
46    State::DcsParam,
47    State::DcsPassthrough,
48    State::Escape,
49    State::EscapeIntermediate,
50    State::Ground,
51    State::OscString,
52    State::SosPmApcString,
53    State::Utf8,
54];
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57#[repr(u8)]
58#[derive(Default)]
59pub enum Action {
60    #[default]
61    Nop = 0,
62    Clear = 1,
63    Collect = 2,
64    CsiDispatch = 3,
65    EscDispatch = 4,
66    Execute = 5,
67    Hook = 6,
68    Ignore = 7,
69    OscEnd = 8,
70    OscPut = 9,
71    OscStart = 10,
72    Param = 11,
73    Print = 12,
74    Put = 13,
75    Unhook = 14,
76    BeginUtf8 = 15,
77}
78
79impl TryFrom<u8> for Action {
80    type Error = u8;
81
82    #[inline(always)]
83    fn try_from(raw: u8) -> Result<Self, Self::Error> {
84        ACTIONS.get(raw as usize).ok_or(raw).copied()
85    }
86}
87
88const ACTIONS: [Action; 16] = [
89    Action::Nop,
90    Action::Clear,
91    Action::Collect,
92    Action::CsiDispatch,
93    Action::EscDispatch,
94    Action::Execute,
95    Action::Hook,
96    Action::Ignore,
97    Action::OscEnd,
98    Action::OscPut,
99    Action::OscStart,
100    Action::Param,
101    Action::Print,
102    Action::Put,
103    Action::Unhook,
104    Action::BeginUtf8,
105];
106
107/// Unpack a u8 into a State and Action
108///
109/// The implementation of this assumes that there are *precisely* 16 variants for both Action and
110/// State. Furthermore, it assumes that the enums are tag-only; that is, there is no data in any
111/// variant.
112///
113/// Bad things will happen if those invariants are violated.
114#[inline(always)]
115pub(crate) const fn unpack(delta: u8) -> (State, Action) {
116    unsafe {
117        (
118            // State is stored in bottom 4 bits
119            mem::transmute::<u8, State>(delta & 0x0f),
120            // Action is stored in top 4 bits
121            mem::transmute::<u8, Action>(delta >> 4),
122        )
123    }
124}
125
126#[inline(always)]
127#[cfg(test)]
128pub(crate) const fn pack(state: State, action: Action) -> u8 {
129    (action as u8) << 4 | state as u8
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn unpack_state_action() {
138        match unpack(0xee) {
139            (State::SosPmApcString, Action::Unhook) => (),
140            _ => panic!("unpack failed"),
141        }
142
143        match unpack(0x0f) {
144            (State::Utf8, Action::Nop) => (),
145            _ => panic!("unpack failed"),
146        }
147
148        match unpack(0xff) {
149            (State::Utf8, Action::BeginUtf8) => (),
150            _ => panic!("unpack failed"),
151        }
152    }
153
154    #[test]
155    fn pack_state_action() {
156        match unpack(0xee) {
157            (State::SosPmApcString, Action::Unhook) => (),
158            _ => panic!("unpack failed"),
159        }
160
161        match unpack(0x0f) {
162            (State::Utf8, Action::Nop) => (),
163            _ => panic!("unpack failed"),
164        }
165
166        match unpack(0xff) {
167            (State::Utf8, Action::BeginUtf8) => (),
168            _ => panic!("unpack failed"),
169        }
170    }
171}