1 use std::collections::{HashMap, HashSet};
2 use std::env;
3 use std::io::{self, Cursor, Write};
4 
5 use crate::ast::{Doc, EnumItem, Event, Expr, ExtInfo, OpCopyMap, Request, Struct, StructField};
6 use crate::output::Output;
7 
8 mod ffi;
9 mod rs;
10 
11 #[derive(Clone, Debug)]
12 pub struct DepInfo {
13     pub xcb_mod: String,
14     pub xcb_mod_prefix: String,
15     pub imports: Vec<String>,
16     pub typ_with_lifetime: HashSet<String>,
17     pub typ_unions: HashSet<String>,
18     pub typ_simple: HashSet<String>,
19     pub typ_pod: HashSet<String>,
20     pub ffi_type_sizes: HashMap<String, Option<usize>>,
21     pub ffi_typ_reg: HashSet<String>,
22     pub rs_typ_reg: HashSet<String>,
23 }
24 
25 impl DepInfo {
has_type(&self, typ: &str) -> bool26     fn has_type(&self, typ: &str) -> bool {
27         self.ffi_type_sizes.contains_key(typ)
28     }
29 }
30 
31 #[derive(Debug)]
32 pub struct CodeGen {
33     xcb_mod: String,
34     xcb_mod_prefix: String,
35 
36     // output files
37     ffi: Output,
38     rs: Output,
39 
40     // additional output buffers that make a second group of declaration/functions
41     // they are appended to the output at the end
42     ffi_buf: Cursor<Vec<u8>>,
43     rs_buf: Cursor<Vec<u8>>,
44 
45     typ_with_lifetime: HashSet<String>,
46     typ_unions: HashSet<String>,
47     typ_simple: HashSet<String>, // integer, chars, xids, enums
48     typ_pod: HashSet<String>,    // simple and plain old data
49 
50     imports: Vec<String>,
51     // registered types sizes (is None if size is not fixed - eg. lists with dynamic length)
52     ffi_type_sizes: HashMap<String, Option<usize>>,
53     // types registered in the FFI module
54     ffi_typ_reg: HashSet<String>,
55     // types registered in the Rust module
56     rs_typ_reg: HashSet<String>,
57 
58     // keep track of struct declarations to handle typealiases refering to a struct
59     // we could simply issue a `type new = old;`, but for now we want to be diff compatible
60     // with python generated bindings which rewrites a complete new struct.
61     structs: Vec<Struct>,
62 
63     dep_info: Vec<DepInfo>,
64 
65     evcopies: OpCopyMap,
66 
67     ptr_width: usize,
68 }
69 
70 #[cfg(target_pointer_width = "64")]
71 const PTR_WIDTH: usize = 64;
72 #[cfg(target_pointer_width = "32")]
73 const PTR_WIDTH: usize = 32;
74 
75 impl CodeGen {
new( xcb_mod: &str, ffi: Output, rs: Output, dep_info: Vec<DepInfo>, evcopies: OpCopyMap, ) -> CodeGen76     pub fn new(
77         xcb_mod: &str,
78         ffi: Output,
79         rs: Output,
80         dep_info: Vec<DepInfo>,
81         evcopies: OpCopyMap,
82     ) -> CodeGen {
83         let mp = if xcb_mod == "xproto" {
84             String::new()
85         } else {
86             format!("{}_", &xcb_mod)
87         };
88 
89         let ptr_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
90             .map(|s| {
91                 str::parse::<usize>(&s).unwrap_or_else(|_| {
92                     panic!("can't parse CARGO_CFG_TARGET_POINTER_WIDTH {} as usize", s)
93                 })
94             })
95             .unwrap_or(PTR_WIDTH);
96 
97         CodeGen {
98             xcb_mod: xcb_mod.to_owned(),
99             xcb_mod_prefix: mp,
100             ffi,
101             rs,
102             ffi_buf: Cursor::new(Vec::new()),
103             rs_buf: Cursor::new(Vec::new()),
104             imports: Vec::new(),
105             typ_with_lifetime: HashSet::new(),
106             typ_unions: HashSet::new(),
107             typ_simple: HashSet::new(),
108             typ_pod: HashSet::new(),
109             ffi_type_sizes: HashMap::new(),
110             ffi_typ_reg: HashSet::new(),
111             rs_typ_reg: HashSet::new(),
112             structs: Vec::new(),
113             dep_info,
114             evcopies,
115             ptr_width,
116         }
117     }
118 
into_depinfo(self) -> DepInfo119     pub fn into_depinfo(self) -> DepInfo {
120         DepInfo {
121             xcb_mod: self.xcb_mod,
122             xcb_mod_prefix: self.xcb_mod_prefix,
123             imports: self.imports,
124             typ_with_lifetime: self.typ_with_lifetime,
125             typ_unions: self.typ_unions,
126             typ_simple: self.typ_simple,
127             typ_pod: self.typ_pod,
128             ffi_type_sizes: self.ffi_type_sizes,
129             ffi_typ_reg: self.ffi_typ_reg,
130             rs_typ_reg: self.rs_typ_reg,
131         }
132     }
133 
prologue(&mut self, imports: Vec<String>, ext_info: &Option<ExtInfo>) -> io::Result<()>134     pub fn prologue(&mut self, imports: Vec<String>, ext_info: &Option<ExtInfo>) -> io::Result<()> {
135         self.imports = imports;
136         let mut imports = HashSet::<String>::new();
137         for imp in self.imports.iter() {
138             imports.insert(imp.clone());
139         }
140         for di in &self.dep_info {
141             for imp in &di.imports {
142                 imports.insert(imp.clone());
143             }
144         }
145 
146         let out = &mut self.ffi;
147         writeln!(out, "use ffi::base::*;")?;
148         writeln!(out, "use ffi::ext::*;")?;
149         for imp in imports.iter() {
150             writeln!(out, "use ffi::{}::*;", imp)?;
151         }
152         writeln!(out, "use libc::{{c_char, c_int, c_uint, c_void}};")?;
153         writeln!(out, "use std;")?;
154 
155         if let Some(ext_info) = ext_info {
156             let maj_name = ffi::opcode_name(&self.xcb_mod_prefix, "MajorVersion");
157             let min_name = ffi::opcode_name(&self.xcb_mod_prefix, "MinorVersion");
158 
159             writeln!(out)?;
160             writeln!(
161                 out,
162                 "pub const {}: u32 = {};",
163                 &maj_name, ext_info.major_version
164             )?;
165             writeln!(
166                 out,
167                 "pub const {}: u32 = {};",
168                 &min_name, ext_info.minor_version
169             )?;
170 
171             let out = &mut self.ffi_buf;
172             writeln!(out)?;
173             writeln!(
174                 out,
175                 "    pub static mut xcb_{}_id: xcb_extension_t;",
176                 &self.xcb_mod
177             )?;
178         }
179 
180         let out = &mut self.rs;
181         writeln!(out, "use base;")?;
182         for imp in imports.iter() {
183             writeln!(out, "use {};", imp)?;
184         }
185         writeln!(out, "use ffi::base::*;")?;
186         writeln!(out, "use ffi::{}::*;", self.xcb_mod)?;
187         for imp in imports.iter() {
188             writeln!(out, "use ffi::{}::*;", imp)?;
189         }
190         writeln!(out, "use libc::{{self, c_char, c_int, c_uint, c_void}};")?;
191         writeln!(out, "use std;")?;
192         writeln!(out, "use std::iter::Iterator;")?;
193         writeln!(out)?;
194 
195         if let Some(ext_info) = ext_info {
196             let out = &mut self.rs;
197             writeln!(out)?;
198             writeln!(out, "pub fn id() -> &'static mut base::Extension {{")?;
199             writeln!(out, "    unsafe {{")?;
200             writeln!(out, "        &mut xcb_{}_id", &self.xcb_mod)?;
201             writeln!(out, "    }}")?;
202             writeln!(out, "}}")?;
203             writeln!(out)?;
204             writeln!(
205                 out,
206                 "pub const MAJOR_VERSION: u32 = {};",
207                 ext_info.major_version
208             )?;
209             writeln!(
210                 out,
211                 "pub const MINOR_VERSION: u32 = {};",
212                 ext_info.minor_version
213             )?;
214         }
215 
216         Ok(())
217     }
218 
epilogue(&mut self) -> io::Result<()>219     pub fn epilogue(&mut self) -> io::Result<()> {
220         let linklib = match self.xcb_mod.as_str() {
221             "xproto" | "big_requests" | "xc_misc" => "xcb".to_owned(),
222             "genericevent" => "xcb-ge".to_owned(),
223             "x_print" => "xcb-xprint".to_owned(),
224             "test" => "xcb-xtest".to_owned(),
225             "selinux" => "xcb-xselinux".to_owned(),
226             m => {
227                 let mut l = "xcb-".to_owned();
228                 l.push_str(m);
229                 l
230             }
231         };
232 
233         let out = &mut self.ffi;
234         // write out all the external functions
235         writeln!(out)?;
236         writeln!(out, "#[link(name = \"{}\")]", linklib)?;
237         writeln!(out, "extern {{")?;
238 
239         out.write_all(self.ffi_buf.get_ref())?;
240 
241         writeln!(out)?;
242         writeln!(out, "}} // extern")?;
243 
244         let out = &mut self.rs;
245         out.write_all(self.rs_buf.get_ref())?;
246         Ok(())
247     }
248 
event(&mut self, ev: Event) -> io::Result<()>249     pub fn event(&mut self, ev: Event) -> io::Result<()> {
250         match ev {
251             Event::Typedef { oldname, newname } => {
252                 let stru = self.structs.iter().find(|stru| stru.name == oldname);
253                 if let Some(stru) = stru {
254                     // regenerating struct
255                     let newstruct = Struct {
256                         name: newname,
257                         fields: stru.fields.clone(),
258                         doc: stru.doc.clone(),
259                     };
260                     self.emit_struct(newstruct)?;
261                 } else {
262                     // classic typedef with `type new = old;`
263                     self.notify_typ(newname.clone());
264 
265                     let ffi_old_typ = self.ffi_use_type_name(&oldname);
266                     let ffi_new_typ = self.ffi_decl_type_name(&newname);
267 
268                     emit_type_alias(&mut self.ffi, &ffi_new_typ, &ffi_old_typ)?;
269                     self.emit_ffi_iterator(&newname, &ffi_new_typ, false)?;
270 
271                     let rs_new_typ = rs::type_name(&newname);
272                     emit_type_alias(&mut self.rs, &rs_new_typ, &ffi_new_typ)?;
273 
274                     let is_simple = self.typ_is_simple(&oldname);
275                     let is_pod = self.typ_is_pod(&oldname);
276 
277                     self.reg_type(
278                         newname,
279                         ffi_new_typ,
280                         rs_new_typ,
281                         self.ffi_type_sizeof(&oldname),
282                         false,
283                         is_simple,
284                         is_pod,
285                     )
286                 }
287             }
288             Event::XidType(name) => self.emit_xid(name)?,
289             Event::XidUnion(xidun) => self.emit_xid(xidun.name)?,
290             Event::Enum(en) => {
291                 // make owned string to pass into the closure
292                 // otherwise borrow checker complains
293                 let xcb_mod_prefix = self.xcb_mod_prefix.to_string();
294 
295                 let ffi_typ = self.ffi_enum_type_name(&en.name);
296                 emit_enum(
297                     &mut self.ffi,
298                     &ffi_typ,
299                     en.items.iter().map(|it| EnumItem {
300                         id: it.id.clone(),
301                         name: ffi::enum_item_name(&xcb_mod_prefix, &en.name, &it.name),
302                         value: it.value,
303                     }),
304                     &en.doc,
305                 )?;
306 
307                 let rs_typ = self.rs_enum_type_name(&en.name);
308                 emit_enum(
309                     &mut self.rs,
310                     &rs_typ,
311                     en.items.iter().map(|it| EnumItem {
312                         id: it.id.clone(),
313                         name: rs::enum_item_name(&en.name, &it.name),
314                         value: it.value,
315                     }),
316                     &en.doc,
317                 )?;
318                 self.reg_type(en.name, ffi_typ, rs_typ, Some(4), false, true, true);
319             }
320             Event::Struct(stru) => self.emit_struct(stru)?,
321             Event::Union(stru) => self.emit_union(stru)?,
322             Event::Error(number, stru) => self.emit_error(number, stru)?,
323             Event::ErrorCopy { name, number, ref_ } => {
324                 self.emit_error_copy(&name, number, &ref_)?
325             }
326             Event::Event {
327                 number,
328                 stru,
329                 no_seq_number,
330                 xge,
331                 ..
332             } => self.emit_event(number, stru, no_seq_number, xge)?,
333             Event::Request(req) => self.emit_request(req)?,
334             _ => {}
335         }
336         Ok(())
337     }
338 
339     // pub fn xcb_mod(&self) -> &str {
340     //     &self.xcb_mod
341     // }
342 
343     #[allow(clippy::too_many_arguments)]
reg_type( &mut self, typ: String, ffi_typ: String, rs_typ: String, ffi_sz: Option<usize>, is_union: bool, is_simple: bool, is_pod: bool, )344     fn reg_type(
345         &mut self,
346         typ: String,
347         ffi_typ: String,
348         rs_typ: String,
349         ffi_sz: Option<usize>,
350         is_union: bool,
351         is_simple: bool,
352         is_pod: bool,
353     ) {
354         self.ffi_typ_reg.insert(ffi_typ);
355         self.rs_typ_reg.insert(rs_typ);
356         if is_union {
357             self.typ_unions.insert(typ.clone());
358         }
359         if is_simple {
360             self.typ_simple.insert(typ.clone());
361         }
362         if is_pod {
363             self.typ_pod.insert(typ.clone());
364         }
365         self.ffi_type_sizes.insert(typ, ffi_sz);
366     }
367 
368     /// notifies that a XCB type was declared in this module
369     /// alternative to reg_type, with less info
370     /// this is useful for replies, cookies, etc. and other derived types
notify_typ(&mut self, typ: String)371     fn notify_typ(&mut self, typ: String) {
372         self.ffi_type_sizes.insert(typ, None);
373     }
374 
has_type(&self, typ: &str) -> bool375     fn has_type(&self, typ: &str) -> bool {
376         self.ffi_type_sizes.contains_key(typ)
377     }
378 
typ_is_simple(&self, typ: &str) -> bool379     fn typ_is_simple(&self, typ: &str) -> bool {
380         match typ {
381             "CARD8" => true,
382             "CARD16" => true,
383             "CARD32" => true,
384             "CARD64" => true,
385             "INT8" => true,
386             "INT16" => true,
387             "INT32" => true,
388             "BYTE" => true,
389             "BOOL" => true,
390             "char" => true,
391             "float" => true,
392             "double" => true,
393             "void" => true,
394             typ => {
395                 let (module, typ) = extract_module(typ);
396                 if let Some(module) = module {
397                     if module == self.xcb_mod {
398                         self.typ_simple.contains(typ)
399                     } else {
400                         self.dep_info
401                             .iter()
402                             .any(|di| di.xcb_mod == module && di.typ_simple.contains(typ))
403                     }
404                 } else if self.has_type(typ) {
405                     self.typ_simple.contains(typ)
406                 } else {
407                     self.dep_info.iter().any(|di| di.typ_simple.contains(typ))
408                 }
409             }
410         }
411     }
412 
typ_is_pod(&self, typ: &str) -> bool413     fn typ_is_pod(&self, typ: &str) -> bool {
414         if self.typ_is_simple(typ) {
415             return true;
416         }
417         let (module, typ) = extract_module(typ);
418         if let Some(module) = module {
419             if module == self.xcb_mod {
420                 self.typ_pod.contains(typ)
421             } else {
422                 self.dep_info
423                     .iter()
424                     .any(|di| di.xcb_mod == module && di.typ_pod.contains(typ))
425             }
426         } else if self.has_type(typ) {
427             self.typ_pod.contains(typ)
428         } else {
429             self.dep_info.iter().any(|di| di.typ_pod.contains(typ))
430         }
431     }
432 
fields_are_pod(&self, fields: &[StructField]) -> bool433     fn fields_are_pod(&self, fields: &[StructField]) -> bool {
434         for f in fields.iter() {
435             match f {
436                 StructField::Field { typ, .. } => {
437                     if !self.typ_is_pod(typ) {
438                         return false;
439                     }
440                 }
441                 StructField::Pad(..) => {}
442                 StructField::AlignPad(..) => {}
443                 _ => {
444                     return false;
445                 }
446             }
447         }
448         true
449     }
450 
fields_need_lifetime(&self, fields: &[StructField]) -> bool451     fn fields_need_lifetime(&self, fields: &[StructField]) -> bool {
452         for f in fields.iter() {
453             match f {
454                 StructField::Field { typ, .. } => {
455                     if self.typ_unions.contains(typ) {
456                         return true;
457                     }
458                     if self.type_has_lifetime(typ) {
459                         return true;
460                     }
461                 }
462                 StructField::List { .. } => {
463                     return true;
464                 }
465                 _ => {}
466             }
467         }
468         false
469     }
470 
type_has_lifetime(&self, typ: &str) -> bool471     fn type_has_lifetime(&self, typ: &str) -> bool {
472         if self.typ_with_lifetime.contains(typ) {
473             true
474         } else {
475             for di in &self.dep_info {
476                 if di.typ_with_lifetime.contains(typ) {
477                     return true;
478                 }
479             }
480             false
481         }
482     }
483 
eligible_to_copy(&self, stru: &Struct) -> bool484     fn eligible_to_copy(&self, stru: &Struct) -> bool {
485         for f in stru.fields.iter() {
486             match f {
487                 StructField::List { len_expr, .. } => {
488                     if expr_fixed_length(len_expr).is_none() {
489                         return false;
490                     }
491                 }
492                 StructField::ValueParam { .. } => {
493                     return false;
494                 }
495                 StructField::Switch(..) => {
496                     return false;
497                 }
498                 StructField::ListNoLen { .. } => {
499                     return false;
500                 }
501                 _ => {}
502             }
503         }
504         true
505     }
506 
emit_xid(&mut self, name: String) -> io::Result<()>507     fn emit_xid(&mut self, name: String) -> io::Result<()> {
508         self.notify_typ(name.clone());
509         let ffi_typ = self.ffi_decl_type_name(&name);
510         emit_type_alias(&mut self.ffi, &ffi_typ, "u32")?;
511         self.emit_ffi_iterator(&name, &ffi_typ, false)?;
512 
513         let rs_typ = rs::type_name(&name);
514         emit_type_alias(&mut self.rs, &rs_typ, &ffi_typ)?;
515 
516         self.reg_type(name, ffi_typ, rs_typ, Some(4), false, true, true);
517         Ok(())
518     }
519 
emit_struct(&mut self, stru: Struct) -> io::Result<()>520     fn emit_struct(&mut self, stru: Struct) -> io::Result<()> {
521         self.notify_typ(stru.name.clone());
522 
523         let has_lifetime = self.fields_need_lifetime(&stru.fields);
524         if has_lifetime {
525             self.typ_with_lifetime.insert(stru.name.clone());
526         }
527         let ffi_typ = self.emit_ffi_struct(&stru, None, false, false, false)?;
528         self.emit_ffi_field_list_accessors(&ffi_typ, &stru.name, &stru.fields, None, false)?;
529         let ffi_it_typ = self.emit_ffi_iterator(&stru.name, &ffi_typ, has_lifetime)?;
530 
531         let rs_typ = self.emit_rs_struct(&ffi_typ, &stru, has_lifetime)?;
532         self.emit_rs_iterator(&stru.name, &rs_typ, &ffi_it_typ, has_lifetime, false)?;
533 
534         let stru_sz = self.compute_ffi_struct_size(&stru);
535         self.reg_type(
536             stru.name.clone(),
537             ffi_typ,
538             rs_typ,
539             stru_sz,
540             false,
541             false,
542             self.fields_are_pod(&stru.fields),
543         );
544 
545         self.structs.push(stru);
546 
547         Ok(())
548     }
549 
emit_union(&mut self, stru: Struct) -> io::Result<()>550     fn emit_union(&mut self, stru: Struct) -> io::Result<()> {
551         self.notify_typ(stru.name.clone());
552 
553         let ffi_sz = self.compute_ffi_union_size(&stru);
554         let ffi_typ = self.ffi_decl_type_name(&stru.name);
555 
556         {
557             let out = &mut self.ffi;
558             writeln!(out)?;
559             emit_doc_text(out, &stru.doc)?;
560             writeln!(out, "// union")?;
561             writeln!(out, "#[repr(C)]")?;
562             writeln!(out, "#[derive(Debug)]")?;
563             writeln!(out, "pub struct {} {{", &ffi_typ)?;
564             writeln!(out, "    pub data: [u8; {}],", ffi_sz)?;
565             writeln!(out, "}}")?;
566             emit_copy_clone(out, &ffi_typ)?;
567         }
568 
569         self.emit_ffi_iterator(&stru.name, &ffi_typ, false)?;
570 
571         let rs_typ = rs::type_name(&stru.name);
572 
573         {
574             let out = &mut self.rs_buf;
575 
576             writeln!(out)?;
577             emit_doc_text(out, &stru.doc)?;
578             emit_type_alias(out, &rs_typ, &ffi_typ)?;
579         }
580 
581         self.emit_rs_union_impl(&rs_typ, ffi_sz, &stru)?;
582 
583         let ffi_it_typ = self.ffi_iterator_name(&stru.name);
584 
585         self.emit_rs_iterator(&stru.name, &rs_typ, &ffi_it_typ, false, true)?;
586 
587         self.reg_type(stru.name, ffi_typ, rs_typ, Some(ffi_sz), true, false, false);
588 
589         Ok(())
590     }
591 
emit_error(&mut self, number: i32, stru: Struct) -> io::Result<()>592     fn emit_error(&mut self, number: i32, stru: Struct) -> io::Result<()> {
593         self.notify_typ(stru.name.clone() + "Error");
594 
595         ffi::emit_opcode(&mut self.ffi, &self.xcb_mod_prefix, &stru.name, number)?;
596 
597         rs::emit_opcode(&mut self.rs_buf, &stru.name, number)?;
598 
599         let fields = {
600             let mut fields = vec![
601                 StructField::Field {
602                     name: "response_type".into(),
603                     typ: "CARD8".into(),
604                     enu: None,
605                 },
606                 StructField::Field {
607                     name: "error_code".into(),
608                     typ: "CARD8".into(),
609                     enu: None,
610                 },
611                 StructField::Field {
612                     name: "sequence".into(),
613                     typ: "CARD16".into(),
614                     enu: None,
615                 },
616             ];
617             for f in stru.fields.into_iter() {
618                 fields.push(f);
619             }
620             fields
621         };
622         let stru = Struct {
623             name: stru.name + "Error",
624             fields,
625             doc: stru.doc,
626         };
627 
628         let ffi_typ = self.emit_ffi_struct(&stru, None, false, false, false)?;
629 
630         let rs_typ = rs::type_name(&stru.name);
631 
632         rs::emit_error(&mut self.rs, &ffi_typ, &rs_typ)?;
633 
634         self.reg_type(
635             stru.name,
636             ffi_typ,
637             rs_typ,
638             None,
639             false,
640             false,
641             self.fields_are_pod(&stru.fields),
642         );
643 
644         Ok(())
645     }
646 
emit_error_copy(&mut self, name: &str, number: i32, error_ref: &str) -> io::Result<()>647     fn emit_error_copy(&mut self, name: &str, number: i32, error_ref: &str) -> io::Result<()> {
648         ffi::emit_opcode(&mut self.ffi, &self.xcb_mod_prefix, name, number)?;
649         let new_name = name.to_owned() + "Error";
650         let old_name = error_ref.to_owned() + "Error";
651 
652         let new_ffi_typ = self.ffi_decl_type_name(&new_name);
653         let old_ffi_typ = self.ffi_use_type_name(&old_name);
654 
655         emit_type_alias(&mut self.ffi, &new_ffi_typ, &old_ffi_typ)?;
656 
657         let rs_typ = rs::type_name(&new_name);
658 
659         rs::emit_error(&mut self.rs, &new_ffi_typ, &rs_typ)?;
660         rs::emit_opcode(&mut self.rs_buf, name, number)?;
661 
662         self.notify_typ(new_name);
663 
664         Ok(())
665     }
666 
emit_event( &mut self, number: i32, stru: Struct, no_seq_number: bool, xge: bool, ) -> io::Result<()>667     fn emit_event(
668         &mut self,
669         number: i32,
670         stru: Struct,
671         no_seq_number: bool,
672         xge: bool,
673     ) -> io::Result<()> {
674         let Struct {
675             name: orig_name,
676             fields: mut orig_fields,
677             doc,
678         } = stru;
679         let event_typ = orig_name.clone() + "Event";
680         self.notify_typ(event_typ.clone());
681 
682         ffi::emit_opcode(&mut self.ffi, &self.xcb_mod_prefix, &orig_name, number)?;
683 
684         let opcopies = self
685             .evcopies
686             .remove(&orig_name)
687             .expect("missing event copies");
688 
689         let (fields, must_pack) = {
690             let mut fields = vec![StructField::Field {
691                 name: "response_type".into(),
692                 typ: "CARD8".into(),
693                 enu: None,
694             }];
695             let mut must_pack = false;
696 
697             let mut sz = 1; // response_type size
698 
699             if xge {
700                 fields.push(StructField::Field {
701                     name: "extension".into(),
702                     typ: "CARD8".into(),
703                     enu: None,
704                 });
705                 fields.push(StructField::Field {
706                     name: "sequence".into(),
707                     typ: "CARD16".into(),
708                     enu: None,
709                 });
710                 fields.push(StructField::Field {
711                     name: "length".into(),
712                     typ: "CARD32".into(),
713                     enu: None,
714                 });
715                 fields.push(StructField::Field {
716                     name: "event_type".into(),
717                     typ: "CARD16".into(),
718                     enu: None,
719                 });
720                 sz += 9;
721             } else if !no_seq_number {
722                 fields.push(orig_fields.remove(0));
723                 fields.push(StructField::Field {
724                     name: "sequence".into(),
725                     typ: "CARD16".into(),
726                     enu: None,
727                 });
728             }
729 
730             for f in orig_fields.into_iter() {
731                 if xge {
732                     let fsz = self.compute_ffi_struct_field_sizeof(&f);
733                     fields.push(f);
734                     if sz < 32 {
735                         sz += fsz.expect("can't compute ffi full_sequence position");
736                         if sz == 32 {
737                             fields.push(StructField::Field {
738                                 name: "full_sequence".into(),
739                                 typ: "CARD32".into(),
740                                 enu: None,
741                             });
742                         }
743                     } else if let Some(fsz) = fsz {
744                         if fsz == 8 {
745                             must_pack = true;
746                         }
747                     }
748                 } else {
749                     fields.push(f);
750                 }
751             }
752             (fields, must_pack)
753         };
754         let stru = Struct {
755             name: event_typ,
756             fields,
757             doc,
758         };
759 
760         let ffi_typ = self.emit_ffi_struct(&stru, None, must_pack, false, false)?;
761         self.emit_ffi_field_list_accessors(&ffi_typ, &orig_name, &stru.fields, None, false)?;
762         let ffi_sz = self.compute_ffi_struct_size(&stru);
763 
764         for c in opcopies.iter() {
765             ffi::emit_opcode(&mut self.ffi, &self.xcb_mod_prefix, &c.name, c.number)?;
766             let new_name = c.name.to_owned() + "Event";
767 
768             let new_ffi_typ = self.ffi_decl_type_name(&new_name);
769             let old_ffi_typ = self.ffi_use_type_name(&stru.name);
770 
771             emit_type_alias(&mut self.ffi, &new_ffi_typ, &old_ffi_typ)?;
772         }
773 
774         let rs_typ = self.emit_rs_event(&orig_name, number, &stru, &ffi_typ, &opcopies, xge)?;
775 
776         self.reg_type(
777             stru.name,
778             ffi_typ,
779             rs_typ,
780             ffi_sz,
781             false,
782             false,
783             self.fields_are_pod(&stru.fields),
784         );
785 
786         Ok(())
787     }
788 
emit_request(&mut self, mut req: Request) -> io::Result<()>789     fn emit_request(&mut self, mut req: Request) -> io::Result<()> {
790         let request_typ = req.name.clone() + "Request";
791         self.notify_typ(request_typ.clone());
792 
793         let fields = {
794             let mut params = req.params.clone();
795             let mut fields = vec![
796                 StructField::Field {
797                     name: "major_opcode".into(),
798                     typ: "CARD8".into(),
799                     enu: None,
800                 },
801                 if self.xcb_mod == "xproto" {
802                     if params.is_empty() {
803                         StructField::Pad("pad0".into(), 1)
804                     } else {
805                         // assert!(self.compute_ffi_struct_field_sizeof(&p) == Some(1usize));
806                         params.remove(0)
807                     }
808                 } else {
809                     StructField::Field {
810                         name: "minor_opcode".into(),
811                         typ: "CARD8".into(),
812                         enu: None,
813                     }
814                 },
815                 StructField::Field {
816                     name: "length".into(),
817                     typ: "CARD16".into(),
818                     enu: None,
819                 },
820             ];
821             fields.append(&mut params);
822             fields
823         };
824 
825         for f in &fields {
826             if let StructField::Switch(name, expr, cases) = f {
827                 let toplevel = req.name.to_string() + "Request";
828                 self.notify_typ(toplevel.clone());
829                 self.emit_ffi_switch_struct(&req.name, name, expr, cases, &toplevel, None)?;
830                 self.emit_rs_switch_typedef(&req.name, name, cases, &toplevel, None)?;
831             }
832         }
833 
834         ffi::emit_opcode(&mut self.ffi, &self.xcb_mod_prefix, &req.name, req.opcode)?;
835 
836         let stru = Struct {
837             name: request_typ,
838             fields,
839             doc: req.doc.clone(),
840         };
841         self.emit_ffi_struct(&stru, None, false, false, false)?;
842 
843         let void = req.reply.is_none();
844         let (ffi_cookie, check_name, checked) = if void {
845             ("VoidCookie".to_string(), req.name.clone() + "Checked", true)
846         } else {
847             (
848                 req.name.clone() + "Cookie",
849                 req.name.clone() + "Unchecked",
850                 false,
851             )
852         };
853 
854         let rs_cookie = if ffi_cookie == "VoidCookie" {
855             String::from("base::VoidCookie")
856         } else {
857             rs::type_name(&ffi_cookie)
858         };
859 
860         rs::emit_opcode(&mut self.rs_buf, &req.name, req.opcode)?;
861 
862         if let Some(reply) = req.reply.take() {
863             let (ffi_cookie, ffi_reply_fn, ffi_reply_typ) =
864                 self.emit_ffi_reply(&req.name, reply.clone())?;
865             self.emit_rs_reply(
866                 &req.name,
867                 &ffi_cookie,
868                 &ffi_reply_fn,
869                 &ffi_reply_typ,
870                 &rs_cookie,
871                 reply,
872             )?;
873             self.notify_typ(req.name.clone() + "Reply");
874             self.notify_typ(req.name.clone() + "Cookie");
875         }
876 
877         let ffi_fn_name = ffi::request_fn_name(&self.xcb_mod_prefix, &req.name);
878         let ffi_check_fn_name = ffi::request_fn_name(&self.xcb_mod_prefix, &check_name);
879         let rs_fn_name = rs::request_fn_name(&req.name);
880         let rs_check_fn_name = rs::request_fn_name(&check_name);
881 
882         self.emit_ffi_req_fn(&req.name, &ffi_fn_name, &ffi_cookie, &req.params, &stru.doc)?;
883         self.emit_ffi_req_fn(
884             &req.name,
885             &ffi_check_fn_name,
886             &ffi_cookie,
887             &req.params,
888             &stru.doc,
889         )?;
890         self.emit_rs_req_fn(
891             &req.name,
892             &rs_fn_name,
893             &ffi_fn_name,
894             &rs_cookie,
895             &req.params,
896             &stru.doc,
897             !checked,
898         )?;
899         self.emit_rs_req_fn(
900             &req.name,
901             &rs_check_fn_name,
902             &ffi_check_fn_name,
903             &rs_cookie,
904             &req.params,
905             &stru.doc,
906             checked,
907         )?;
908 
909         Ok(())
910     }
911 }
912 
has_fd(fields: &[StructField]) -> bool913 fn has_fd(fields: &[StructField]) -> bool {
914     for f in fields.iter() {
915         if let StructField::Fd(_) = f {
916             return true;
917         }
918     }
919     false
920 }
921 
make_field(name: String, typ: String) -> StructField922 fn make_field(name: String, typ: String) -> StructField {
923     StructField::Field {
924         name,
925         typ,
926         enu: None,
927     }
928 }
929 
expr_fixed_length(expr: &Expr<usize>) -> Option<usize>930 fn expr_fixed_length(expr: &Expr<usize>) -> Option<usize> {
931     match expr {
932         Expr::EnumRef { .. } => None, // FIXME: get the value of the enum item
933         Expr::Value(val) => Some(*val),
934         Expr::Popcount(ex) => expr_fixed_length(ex).map(|sz| sz.count_ones() as _),
935         Expr::Op(op, lhs, rhs) => match (expr_fixed_length(lhs), expr_fixed_length(rhs)) {
936             (Some(lhs), Some(rhs)) => match op.as_str() {
937                 "+" => Some(lhs + rhs),
938                 "-" => Some(lhs - rhs),
939                 "*" => Some(lhs * rhs),
940                 "/" => Some(lhs / rhs),
941                 _ => panic!("Unexpected binary operator in Expr: {}", op),
942             },
943             _ => None,
944         },
945         Expr::Unop(op, val) => expr_fixed_length(val).map(|val| match op.as_str() {
946             "~" => !val,
947             _ => panic!("Unexpected unary operator in Expr: {}", op),
948         }),
949         _ => None,
950     }
951 }
952 
capitalize(s: &str) -> String953 fn capitalize(s: &str) -> String {
954     let mut ch = s.chars();
955     match ch.next() {
956         None => String::new(),
957         Some(c) => c.to_uppercase().chain(ch).collect(),
958     }
959 }
960 
961 // insert a underscore before each uppercase/digit preceded or follwed by lowercase
962 // do not apply to the first char
tit_split<H>(name: &str, is_high: H) -> String where H: Fn(char) -> bool,963 fn tit_split<H>(name: &str, is_high: H) -> String
964 where
965     H: Fn(char) -> bool,
966 {
967     if name.len() <= 1 {
968         return name.into();
969     }
970 
971     let is_low = |c: char| c.is_ascii_lowercase();
972 
973     let mut res = String::new();
974     let mut ch = name.chars();
975     let mut prev = ch.next().unwrap();
976     res.push(prev);
977     let mut c = ch.next().unwrap();
978 
979     for next in ch {
980         if (is_low(prev) && is_high(c) || is_high(c) && is_low(next)) && prev != '_' {
981             res.push('_');
982         }
983         res.push(c);
984         prev = c;
985         c = next;
986     }
987     if is_low(prev) && is_high(c) && prev != '_' {
988         res.push('_');
989     }
990     res.push(c);
991 
992     res
993 }
994 
995 // capitalize each substring beginning by uppercase
996 // said otherwise: every upper preceded by another upper and followed by a upper is turned to lower
tit_cap(name: &str) -> String997 fn tit_cap(name: &str) -> String {
998     if name.len() <= 1 {
999         return name.into();
1000     }
1001 
1002     let is_high = |c: char| c.is_ascii_uppercase() | c.is_ascii_digit();
1003 
1004     let mut res = String::new();
1005     let mut ch = name.chars();
1006     let mut prev = ch.next().unwrap();
1007     res.push(prev.to_ascii_uppercase());
1008     let mut c = ch.next().unwrap();
1009 
1010     for next in ch {
1011         if c != '_' {
1012             if is_high(c) && is_high(prev) && (is_high(next) || next == '_') {
1013                 res.push(c.to_ascii_lowercase())
1014             } else if prev == '_' && c != '_' {
1015                 res.push(c.to_ascii_uppercase())
1016             } else {
1017                 res.push(c)
1018             }
1019         }
1020         prev = c;
1021         c = next;
1022     }
1023     if is_high(c) && is_high(prev) {
1024         res.push(c.to_ascii_lowercase());
1025     } else {
1026         res.push(c);
1027     }
1028 
1029     res
1030 }
1031 
1032 #[test]
test_tit_cap()1033 fn test_tit_cap() {
1034     assert!(tit_cap("SomeString") == "SomeString");
1035     assert!(tit_cap("WINDOW") == "Window");
1036     assert!(tit_cap("CONTEXT_TAG") == "ContextTag");
1037     assert!(tit_cap("value_list") == "ValueList");
1038     assert!(tit_cap("GContext") == "GContext");
1039     assert!(tit_cap("IDChoice") == "IdChoice");
1040 }
1041 
tit_dig_split(name: &str) -> String1042 fn tit_dig_split(name: &str) -> String {
1043     tit_split(name, |c| c.is_ascii_uppercase() || c.is_ascii_digit())
1044 }
1045 
1046 #[test]
test_tit_dig_split()1047 fn test_tit_dig_split() {
1048     assert_eq!(tit_dig_split("SomeString"), "Some_String");
1049     assert_eq!(tit_dig_split("WINDOW"), "WINDOW");
1050 }
1051 
1052 const KEYWORDS: &[&str] = &["type", "str", "match", "new", "await"];
1053 
field_name(name: &str) -> String1054 fn field_name(name: &str) -> String {
1055     let mut res = tit_split(name, |c| c.is_ascii_uppercase()).to_ascii_lowercase();
1056 
1057     if KEYWORDS.contains(&res.as_str()) {
1058         res.push('_');
1059     }
1060 
1061     res
1062 }
1063 
1064 #[test]
test_field_name()1065 fn test_field_name() {
1066     assert_eq!(field_name("groupMaps"), "group_maps");
1067     assert_eq!(field_name("num_FB_configs"), "num_fb_configs");
1068     assert_eq!(field_name("sizeID"), "size_id");
1069     assert_eq!(field_name("new"), "new_");
1070     assert_eq!(field_name("byte1"), "byte1");
1071 }
1072 
extract_module(typ: &str) -> (Option<&str>, &str)1073 fn extract_module(typ: &str) -> (Option<&str>, &str) {
1074     let len = typ.len();
1075     let colon = typ.as_bytes().iter().position(|b| *b == b':');
1076     if let Some(colon) = colon {
1077         (Some(&typ[0..colon]), &typ[colon + 1..len])
1078     } else {
1079         (None, typ)
1080     }
1081 }
1082 
qualified_name(xcb_mod: &str, module: &Option<&str>, name: &str) -> String1083 fn qualified_name(xcb_mod: &str, module: &Option<&str>, name: &str) -> String {
1084     if let Some(module) = module {
1085         if module != &xcb_mod {
1086             format!("{}::{}", module, &name)
1087         } else {
1088             name.into()
1089         }
1090     } else {
1091         name.into()
1092     }
1093 }
emit_type_alias<Out: Write>(out: &mut Out, new_typ: &str, old_typ: &str) -> io::Result<()>1094 fn emit_type_alias<Out: Write>(out: &mut Out, new_typ: &str, old_typ: &str) -> io::Result<()> {
1095     writeln!(out)?;
1096     writeln!(out, "pub type {} = {};", new_typ, old_typ)?;
1097     Ok(())
1098 }
1099 
emit_doc_str<Out: Write>(out: &mut Out, docstr: &str, indent: &str) -> io::Result<()>1100 fn emit_doc_str<Out: Write>(out: &mut Out, docstr: &str, indent: &str) -> io::Result<()> {
1101     let mut wrote = false;
1102     if !docstr.is_empty() {
1103         for s in docstr.split('\n') {
1104             let s = s.trim_end();
1105             if !s.is_empty() {
1106                 writeln!(out, "///{}{}", indent, s.trim_end())?;
1107             } else {
1108                 writeln!(out, "///")?;
1109             }
1110             wrote = true;
1111         }
1112     }
1113     if !wrote {
1114         writeln!(out, "///")
1115     } else {
1116         Ok(())
1117     }
1118 }
1119 
emit_doc_text<Out: Write>(out: &mut Out, doc: &Option<Doc>) -> io::Result<()>1120 fn emit_doc_text<Out: Write>(out: &mut Out, doc: &Option<Doc>) -> io::Result<()> {
1121     if let Some(doc) = doc {
1122         if !doc.brief.is_empty() {
1123             emit_doc_str(out, &doc.brief, " ")?;
1124         }
1125         if !doc.brief.is_empty() && !doc.text.is_empty() {
1126             writeln!(out, "///")?;
1127         }
1128         if !doc.text.is_empty() {
1129             emit_doc_str(out, &doc.text, " ")?;
1130         }
1131     }
1132     Ok(())
1133 }
1134 
emit_doc_field<Out: Write>(out: &mut Out, doc: &Option<Doc>, field: &str) -> io::Result<()>1135 fn emit_doc_field<Out: Write>(out: &mut Out, doc: &Option<Doc>, field: &str) -> io::Result<()> {
1136     if let Some(doc) = doc {
1137         if let Some(f) = doc.fields.iter().find(|f| f.name == field) {
1138             emit_doc_str(out, &f.text, " ")
1139         } else {
1140             //writeln!(out, "///")
1141             Ok(())
1142         }
1143     } else {
1144         Ok(())
1145     }
1146 }
1147 
emit_doc_field_indent<Out: Write>( out: &mut Out, doc: &Option<Doc>, field: &str, indent: &str, ) -> io::Result<()>1148 fn emit_doc_field_indent<Out: Write>(
1149     out: &mut Out,
1150     doc: &Option<Doc>,
1151     field: &str,
1152     indent: &str,
1153 ) -> io::Result<()> {
1154     if let Some(doc) = doc {
1155         if let Some(f) = doc.fields.iter().find(|f| f.name == field) {
1156             emit_doc_str(out, &f.text, indent)?;
1157         }
1158     }
1159     Ok(())
1160 }
1161 
emit_copy_clone<Out: Write>(out: &mut Out, typ: &str) -> io::Result<()>1162 fn emit_copy_clone<Out: Write>(out: &mut Out, typ: &str) -> io::Result<()> {
1163     writeln!(out)?;
1164     writeln!(out, "impl Copy for {} {{}}", &typ)?;
1165     writeln!(out, "impl Clone for {} {{", &typ)?;
1166     writeln!(out, "    fn clone(&self) -> {} {{ *self }}", &typ)?;
1167     writeln!(out, "}}")?;
1168 
1169     Ok(())
1170 }
1171 
emit_enum<Out, Items>( out: &mut Out, typ: &str, items: Items, doc: &Option<Doc>, ) -> io::Result<()> where Out: Write, Items: Iterator<Item = EnumItem>,1172 fn emit_enum<Out, Items>(
1173     out: &mut Out,
1174     typ: &str,
1175     items: Items,
1176     doc: &Option<Doc>,
1177 ) -> io::Result<()>
1178 where
1179     Out: Write,
1180     Items: Iterator<Item = EnumItem>,
1181 {
1182     writeln!(out)?;
1183     emit_doc_text(out, doc)?;
1184     writeln!(out, "pub type {} = u32;", typ)?;
1185     for item in items {
1186         emit_doc_field(out, doc, &item.id)?;
1187         let val = format!("0x{:02x}", item.value);
1188         writeln!(out, "pub const {}: {} = {};", item.name, typ, val)?;
1189     }
1190     Ok(())
1191 }
1192 
1193 struct ListField {
1194     name: String,
1195     typ: String,
1196     lenfield: String,
1197     // lenfield_typ: String,
1198 }
1199 
1200 impl ListField {
fetch_from(fields: &[StructField]) -> Vec<ListField>1201     fn fetch_from(fields: &[StructField]) -> Vec<ListField> {
1202         let mut res = Vec::new();
1203         for f in fields {
1204             match f {
1205                 StructField::List {
1206                     name,
1207                     typ,
1208                     len_expr,
1209                 } => {
1210                     let lenfield = expr_lenfield(len_expr);
1211                     if let Some(lenfield) = lenfield {
1212                         let name = name.clone();
1213                         let typ = typ.clone();
1214                         let lenfield = lenfield.to_string();
1215                         // let lenfield_typ = fields
1216                         //     .iter()
1217                         //     .find_map(|f| match f {
1218                         //         StructField::Field { name, typ, .. } => {
1219                         //             if name == &lenfield {
1220                         //                 Some(typ.clone())
1221                         //             } else {
1222                         //                 None
1223                         //             }
1224                         //         }
1225                         //         _ => None,
1226                         //     })
1227                         //     .expect("can't find lenfield type");
1228                         res.push(ListField {
1229                             name,
1230                             typ,
1231                             lenfield,
1232                             // lenfield_typ,
1233                         });
1234                     }
1235                 }
1236                 StructField::ListNoLen { name, typ } => {
1237                     let name = name.clone();
1238                     let typ = typ.clone();
1239                     let lenfield = name.clone() + "_len";
1240                     res.push(ListField {
1241                         name,
1242                         typ,
1243                         lenfield,
1244                         // lenfield_typ: "CARD32".to_string(),
1245                     });
1246                 }
1247                 _ => {}
1248             }
1249         }
1250         res
1251     }
1252 }
1253 
expr_lenfield(expr: &Expr<usize>) -> Option<&str>1254 fn expr_lenfield(expr: &Expr<usize>) -> Option<&str> {
1255     match expr {
1256         Expr::FieldRef(name) => Some(name),
1257         Expr::Op(_, lhs, rhs) => expr_lenfield(lhs).or_else(|| expr_lenfield(rhs)),
1258         Expr::Unop(_, rhs) => expr_lenfield(rhs),
1259         Expr::Popcount(e) => expr_lenfield(e),
1260         _ => None,
1261     }
1262 }
1263 
request_has_template(params: &[StructField]) -> bool1264 fn request_has_template(params: &[StructField]) -> bool {
1265     for f in params.iter() {
1266         if let StructField::List { typ, .. } = f {
1267             if typ == "void" {
1268                 return true;
1269             }
1270         }
1271     }
1272     false
1273 }
1274 
enum_suffix_exception(xcb_mod: &str, enum_typ: &str) -> bool1275 fn enum_suffix_exception(xcb_mod: &str, enum_typ: &str) -> bool {
1276     matches!(
1277         (xcb_mod, enum_typ),
1278         ("render", "Picture") | ("present", "Event")
1279     )
1280 }
1281