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