1pub struct Output<const CAPACITY: usize> {
12 pub bytes: [u8; CAPACITY],
14 pub length: usize,
16}
17
18impl<const CAPACITY: usize> Default for Output<CAPACITY> {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl<const CAPACITY: usize> Output<CAPACITY> {
25 pub const fn new() -> Self {
27 Self {
28 bytes: [0u8; CAPACITY],
29 length: 0,
30 }
31 }
32
33 const fn put_byte(&mut self, byte: u8) {
34 if CAPACITY > 0 {
35 self.bytes[self.length] = byte;
36 }
37 self.length += 1;
38 }
39
40 pub const fn put(&mut self, text: &str) {
42 let bytes = text.as_bytes();
43 let mut index = 0;
44 while index < bytes.len() {
45 self.put_byte(bytes[index]);
46 index += 1;
47 }
48 }
49
50 pub const fn put_usize(&mut self, value: usize) {
52 if value >= 10 {
53 self.put_usize(value / 10);
54 }
55 self.put_byte(b'0' + (value % 10) as u8);
56 }
57
58 pub const fn put_quoted(&mut self, text: &str) {
61 self.put_byte(b'"');
62 let bytes = text.as_bytes();
63 let mut index = 0;
64 while index < bytes.len() {
65 let byte = bytes[index];
66 if byte == b'"' || byte == b'\\' {
67 self.put_byte(b'\\');
68 }
69 self.put_byte(byte);
70 index += 1;
71 }
72 self.put_byte(b'"');
73 }
74
75 pub const fn put_ident(&mut self, name: &str) {
77 self.put(name);
78 if is_reserved(name) {
79 self.put("_");
80 }
81 }
82
83 pub const fn put_quoted_ident(&mut self, name: &str) {
85 self.put_byte(b'"');
86 self.put_ident(name);
87 self.put_byte(b'"');
88 }
89
90 pub const fn indent(&mut self, count: usize) {
92 let mut level = 0;
93 while level < count {
94 self.put(" ");
95 level += 1;
96 }
97 }
98}
99
100pub const fn str_eq(left: &str, right: &str) -> bool {
102 let left = left.as_bytes();
103 let right = right.as_bytes();
104 if left.len() != right.len() {
105 return false;
106 }
107 let mut index = 0;
108 while index < left.len() {
109 if left[index] != right[index] {
110 return false;
111 }
112 index += 1;
113 }
114 true
115}
116
117pub const fn is_ident(text: &str) -> bool {
121 let bytes = text.as_bytes();
122 if bytes.is_empty() {
123 return false;
124 }
125 let mut index = 0;
126 while index < bytes.len() {
127 let byte = bytes[index];
128 let alpha = byte.is_ascii_alphabetic() || byte == b'_' || byte == b'$';
129 let ok = if index == 0 {
130 alpha
131 } else {
132 alpha || byte.is_ascii_digit()
133 };
134 if !ok {
135 return false;
136 }
137 index += 1;
138 }
139 true
140}
141
142const RESERVED: &[&str] = &[
145 "arguments",
146 "await",
147 "break",
148 "case",
149 "catch",
150 "class",
151 "const",
152 "continue",
153 "debugger",
154 "default",
155 "delete",
156 "do",
157 "else",
158 "enum",
159 "eval",
160 "export",
161 "extends",
162 "false",
163 "finally",
164 "for",
165 "function",
166 "if",
167 "implements",
168 "import",
169 "in",
170 "instanceof",
171 "interface",
172 "let",
173 "new",
174 "null",
175 "package",
176 "private",
177 "protected",
178 "public",
179 "return",
180 "static",
181 "super",
182 "switch",
183 "this",
184 "throw",
185 "true",
186 "try",
187 "typeof",
188 "var",
189 "void",
190 "while",
191 "with",
192 "yield",
193];
194
195pub const fn is_reserved(name: &str) -> bool {
197 let mut index = 0;
198 while index < RESERVED.len() {
199 if str_eq(RESERVED[index], name) {
200 return true;
201 }
202 index += 1;
203 }
204 false
205}