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