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