1#![allow(clippy::uninlined_format_args)]
4
5use crate::format_type::Field;
6use convert_case::{Case, Casing};
7use serde::Deserialize;
8use std::collections::BTreeMap;
9use std::io::{self, Write};
10use std::path::Path;
11
12mod format_type;
13
14#[derive(Deserialize)]
15#[cfg_attr(debug_assertions, derive(Debug, Eq, PartialEq))]
16struct EnumFormat {
17 repr: String,
18 #[serde(default)]
19 bitflag: bool,
20 variants: BTreeMap<String, usize>,
21}
22
23impl EnumFormat {
24 pub fn write(&self, name: &str, out: &mut impl Write) -> io::Result<()> {
25 let mut variants = self.variants.iter().collect::<Vec<_>>();
27 variants.sort_unstable_by(|l, r| l.1.cmp(r.1));
28
29 if self.bitflag {
30 writeln!(out, "bitflags::bitflags! {{")?;
31 writeln!(out, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]")?;
32 writeln!(out, "pub struct {}: {} {{", name, self.repr)?;
33 for (name, variant) in variants.iter() {
34 writeln!(
35 out,
36 "const {} = {};",
37 name.to_case(Case::UpperSnake),
38 variant
39 )?;
40 }
41 writeln!(out, "}}")?;
42
43 writeln!(out, "}}")?;
44 } else {
45 writeln!(out, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]")?;
46 writeln!(out, "#[repr({})]", self.repr)?;
47 writeln!(out, "pub enum {} {{", name)?;
48
49 for (name, variant) in variants.iter() {
50 writeln!(out, "{} = {},", name, variant)?;
51 }
52 writeln!(out, "}}")?;
53 }
54
55 writeln!(out, "impl XimRead for {} {{", name)?;
56
57 writeln!(
58 out,
59 "fn read(reader: &mut Reader) -> Result<Self, ReadError> {{ let repr = {}::read(reader)?;", self.repr)?;
60
61 if self.bitflag {
62 writeln!(
63 out,
64 "Self::from_bits(repr).ok_or_else(|| reader.invalid_data(\"{}\", repr))",
65 name
66 )?;
67 } else {
68 writeln!(out, "match repr {{")?;
69 for (name, variants) in variants.iter() {
70 writeln!(out, "{v} => Ok(Self::{n}),", v = variants, n = name)?;
71 }
72
73 writeln!(
74 out,
75 "_ => Err(reader.invalid_data(\"{n}\", repr)),",
76 n = name
77 )?;
78
79 writeln!(out, "}}")?;
80 }
81
82 writeln!(out, "}}")?;
83
84 writeln!(out, "}}")?;
86
87 writeln!(out, "impl XimWrite for {} {{", name)?;
88
89 writeln!(out, "fn write(&self, writer: &mut Writer) {{")?;
90
91 if self.bitflag {
92 writeln!(out, "self.bits().write(writer);")?;
93 } else {
94 writeln!(out, "(*self as {}).write(writer);", self.repr)?;
95 }
96
97 writeln!(out, "}}")?;
98
99 writeln!(
100 out,
101 "fn size(&self) -> usize {{ core::mem::size_of::<{}>() }}",
102 self.repr
103 )?;
104
105 writeln!(out, "}}")?;
107
108 Ok(())
109 }
110}
111
112#[derive(Deserialize)]
113#[cfg_attr(debug_assertions, derive(Debug, Eq, PartialEq))]
114struct RequestFormat {
115 major_opcode: u8,
116 minor_opcode: Option<u8>,
117 body: Vec<Field>,
118}
119
120#[derive(Deserialize)]
121#[cfg_attr(debug_assertions, derive(Debug, Eq, PartialEq))]
122#[serde(transparent)]
123struct StructFormat {
124 body: Vec<Field>,
125}
126
127impl StructFormat {
128 pub fn write(&self, name: &str, out: &mut impl Write) -> io::Result<()> {
129 writeln!(out, "#[derive(Clone, Debug, Eq, PartialEq)]")?;
130 write!(out, "pub struct {}", name)?;
131 writeln!(out, "{{")?;
132
133 for field in self.body.iter() {
134 writeln!(out, "pub {}: {},", field.name, field.ty)?;
135 }
136
137 writeln!(out, "}}")?;
138
139 writeln!(out, "impl XimRead for {} {{", name)?;
140
141 writeln!(
142 out,
143 "fn read(reader: &mut Reader) -> Result<Self, ReadError> {{"
144 )?;
145
146 writeln!(out, "Ok(Self {{")?;
147 for field in self.body.iter() {
148 write!(out, "{}: ", field.name)?;
149 field.ty.read(out)?;
150 write!(out, ",")?;
151 }
152 writeln!(out, "}})")?;
153
154 writeln!(out, "}}")?;
156 writeln!(out, "}}")?;
158
159 writeln!(out, "impl XimWrite for {} {{", name)?;
160 writeln!(out, "fn write(&self, writer: &mut Writer) {{")?;
161 for field in self.body.iter() {
162 field.ty.write(&format!("self.{}", field.name), out)?;
163 }
164 writeln!(out, "}}")?;
166
167 writeln!(out, "fn size(&self) -> usize {{")?;
168 writeln!(out, "let mut content_size = 0;")?;
169
170 for field in self.body.iter() {
171 write!(out, "content_size += ")?;
172 field.ty.size(&format!("self.{}", field.name), out)?;
173 writeln!(out, ";")?;
174 }
175
176 writeln!(out, "content_size")?;
177
178 writeln!(out, "}}")?;
180
181 writeln!(out, "}}")?;
183
184 Ok(())
185 }
186}
187
188#[derive(Deserialize)]
189#[cfg_attr(debug_assertions, derive(Debug, Eq, PartialEq))]
190struct XimFormat {
191 #[serde(rename = "Enums")]
192 enums: BTreeMap<String, EnumFormat>,
193 #[serde(rename = "AttributeNames")]
194 attribute_names: BTreeMap<String, String>,
195 #[serde(rename = "Structs")]
196 structs: BTreeMap<String, StructFormat>,
197 #[serde(rename = "Requests")]
198 requests: BTreeMap<String, RequestFormat>,
199}
200
201impl XimFormat {
202 pub fn write(&self, out: &mut impl Write) -> io::Result<()> {
203 for (name, em) in self.enums.iter() {
204 em.write(name, out)?;
205 }
206
207 for (name, st) in self.structs.iter() {
208 st.write(name, out)?;
209 }
210
211 writeln!(
212 out,
213 "#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]"
214 )?;
215 writeln!(out, "pub enum AttributeName {{")?;
216 for (key, _value) in self.attribute_names.iter() {
217 writeln!(out, "{},", key)?;
218 }
219 writeln!(out, "}}")?;
220
221 writeln!(out, "impl AttributeName {{")?;
222 writeln!(out, "pub fn name(self) -> &'static str {{")?;
223 writeln!(out, "match self {{")?;
224 for (key, value) in self.attribute_names.iter() {
225 writeln!(out, "Self::{} => \"{}\",", key, value)?;
226 }
227 writeln!(out, "}}")?;
229 writeln!(out, "}}")?;
231 writeln!(out, "}}")?;
233
234 writeln!(out, "impl XimRead for AttributeName {{")?;
235 writeln!(
236 out,
237 "fn read(reader: &mut Reader) -> Result<Self, ReadError> {{"
238 )?;
239 writeln!(
240 out,
241 "let len = u16::read(reader)?; match reader.consume(len as usize)? {{"
242 )?;
243 for (key, value) in self.attribute_names.iter() {
244 writeln!(out, "b\"{}\" => Ok(Self::{}),", value, key)?;
245 }
246 writeln!(out, "bytes => Err(reader.invalid_data(\"AttributeName\", core::str::from_utf8(bytes).unwrap_or(\"NOT_UTF8\"))),")?;
247 writeln!(out, "}}")?;
249 writeln!(out, "}}")?;
251 writeln!(out, "}}")?;
253
254 writeln!(out, "impl XimWrite for AttributeName {{")?;
255
256 writeln!(out, "fn write(&self, writer: &mut Writer) {{")?;
257 writeln!(out, "let name = self.name(); (name.len() as u16).write(writer); writer.write(name.as_bytes());")?;
258 writeln!(out, "}}")?;
260
261 writeln!(out, "fn size(&self) -> usize {{")?;
262 writeln!(out, "self.name().len() + 2")?;
263 writeln!(out, "}}")?;
265
266 writeln!(out, "}}")?;
268
269 writeln!(out, "#[derive(Debug, Clone, Eq, PartialEq)]")?;
270 writeln!(out, "pub enum Request {{")?;
271
272 for (name, req) in self.requests.iter() {
273 writeln!(out, "{} {{", name)?;
274 for field in req.body.iter() {
275 writeln!(out, "{}: {},", field.name, field.ty)?;
276 }
277 writeln!(out, "}},")?;
278 }
279
280 writeln!(out, "}}")?;
281
282 writeln!(out, "impl Request {{")?;
283 writeln!(out, "pub fn name(&self) -> &'static str {{")?;
284 writeln!(out, "match self {{")?;
285 for (name, _req) in self.requests.iter() {
286 writeln!(out, "Request::{} {{ .. }} => \"{}\",", name, name)?;
287 }
288 writeln!(out, "}}")?;
290 writeln!(out, "}}")?;
292 writeln!(out, "}}")?;
294
295 writeln!(out, "impl XimRead for Request {{")?;
296
297 writeln!(
298 out,
299 "fn read(reader: &mut Reader) -> Result<Self, ReadError> {{"
300 )?;
301
302 writeln!(
303 out,
304 "let major_opcode = reader.u8()?; let minor_opcode = reader.u8()?; let _length = reader.u16()?;"
305 )?;
306
307 writeln!(out, "match (major_opcode, minor_opcode) {{")?;
308
309 for (name, req) in self.requests.iter() {
310 write!(out, "({}, ", req.major_opcode)?;
311
312 if let Some(minor) = req.minor_opcode {
313 write!(out, "{}", minor)?;
314 } else {
315 write!(out, "_")?;
316 }
317
318 writeln!(out, ") => Ok(Request::{} {{", name)?;
319 for field in req.body.iter() {
320 write!(out, "{}: ", field.name)?;
321 field.ty.read(out)?;
322 write!(out, ",")?;
323 }
324 writeln!(out, "}}),")?;
325 }
326
327 writeln!(out, "_ => Err(reader.invalid_data(\"Opcode\", alloc::format!(\"({{}}, {{}})\", major_opcode, minor_opcode))),")?;
328
329 writeln!(out, "}}")?;
331
332 writeln!(out, "}}")?;
334
335 writeln!(out, "}}")?;
337
338 writeln!(out, "impl XimWrite for Request {{")?;
339
340 writeln!(out, "fn write(&self, writer: &mut Writer) {{")?;
341
342 writeln!(out, "match self {{")?;
343
344 for (name, req) in self.requests.iter() {
345 writeln!(out, "Request::{} {{", name)?;
346 for field in req.body.iter() {
347 write!(out, "{}, ", field.name)?;
348 }
349 writeln!(out, "}} => {{")?;
350
351 writeln!(out, "{}u8.write(writer);", req.major_opcode)?;
352 writeln!(out, "{}u8.write(writer);", req.minor_opcode.unwrap_or(0))?;
353 writeln!(out, "(((self.size() - 4) / 4) as u16).write(writer);")?;
354
355 for field in req.body.iter() {
356 field.ty.write(&field.name, out)?;
357 }
358
359 writeln!(out, "}}")?;
360 }
361
362 writeln!(out, "}}")?;
364
365 writeln!(out, "}}")?;
367
368 writeln!(out, "fn size(&self) -> usize {{")?;
369 writeln!(out, "let mut content_size = 0;")?;
370
371 writeln!(out, "match self {{")?;
372
373 for (name, req) in self.requests.iter() {
374 writeln!(out, "Request::{} {{", name)?;
375 for field in req.body.iter() {
376 write!(out, "{}, ", field.name)?;
377 }
378 writeln!(out, "}} => {{")?;
379
380 for field in req.body.iter() {
381 write!(out, "content_size += ")?;
382 field.ty.size(&field.name, out)?;
383 writeln!(out, ";")?;
384 }
385
386 writeln!(out, "}}")?;
387 }
388
389 writeln!(out, "}}")?;
391 writeln!(out, "content_size + 4")?;
392
393 writeln!(out, "}}")?;
395
396 writeln!(out, "}}")?;
398
399 Ok(())
400 }
401}
402
403pub fn write_format(
404 format_str: &str,
405 out_path: impl AsRef<Path>,
406) -> Result<(), Box<dyn std::error::Error>> {
407 let format: XimFormat = serde_yaml::from_str(format_str)?;
408
409 let mut file = std::io::BufWriter::new(std::fs::File::create(out_path.as_ref())?);
410
411 file.write_all(include_bytes!("../res/snippet.rs"))?;
412 format.write(&mut file)?;
413 file.flush()?;
414
415 let rustfmt = std::process::Command::new("rustfmt")
416 .arg(std::fs::canonicalize(out_path.as_ref())?)
417 .spawn()
418 .expect("call rustfmt")
419 .wait()
420 .unwrap();
421
422 assert!(rustfmt.success());
423
424 Ok(())
425}