1 use std::io::{self, Write};
2
3 use super::{
4 capitalize, emit_doc_field, emit_doc_text, enum_suffix_exception, expr_fixed_length,
5 extract_module, field_name, has_fd, make_field, tit_dig_split, CodeGen,
6 };
7 use crate::ast::{Doc, Expr, Reply, Struct, StructField, SwitchCase};
8
9 impl CodeGen {
has_ffi_type(&self, typ: &str) -> bool10 fn has_ffi_type(&self, typ: &str) -> bool {
11 self.ffi_typ_reg.contains(typ)
12 }
13
14 /// FFI type name
ffi_decl_type_name(&self, typ: &str) -> String15 pub fn ffi_decl_type_name(&self, typ: &str) -> String {
16 let typ = tit_dig_split(typ).to_ascii_lowercase();
17 format!("xcb_{}{}_t", &self.xcb_mod_prefix, typ)
18 }
19
20 /// same as ffi_decl_type_name but can also have a namespace before (with a single colon)
ffi_use_type_name(&self, typ: &str) -> String21 pub fn ffi_use_type_name(&self, typ: &str) -> String {
22 match typ {
23 "CARD8" => "u8".into(),
24 "CARD16" => "u16".into(),
25 "CARD32" => "u32".into(),
26 "CARD64" => "u64".into(),
27 "INT8" => "i8".into(),
28 "INT16" => "i16".into(),
29 "INT32" => "i32".into(),
30 "BYTE" => "u8".into(),
31 "BOOL" => "u8".into(),
32 "char" => "c_char".into(),
33 "float" => "f32".into(),
34 "double" => "f64".into(),
35 "void" => "c_void".into(),
36 typ => {
37 let (module, typ) = extract_module(typ);
38
39 if let Some(module) = module {
40 let typ = tit_dig_split(typ).to_ascii_lowercase();
41 let mod_prefix = if module == "xproto" {
42 String::new()
43 } else {
44 format!("{}_", module)
45 };
46 format!("xcb_{}{}_t", &mod_prefix, typ)
47 } else {
48 let mod_prefix = if self.has_type(typ) {
49 &self.xcb_mod_prefix
50 } else {
51 let mut pref = "";
52
53 for di in self.dep_info.iter() {
54 if di.has_type(typ) {
55 pref = &di.xcb_mod_prefix;
56 break;
57 }
58 }
59
60 pref
61 };
62 let typ = tit_dig_split(typ).to_ascii_lowercase();
63 format!("xcb_{}{}_t", mod_prefix, typ)
64 }
65 }
66 }
67 }
68
ffi_iterator_name(&self, typ: &str) -> String69 pub fn ffi_iterator_name(&self, typ: &str) -> String {
70 let mod_prefix = if self.has_type(typ) {
71 &self.xcb_mod_prefix
72 } else {
73 let mut pref = "";
74
75 for di in self.dep_info.iter() {
76 if di.has_type(typ) {
77 pref = &di.xcb_mod_prefix;
78 break;
79 }
80 }
81
82 pref
83 };
84 format!(
85 "xcb_{}{}_iterator_t",
86 &mod_prefix,
87 tit_dig_split(typ).to_ascii_lowercase()
88 )
89 }
90
ffi_type_sizeof(&self, typ: &str) -> Option<usize>91 pub fn ffi_type_sizeof(&self, typ: &str) -> Option<usize> {
92 match typ {
93 "CARD8" => Some(1),
94 "CARD16" => Some(2),
95 "CARD32" => Some(4),
96 "CARD64" => Some(8),
97 "INT8" => Some(1),
98 "INT16" => Some(2),
99 "INT32" => Some(4),
100 "BYTE" => Some(1),
101 "BOOL" => Some(1),
102 "char" => Some(1),
103 "float" => Some(4),
104 "double" => Some(8),
105 "void" => Some(0),
106 typ => {
107 // FIXME: handle module
108 let (_, typ) = extract_module(typ);
109
110 if let Some(sz) = self.ffi_type_sizes.get(typ) {
111 *sz
112 } else {
113 // checking in the imported dependencies
114 for di in self.dep_info.iter() {
115 if let Some(sz) = di.ffi_type_sizes.get(typ) {
116 return *sz;
117 }
118 }
119 None
120 }
121 }
122 }
123 }
124
ffi_enum_type_name(&mut self, typ: &str) -> String125 pub fn ffi_enum_type_name(&mut self, typ: &str) -> String {
126 let base = tit_dig_split(typ).to_ascii_lowercase();
127 let try1 = format!("xcb_{}{}_t", self.xcb_mod_prefix, base);
128 if self.has_ffi_type(&try1) || enum_suffix_exception(&self.xcb_mod, typ) {
129 format!("xcb_{}{}_enum_t", self.xcb_mod_prefix, base)
130 } else {
131 try1
132 }
133 }
134
compute_ffi_struct_field_sizeof(&self, field: &StructField) -> Option<usize>135 pub fn compute_ffi_struct_field_sizeof(&self, field: &StructField) -> Option<usize> {
136 match field {
137 StructField::Field { typ, .. } => self.ffi_type_sizeof(typ),
138 StructField::Pad(_, pad_sz) => Some(*pad_sz),
139 StructField::List { typ, len_expr, .. } => {
140 match (self.ffi_type_sizeof(typ), expr_fixed_length(len_expr)) {
141 (Some(sz), Some(len)) => Some(sz * len),
142 _ => None,
143 }
144 }
145 StructField::ListNoLen { .. } => None,
146 f => unimplemented!("{:?}", f),
147 }
148 }
149
compute_ffi_struct_size(&self, stru: &Struct) -> Option<usize>150 pub fn compute_ffi_struct_size(&self, stru: &Struct) -> Option<usize> {
151 let mut stru_sz = Some(0usize);
152
153 for f in stru.fields.iter() {
154 match f {
155 StructField::AlignPad(_, alignment) => match stru_sz.as_mut() {
156 Some(sz) => {
157 let curr = *sz % alignment;
158 if curr != 0 {
159 *sz += alignment - curr;
160 }
161 }
162 _ => {
163 return None;
164 }
165 },
166 field => {
167 match (
168 stru_sz.as_mut(),
169 self.compute_ffi_struct_field_sizeof(field),
170 ) {
171 (Some(stru_sz), Some(f_sz)) => {
172 *stru_sz += f_sz;
173 }
174 _ => {
175 return None;
176 }
177 }
178 }
179 }
180 }
181
182 stru_sz
183 }
184
compute_ffi_union_size(&self, stru: &Struct) -> usize185 pub fn compute_ffi_union_size(&self, stru: &Struct) -> usize {
186 let mut biggest = 1;
187 let mut alignment = 1;
188
189 for f in stru.fields.iter() {
190 let mut fs = self.ptr_width;
191 let mut fa = self.ptr_width;
192 match f {
193 StructField::AlignPad(_, _) => panic!("Unexpected align pad in union"),
194 StructField::Pad(_, _) => panic!("Unexpected pad in union"),
195 StructField::Field { typ, .. } => {
196 if let Some(sz) = self.ffi_type_sizeof(typ) {
197 fs = sz;
198 fa = sz;
199 }
200 }
201 StructField::List { typ, len_expr, .. } => {
202 if let Some(sz) = self.ffi_type_sizeof(typ) {
203 fs = sz;
204 fa = sz;
205 }
206 if let Some(len) = expr_fixed_length(len_expr) {
207 fs = len * fa;
208 }
209 }
210 StructField::ListNoLen { .. } => panic!("Unexpected list without length in union"),
211
212 f => unimplemented!("{:?}", f),
213 }
214
215 biggest = biggest.max(fs);
216 alignment = alignment.max(fa);
217 }
218
219 let mut num_aligned = biggest / alignment;
220 if biggest % alignment > 0 {
221 num_aligned += 1;
222 }
223 num_aligned * alignment
224 }
225
emit_ffi_iterator( &mut self, name: &str, typ: &str, has_lifetime: bool, ) -> io::Result<String>226 pub fn emit_ffi_iterator(
227 &mut self,
228 name: &str,
229 typ: &str,
230 has_lifetime: bool,
231 ) -> io::Result<String> {
232 let it_typ = self.ffi_iterator_name(name);
233 let it_next = iterator_next_fn_name(&self.xcb_mod_prefix, name);
234 let it_end = iterator_end_fn_name(&self.xcb_mod_prefix, name);
235
236 let out = &mut self.ffi;
237
238 let lifetime = if has_lifetime { "<'a>" } else { "" };
239
240 writeln!(out)?;
241 writeln!(out, "#[repr(C)]")?;
242 writeln!(out, "#[derive(Debug)]")?;
243 writeln!(out, "pub struct {}{} {{", &it_typ, lifetime)?;
244 writeln!(out, " pub data: *mut {},", &typ)?;
245 writeln!(out, " pub rem: c_int,")?;
246 writeln!(out, " pub index: c_int,")?;
247 if has_lifetime {
248 writeln!(out, " _phantom: std::marker::PhantomData<&'a {}>,", &typ)?;
249 }
250 writeln!(out, "}}")?;
251
252 let out = &mut self.ffi_buf;
253 writeln!(out).unwrap();
254 writeln!(out, "pub fn {}(i: *mut {});", &it_next, &it_typ).unwrap();
255 writeln!(out).unwrap();
256 writeln!(
257 out,
258 "pub fn {}(i: *mut {}) -> xcb_generic_iterator_t;",
259 &it_end, &it_typ
260 )
261 .unwrap();
262 Ok(it_typ)
263 }
264
emit_ffi_field_list_accessor( &mut self, ffi_typ: &str, xcb_name: &str, fname: &str, ftyp: &str, toplevel_typ: Option<&str>, fixed_size: bool, ) -> io::Result<()>265 fn emit_ffi_field_list_accessor(
266 &mut self,
267 ffi_typ: &str,
268 xcb_name: &str,
269 fname: &str,
270 ftyp: &str,
271 toplevel_typ: Option<&str>,
272 fixed_size: bool,
273 ) -> io::Result<()> {
274 let is_simple = self.typ_is_simple(ftyp);
275
276 let accessor_needed = fixed_size;
277 let length_needed = true;
278 let end_needed = is_simple;
279 let iterator_needed = !is_simple;
280
281 let has_lifetime = self.type_has_lifetime(ftyp);
282
283 let args = if let Some(toplevel_typ) = toplevel_typ {
284 format!(
285 "R: *const {}, S: *const {}",
286 self.ffi_use_type_name(toplevel_typ),
287 ffi_typ
288 )
289 } else {
290 format!("R: *const {}", ffi_typ)
291 };
292
293 if accessor_needed {
294 let ftyp = self.ffi_use_type_name(ftyp);
295 let acc_fn = field_list_iterator_acc_fn_name(&self.xcb_mod_prefix, xcb_name, fname);
296 // the following only for diff equality with Python code
297 let param = if toplevel_typ.is_some() { "S" } else { "R" };
298 let out = &mut self.ffi_buf;
299 writeln!(out)?;
300 writeln!(
301 out,
302 "pub fn {}({}: *const {}) -> *mut {};",
303 &acc_fn, param, &ffi_typ, &ftyp
304 )?;
305 }
306
307 if length_needed {
308 let len_fn = field_list_iterator_len_fn_name(&self.xcb_mod_prefix, xcb_name, fname);
309 let out = &mut self.ffi_buf;
310 writeln!(out)?;
311 writeln!(out, "pub fn {}({}) -> c_int;", &len_fn, &args)?;
312 }
313
314 if end_needed {
315 let end_fn = field_list_iterator_end_fn_name(&self.xcb_mod_prefix, xcb_name, fname);
316 let out = &mut self.ffi_buf;
317 writeln!(out)?;
318 writeln!(
319 out,
320 "pub fn {}({}) -> xcb_generic_iterator_t;",
321 &end_fn, &args
322 )?;
323 }
324
325 if iterator_needed {
326 let lifetime = if has_lifetime { "<'a>" } else { "" };
327 let it_fn = field_list_iterator_it_fn_name(&self.xcb_mod_prefix, xcb_name, fname);
328 let it_typ = self.ffi_iterator_name(ftyp);
329 let out = &mut self.ffi_buf;
330 writeln!(out)?;
331 writeln!(
332 out,
333 "pub fn {}{}({}) -> {}{};",
334 &it_fn, &lifetime, &args, &it_typ, &lifetime
335 )?;
336 }
337 Ok(())
338 }
339
emit_ffi_field_list_accessors( &mut self, ffi_typ: &str, xcb_name: &str, fields: &[StructField], toplevel_typ: Option<&str>, is_switch: bool, ) -> io::Result<()>340 pub fn emit_ffi_field_list_accessors(
341 &mut self,
342 ffi_typ: &str,
343 xcb_name: &str,
344 fields: &[StructField],
345 toplevel_typ: Option<&str>,
346 is_switch: bool,
347 ) -> io::Result<()> {
348 for f in fields {
349 match f {
350 StructField::List {
351 name,
352 typ,
353 len_expr,
354 } => {
355 let fixed_size = self.ffi_type_sizeof(typ).is_some();
356 let fixed_len = expr_fixed_length(len_expr).is_some();
357
358 if fixed_size && fixed_len {
359 continue;
360 }
361 self.emit_ffi_field_list_accessor(
362 ffi_typ,
363 xcb_name,
364 name,
365 typ,
366 toplevel_typ,
367 fixed_size,
368 )?;
369 }
370 StructField::ListNoLen {
371 name, typ
372 } => {
373 let fixed_size = self.ffi_type_sizeof(typ).is_some();
374 self.emit_ffi_field_list_accessor(
375 ffi_typ,
376 xcb_name,
377 name,
378 typ,
379 toplevel_typ,
380 fixed_size,
381 )?;
382 }
383 StructField::ValueParam { list_name, .. } => {
384 self.emit_ffi_field_list_accessor(
385 ffi_typ,
386 xcb_name,
387 list_name,
388 "CARD32",
389 toplevel_typ,
390 true,
391 )?;
392 }
393 StructField::Field { name, typ, .. } => {
394 if is_switch && !self.typ_is_pod(typ) {
395 let fn_name = switch_accessor_fn(&self.xcb_mod_prefix, xcb_name, name);
396 let ret = self.ffi_use_type_name(typ);
397 let out = &mut self.ffi_buf;
398 writeln!(
399 out,
400 "pub fn {}(R: *const {}) -> *mut {};",
401 &fn_name, ffi_typ, ret,
402 )?;
403 }
404 }
405 StructField::Switch(name, ..) => {
406 let fn_name = switch_accessor_fn(&self.xcb_mod_prefix, xcb_name, name);
407 let ret = if is_switch {
408 let typ = xcb_name.to_string() + &capitalize(name);
409 self.notify_typ(typ.to_string());
410 self.ffi_use_type_name(&typ)
411 } else {
412 "c_void".to_string()
413 };
414
415 let out = &mut self.ffi_buf;
416
417 writeln!(
418 out,
419 "pub fn {}(R: *const {}) -> *mut {};",
420 &fn_name, ffi_typ, ret,
421 )?;
422 }
423 _ => {}
424 }
425 }
426 Ok(())
427 }
428
emit_ffi_struct( &mut self, stru: &Struct, case_req_name: Option<&str>, must_pack: bool, no_copy: bool, is_switch: bool, ) -> io::Result<String>429 pub fn emit_ffi_struct(
430 &mut self,
431 stru: &Struct,
432 case_req_name: Option<&str>,
433 must_pack: bool,
434 no_copy: bool,
435 is_switch: bool,
436 ) -> io::Result<String> {
437 let Struct { name, fields, doc } = &stru;
438
439 let ffi_typ = if name.starts_with('_') {
440 name.clone()
441 } else {
442 self.ffi_decl_type_name(name)
443 };
444
445 let impl_copy_clone = must_pack || self.eligible_to_copy(stru) && !no_copy;
446
447 let copyclone = if impl_copy_clone { "Copy, Clone, " } else { "" };
448
449 {
450 let must_pack = if must_pack { ", packed" } else { "" };
451
452 let out = &mut self.ffi;
453 writeln!(out)?;
454 emit_doc_text(out, doc)?;
455 writeln!(out, "#[derive({}Debug)]", copyclone)?;
456 writeln!(out, "#[repr(C{})]", must_pack)?;
457 writeln!(out, "pub struct {} {{", &ffi_typ)?;
458 }
459
460 // cases of ValueParam were the mask is declared as a field in the struct
461 // before the actual ValueParam field. We keep track of all fields written
462 // to avoid doubles
463 let mut written_fields = Vec::new();
464
465 for f in fields.iter() {
466 match f {
467 StructField::Field { name, typ, .. } | StructField::Expr { name, typ, .. } => {
468 let ptr = if self.ffi_type_sizeof(typ).is_some() {
469 ""
470 } else {
471 "*mut "
472 };
473 //let ptr = if self.typ_is_pod(&typ) { "" } else {"*mut "};
474 let typ = self.ffi_use_type_name(typ);
475 let out = &mut self.ffi;
476 emit_doc_field(out, doc, name)?;
477 writeln!(out, " pub {}: {}{},", field_name(name), ptr, typ,)?;
478 written_fields.push(name.as_str());
479 }
480 StructField::Pad(name, sz) => {
481 let out = &mut self.ffi;
482 let padtyp = match sz {
483 1 => "u8".into(),
484 x => format!("[u8; {}]", x),
485 };
486 writeln!(out, " pub {}: {},", name, padtyp)?;
487 }
488 StructField::AlignPad(name, _) => {
489 let out = &mut self.ffi;
490 if is_switch {
491 writeln!(out, " pub {}: *mut u8,", name)?;
492 }
493 }
494 StructField::List {
495 name,
496 typ,
497 len_expr,
498 } => {
499 if let Some(sz) = expr_fixed_length(len_expr) {
500 let typ = self.ffi_use_type_name(typ);
501 let out = &mut self.ffi;
502
503 emit_doc_field(out, doc, name)?;
504 writeln!(out, " pub {}: [{}; {}],", field_name(name), &typ, sz)?;
505 } else if is_switch {
506 let typ = self.ffi_use_type_name(typ);
507 let out = &mut self.ffi;
508
509 emit_doc_field(out, doc, name)?;
510 writeln!(out, " pub {}: *mut {},", field_name(name), &typ)?;
511 }
512 }
513 StructField::ValueParam {
514 mask_name,
515 mask_typ,
516 ..
517 } => {
518 if written_fields.contains(&mask_name.as_str()) {
519 continue;
520 }
521 let mask_typ = self.ffi_use_type_name(mask_typ);
522 let out = &mut self.ffi;
523 emit_doc_field(out, doc, mask_name)?;
524 writeln!(out, " pub {}: {},", field_name(mask_name), mask_typ,)?;
525 }
526 StructField::Switch(name, _, _) => {
527 if let Some(case_req_name) = case_req_name {
528 let typ = switch_struct_name(&self.xcb_mod_prefix, case_req_name, name);
529 let out = &mut self.ffi;
530 writeln!(out, " pub {}: {},", field_name(name), typ)?;
531 }
532 }
533 StructField::NamedCase(name, typ) => {
534 let out = &mut self.ffi;
535 writeln!(out, " pub {}: {},", field_name(name), typ)?;
536 }
537 _ => {}
538 }
539 }
540
541 let out = &mut self.ffi;
542 writeln!(out, "}}")?;
543
544 Ok(ffi_typ)
545 }
546
emit_ffi_switch_struct( &mut self, typ_name: &str, switch_name: &str, _expr: &Expr<usize>, cases: &[SwitchCase], toplevel_typ: &str, parent_switch: Option<&str>, ) -> io::Result<String>547 pub fn emit_ffi_switch_struct(
548 &mut self,
549 typ_name: &str,
550 switch_name: &str,
551 _expr: &Expr<usize>,
552 cases: &[SwitchCase],
553 toplevel_typ: &str,
554 parent_switch: Option<&str>,
555 ) -> io::Result<String> {
556 let fields = {
557 let mut fields = Vec::new();
558 for c in cases.iter() {
559 if let Some(name) = &c.name {
560 let typ = switch_named_case(&self.xcb_mod_prefix, typ_name, switch_name, name);
561 fields.push(StructField::NamedCase(name.clone(), typ));
562 } else {
563 fields.append(&mut c.fields.clone());
564 }
565 }
566 fields
567 };
568
569 let stru_name = typ_name.to_string() + &capitalize(switch_name);
570
571 let stru = Struct {
572 name: stru_name.clone(),
573 fields,
574 doc: None,
575 };
576 let ffi_typ = self.emit_ffi_struct(&stru, None, false, true, true)?;
577
578 let ffi_typ = parent_switch.unwrap_or(&ffi_typ);
579
580 self.emit_ffi_field_list_accessors(
581 ffi_typ,
582 &stru_name,
583 &stru.fields,
584 Some(toplevel_typ),
585 true,
586 )?;
587
588 for c in cases.iter() {
589 if let Some(name) = &c.name {
590 let typ = switch_named_case(&self.xcb_mod_prefix, typ_name, switch_name, name);
591 let stru = Struct {
592 name: typ.clone(),
593 fields: c.fields.clone(),
594 doc: None,
595 };
596 let case_req_name = stru_name.clone() + &capitalize(name);
597 self.emit_ffi_struct(&stru, Some(&case_req_name), false, true, true)?;
598
599 self.emit_ffi_field_list_accessors(
600 ffi_typ,
601 &case_req_name,
602 &stru.fields,
603 Some(toplevel_typ),
604 true,
605 )?;
606 }
607 }
608 for c in cases.iter() {
609 for f in c.fields.iter() {
610 if let StructField::Switch(cname, cexpr, ccases) = f {
611 let stru_name = if let Some(name) = &c.name {
612 stru_name.clone() + &capitalize(name)
613 } else {
614 stru_name.clone()
615 };
616 self.emit_ffi_switch_struct(
617 &stru_name,
618 cname,
619 cexpr,
620 ccases,
621 toplevel_typ,
622 Some(ffi_typ),
623 )?;
624 }
625 }
626 }
627 Ok(ffi_typ.to_string())
628 }
629
emit_ffi_req_fn( &mut self, req_name: &str, fn_name: &str, cookie_name: &str, fields: &[StructField], doc: &Option<Doc>, ) -> io::Result<()>630 pub fn emit_ffi_req_fn(
631 &mut self,
632 req_name: &str,
633 fn_name: &str,
634 cookie_name: &str,
635 fields: &[StructField],
636 doc: &Option<Doc>,
637 ) -> io::Result<()> {
638 let cookie_typ = self.ffi_use_type_name(cookie_name);
639 {
640 let out = &mut self.ffi_buf;
641 writeln!(out)?;
642 emit_doc_text(out, doc)?;
643 writeln!(out, " pub fn {} (", &fn_name)?;
644 writeln!(out, " c: *mut xcb_connection_t,")?;
645 }
646 let mut written_fields = Vec::new();
647 for f in fields.iter() {
648 match f {
649 StructField::Field { name, typ, .. } => {
650 written_fields.push(name);
651 let name = field_name(name);
652 let is_pod = self.typ_is_pod(typ);
653 let is_simple = self.typ_is_simple(typ);
654 let typ = self.ffi_use_type_name(typ);
655 if is_simple || is_pod {
656 writeln!(&mut self.ffi_buf, " {}: {},", &name, &typ)?;
657 } else {
658 writeln!(&mut self.ffi_buf, " {}: *mut {},", &name, &typ)?;
659 }
660 }
661 StructField::Fd(name) => {
662 let name = field_name(name);
663 writeln!(&mut self.ffi_buf, " {}: i32,", &name)?;
664 }
665 StructField::ValueParam {
666 mask_typ,
667 mask_name,
668 list_name,
669 } => {
670 let mask_typ = self.ffi_use_type_name(mask_typ);
671 let list_name = field_name(list_name);
672
673 let out = &mut self.ffi_buf;
674 if !written_fields.contains(&mask_name) {
675 let mask_name = field_name(mask_name);
676 writeln!(out, " {}: {},", &mask_name, &mask_typ)?;
677 }
678 writeln!(out, " {}: *const u32,", &list_name)?;
679 }
680 StructField::List { name, typ, .. } => {
681 let name = field_name(name);
682 let typ = self.ffi_use_type_name(typ);
683 let out = &mut self.ffi_buf;
684 writeln!(out, " {}: *const {},", &name, &typ)?;
685 }
686 StructField::ListNoLen { name, typ } => {
687 let len_name = name.clone() + "_len";
688 let name = field_name(name);
689 let typ = self.ffi_use_type_name(typ);
690 let out = &mut self.ffi_buf;
691 writeln!(out, " {}: u32,", &len_name)?;
692 writeln!(out, " {}: *const {},", &name, &typ)?;
693 }
694 StructField::Switch(name, ..) => {
695 let name = field_name(name);
696 let typ = switch_struct_name(&self.xcb_mod_prefix, req_name, &name);
697 writeln!(&mut self.ffi_buf, " {}: *const {},", &name, &typ)?;
698 }
699 _ => {}
700 }
701 }
702
703 let out = &mut self.ffi_buf;
704 writeln!(out, " ) -> {};", &cookie_typ)?;
705
706 Ok(())
707 }
708
emit_ffi_reply( &mut self, req_name: &str, mut reply: Reply, ) -> io::Result<(String, String, String)>709 pub fn emit_ffi_reply(
710 &mut self,
711 req_name: &str,
712 mut reply: Reply,
713 ) -> io::Result<(String, String, String)> {
714 // writting cookie struct
715 let cookie_name = req_name.to_string() + "Cookie";
716 let cookie_ffi_typ = self.ffi_decl_type_name(&cookie_name);
717 {
718 let out = &mut self.ffi;
719 writeln!(out)?;
720 writeln!(out, "#[derive(Copy, Clone, Debug)]")?;
721 writeln!(out, "#[repr(C)]")?;
722 writeln!(out, "pub struct {} {{", &cookie_ffi_typ)?;
723 writeln!(out, " pub(crate) sequence: c_uint,")?;
724 writeln!(out, "}}")?;
725 }
726
727 for f in &reply.fields {
728 if let StructField::Switch(name, expr, cases) = f {
729 let toplevel = req_name.to_string() + "Reply";
730 self.notify_typ(toplevel.clone());
731 self.emit_ffi_switch_struct(req_name, name, expr, cases, &toplevel, None)?;
732 }
733 }
734
735 let reply_fields = {
736 let mut fields = vec![
737 make_field("response_type".into(), "CARD8".into()),
738 if reply.fields.is_empty() {
739 StructField::Pad("pad0".into(), 1usize)
740 } else {
741 reply.fields.remove(0)
742 },
743 make_field("sequence".into(), "CARD16".into()),
744 make_field("length".into(), "CARD32".into()),
745 ];
746 fields.append(&mut reply.fields);
747 fields
748 };
749 let reply = Struct {
750 name: req_name.to_string() + "Reply",
751 fields: reply_fields,
752 doc: reply.doc,
753 };
754
755 let ffi_reply_typ = self.emit_ffi_struct(&reply, None, false, false, false)?;
756
757 self.emit_ffi_field_list_accessors(&ffi_reply_typ, req_name, &reply.fields, None, false)?;
758
759 let ffi_reply_fn = reply_fn_name(&self.xcb_mod_prefix, req_name);
760 {
761 let out = &mut self.ffi_buf;
762 writeln!(out)?;
763 writeln!(
764 out,
765 " /// the returned value must be freed by the caller using libc::free()."
766 )?;
767 writeln!(out, " pub fn {} (", &ffi_reply_fn)?;
768 writeln!(out, " c: *mut xcb_connection_t,")?;
769 writeln!(out, " cookie: {},", &cookie_ffi_typ)?;
770 writeln!(out, " error: *mut *mut xcb_generic_error_t,")?;
771 writeln!(out, " ) -> *mut {};", &ffi_reply_typ)?;
772 }
773
774 if has_fd(&reply.fields) {
775 let fds_fn = reply_fds_fn_name(&self.xcb_mod_prefix, req_name);
776 let out = &mut self.ffi_buf;
777 writeln!(out)?;
778 writeln!(out, " pub fn {}(", &fds_fn)?;
779 writeln!(out, " c: *mut xcb_connection_t,")?;
780 writeln!(out, " reply: *mut {},", &ffi_reply_typ)?;
781 writeln!(out, " ) -> *mut c_int;")?;
782 }
783
784 Ok((cookie_ffi_typ, ffi_reply_fn, ffi_reply_typ))
785 }
786 }
787
enum_item_name(xcb_mod_prefix: &str, name: &str, item: &str) -> String788 pub fn enum_item_name(xcb_mod_prefix: &str, name: &str, item: &str) -> String {
789 format!(
790 "XCB_{}{}_{}",
791 xcb_mod_prefix,
792 tit_dig_split(name),
793 tit_dig_split(item)
794 )
795 .to_ascii_uppercase()
796 }
797
iterator_next_fn_name(xcb_mod_prefix: &str, typ: &str) -> String798 pub fn iterator_next_fn_name(xcb_mod_prefix: &str, typ: &str) -> String {
799 format!(
800 "xcb_{}{}_next",
801 xcb_mod_prefix,
802 tit_dig_split(typ).to_ascii_lowercase()
803 )
804 }
805
iterator_end_fn_name(xcb_mod_prefix: &str, typ: &str) -> String806 pub fn iterator_end_fn_name(xcb_mod_prefix: &str, typ: &str) -> String {
807 format!(
808 "xcb_{}{}_end",
809 xcb_mod_prefix,
810 tit_dig_split(typ).to_ascii_lowercase()
811 )
812 }
813
field_list_iterator_acc_fn_name( xcb_mod_prefix: &str, typ_name: &str, field: &str, ) -> String814 pub fn field_list_iterator_acc_fn_name(
815 xcb_mod_prefix: &str,
816 typ_name: &str,
817 field: &str,
818 ) -> String {
819 format!(
820 "xcb_{}{}_{}",
821 &xcb_mod_prefix,
822 tit_dig_split(typ_name).to_ascii_lowercase(),
823 tit_dig_split(field).to_ascii_lowercase()
824 )
825 }
826
field_list_iterator_len_fn_name( xcb_mod_prefix: &str, typ_name: &str, field: &str, ) -> String827 pub fn field_list_iterator_len_fn_name(
828 xcb_mod_prefix: &str,
829 typ_name: &str,
830 field: &str,
831 ) -> String {
832 format!(
833 "xcb_{}{}_{}_length",
834 &xcb_mod_prefix,
835 tit_dig_split(typ_name).to_ascii_lowercase(),
836 tit_dig_split(field).to_ascii_lowercase()
837 )
838 }
839
field_list_iterator_end_fn_name( xcb_mod_prefix: &str, typ_name: &str, field: &str, ) -> String840 pub fn field_list_iterator_end_fn_name(
841 xcb_mod_prefix: &str,
842 typ_name: &str,
843 field: &str,
844 ) -> String {
845 format!(
846 "xcb_{}{}_{}_end",
847 &xcb_mod_prefix,
848 tit_dig_split(typ_name).to_ascii_lowercase(),
849 tit_dig_split(field).to_ascii_lowercase()
850 )
851 }
852
field_list_iterator_it_fn_name(xcb_mod_prefix: &str, typ_name: &str, field: &str) -> String853 pub fn field_list_iterator_it_fn_name(xcb_mod_prefix: &str, typ_name: &str, field: &str) -> String {
854 format!(
855 "xcb_{}{}_{}_iterator",
856 &xcb_mod_prefix,
857 tit_dig_split(typ_name).to_ascii_lowercase(),
858 tit_dig_split(field).to_ascii_lowercase()
859 )
860 }
861
switch_struct_name(xcb_mod_prefix: &str, req_name: &str, switch_name: &str) -> String862 pub fn switch_struct_name(xcb_mod_prefix: &str, req_name: &str, switch_name: &str) -> String {
863 format!(
864 "xcb_{}{}_{}_t",
865 &xcb_mod_prefix,
866 tit_dig_split(req_name).to_ascii_lowercase(),
867 tit_dig_split(switch_name).to_ascii_lowercase()
868 )
869 }
870
switch_accessor_fn(xcb_mod_prefix: &str, req_name: &str, switch_name: &str) -> String871 pub fn switch_accessor_fn(xcb_mod_prefix: &str, req_name: &str, switch_name: &str) -> String {
872 format!(
873 "xcb_{}{}_{}",
874 &xcb_mod_prefix,
875 tit_dig_split(req_name).to_ascii_lowercase(),
876 tit_dig_split(switch_name).to_ascii_lowercase()
877 )
878 }
879
switch_named_case( xcb_mod_prefix: &str, req_name: &str, switch_name: &str, case_name: &str, ) -> String880 pub fn switch_named_case(
881 xcb_mod_prefix: &str,
882 req_name: &str,
883 switch_name: &str,
884 case_name: &str,
885 ) -> String {
886 format!(
887 "_xcb_{}{}_{}__{}",
888 &xcb_mod_prefix,
889 tit_dig_split(req_name).to_ascii_lowercase(),
890 tit_dig_split(switch_name),
891 tit_dig_split(case_name)
892 )
893 }
894
request_fn_name(xcb_mod_prefix: &str, req_name: &str) -> String895 pub fn request_fn_name(xcb_mod_prefix: &str, req_name: &str) -> String {
896 format!(
897 "xcb_{}{}",
898 &xcb_mod_prefix,
899 tit_dig_split(req_name).to_ascii_lowercase(),
900 )
901 }
902
reply_fn_name(xcb_mod_prefix: &str, req_name: &str) -> String903 pub fn reply_fn_name(xcb_mod_prefix: &str, req_name: &str) -> String {
904 format!(
905 "xcb_{}{}_reply",
906 &xcb_mod_prefix,
907 tit_dig_split(req_name).to_ascii_lowercase(),
908 )
909 }
910
reply_fds_fn_name(xcb_mod_prefix: &str, req_name: &str) -> String911 pub fn reply_fds_fn_name(xcb_mod_prefix: &str, req_name: &str) -> String {
912 format!(
913 "xcb_{}{}_reply_fds",
914 &xcb_mod_prefix,
915 tit_dig_split(req_name).to_ascii_lowercase(),
916 )
917 }
918
opcode_name(xcb_mod_prefix: &str, name: &str) -> String919 pub fn opcode_name(xcb_mod_prefix: &str, name: &str) -> String {
920 format!(
921 "XCB_{}{}",
922 xcb_mod_prefix.to_ascii_uppercase(),
923 tit_dig_split(name).to_ascii_uppercase()
924 )
925 }
926
emit_opcode<Out: Write>( out: &mut Out, xcb_mod_prefix: &str, name: &str, num: i32, ) -> io::Result<()>927 pub fn emit_opcode<Out: Write>(
928 out: &mut Out,
929 xcb_mod_prefix: &str,
930 name: &str,
931 num: i32,
932 ) -> io::Result<()> {
933 let op_name = opcode_name(xcb_mod_prefix, name);
934 let num_typ = if num < 0 { "i8" } else { "u8" };
935 writeln!(out)?;
936 writeln!(out, "pub const {}: {} = {};", &op_name, &num_typ, num)?;
937 Ok(())
938 }
939