vt_push_parser/
ascii.rs

1macro_rules! ascii_control {
2    ($(($variant:ident, $value:expr)),* $(,)?) => {
3        /// ASCII control codes.
4        #[repr(u8)]
5        pub enum AsciiControl {
6            $( $variant = $value, )*
7        }
8
9        impl std::fmt::Display for AsciiControl {
10            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11                match self {
12                    $( AsciiControl::$variant => write!(f, "<{}>", stringify!($variant).to_ascii_uppercase()), )*
13                }
14            }
15        }
16
17        impl std::fmt::Debug for AsciiControl {
18            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19                match self {
20                    $( AsciiControl::$variant => write!(f, "<{}>", stringify!($variant).to_ascii_uppercase()), )*
21                }
22            }
23        }
24
25        impl TryFrom<u8> for AsciiControl {
26            type Error = ();
27            fn try_from(value: u8) -> Result<Self, Self::Error> {
28                $(
29                    if value == $value {
30                        return Ok(AsciiControl::$variant);
31                    }
32                )*
33                Err(())
34            }
35        }
36
37        impl TryFrom<char> for AsciiControl {
38            type Error = ();
39            fn try_from(value: char) -> Result<Self, Self::Error> {
40                $(
41                    if value == char::from($value) {
42                        return Ok(AsciiControl::$variant);
43                    }
44                )*
45                Err(())
46            }
47        }
48
49        impl std::str::FromStr for AsciiControl {
50            type Err = ();
51            fn from_str(s: &str) -> Result<Self, Self::Err> {
52                $(
53                    if s.eq_ignore_ascii_case(stringify!($name)) {
54                        return Ok(AsciiControl::$variant);
55                    }
56                )*
57                Err(())
58            }
59        }
60    };
61}
62
63ascii_control! {
64    (Nul, 0),
65    (Soh, 1),
66    (Stx, 2),
67    (Etx, 3),
68    (Eot, 4),
69    (Enq, 5),
70    (Ack, 6),
71    (Bel, 7),
72    (Bs, 8),
73    (Tab, 9),
74    (Lf, 10),
75    (Vt, 11),
76    (Ff, 12),
77    (Cr, 13),
78    (So, 14 ),
79    (Si, 15),
80    (Dle, 16),
81    (Dc1, 17),
82    (Dc2, 18),
83    (Dc3, 19),
84    (Dc4, 20),
85    (Nak, 21),
86    (Syn, 22),
87    (Etb, 23),
88    (Can, 24),
89    (Em, 25),
90    (Sub, 26),
91    (Esc, 27),
92    (Fs, 28),
93    (Gs, 29),
94    (Rs, 30),
95    (Us, 31),
96    (Del, 127),
97}
98
99#[doc(hidden)]
100pub fn decode_string(input: &str) -> Vec<u8> {
101    let mut result = Vec::new();
102    let mut chars = input.chars().peekable();
103
104    while let Some(ch) = chars.next() {
105        if ch == '<' {
106            // Collect characters until '>'
107            let mut control_name = String::new();
108            while let Some(ch) = chars.next() {
109                if ch == '>' {
110                    break;
111                }
112                control_name.push(ch);
113            }
114
115            // Parse the control name and convert to byte
116            match control_name.to_uppercase().as_str() {
117                "NUL" => result.push(0),
118                "SOH" => result.push(1),
119                "STX" => result.push(2),
120                "ETX" => result.push(3),
121                "EOT" => result.push(4),
122                "ENQ" => result.push(5),
123                "ACK" => result.push(6),
124                "BEL" => result.push(7),
125                "BS" => result.push(8),
126                "TAB" => result.push(9),
127                "LF" => result.push(10),
128                "VT" => result.push(11),
129                "FF" => result.push(12),
130                "CR" => result.push(13),
131                "SO" => result.push(14),
132                "SI" => result.push(15),
133                "DLE" => result.push(16),
134                "DC1" => result.push(17),
135                "DC2" => result.push(18),
136                "DC3" => result.push(19),
137                "DC4" => result.push(20),
138                "NAK" => result.push(21),
139                "SYN" => result.push(22),
140                "ETB" => result.push(23),
141                "CAN" => result.push(24),
142                "EM" => result.push(25),
143                "SUB" => result.push(26),
144                "ESC" => result.push(27),
145                "FS" => result.push(28),
146                "GS" => result.push(29),
147                "RS" => result.push(30),
148                "US" => result.push(31),
149                "DEL" => result.push(127),
150                _ => {
151                    // If not a recognized control code, treat as literal text
152                    result.push(b'<');
153                    result.extend_from_slice(control_name.as_bytes());
154                    result.push(b'>');
155                }
156            }
157        } else {
158            // Regular character, convert to byte
159            let mut buf = [0; 4];
160            let char_bytes = ch.encode_utf8(&mut buf);
161            result.extend_from_slice(char_bytes.as_bytes());
162        }
163    }
164
165    result
166}
167
168#[doc(hidden)]
169pub fn encode_string(bytes: &[u8]) -> String {
170    use std::fmt::Write;
171    let mut s = String::new();
172    for chunk in bytes.utf8_chunks() {
173        for c in chunk.valid().chars() {
174            if let Ok(c) = AsciiControl::try_from(c) {
175                write!(s, "{}", c).unwrap();
176            } else {
177                write!(s, "{}", c).unwrap();
178            }
179        }
180        if !chunk.invalid().is_empty() {
181            write!(s, "<{}>", hex::encode(chunk.invalid())).unwrap();
182        }
183    }
184    s
185}