1use std::{
2 path::{Path, PathBuf},
3 str::FromStr,
4};
5
6use log::{trace, warn};
7
8use crate::{
9 library::*,
10 version::Version,
11 xmlparser::{Element, XmlParser},
12};
13
14const EMPTY_CTYPE: &str = "/*EMPTY*/";
15
16pub fn is_empty_c_type(c_type: &str) -> bool {
17 c_type == EMPTY_CTYPE
18}
19
20impl Library {
21 pub fn read_file<P: AsRef<Path>>(
22 &mut self,
23 dirs: &[P],
24 libs: &mut Vec<String>,
25 ) -> Result<(), String> {
26 for dir in dirs {
27 let dir: &Path = dir.as_ref();
28 let file_name = make_file_name(dir, &libs[libs.len() - 1]);
29 let Ok(mut parser) = XmlParser::from_path(&file_name) else {
30 continue;
31 };
32 return parser.document(|p, _| {
33 p.element_with_name("repository", |sub_parser, _elem| {
34 self.read_repository(dirs, sub_parser, libs)
35 })
36 });
37 }
38 Err(format!("Couldn't find `{}`...", &libs[libs.len() - 1]))
39 }
40
41 fn read_repository<P: AsRef<Path>>(
42 &mut self,
43 dirs: &[P],
44 parser: &mut XmlParser<'_>,
45 libs: &mut Vec<String>,
46 ) -> Result<(), String> {
47 let mut packages = Vec::new();
48 let mut includes = Vec::new();
49 parser.elements(|parser, elem| match elem.name() {
50 "include" => {
51 match (elem.attr("name"), elem.attr("version")) {
52 (Some(name), Some(ver)) => {
53 if self.find_namespace(name).is_none() {
54 let lib = format!("{name}-{ver}");
55 if libs.contains(&lib) {
56 return Err(format!(
57 "`{}` includes itself (full path:`{}`)!",
58 lib,
59 libs.join("::")
60 ));
61 }
62 libs.push(lib);
63 self.read_file(dirs, libs)?;
64 libs.pop();
65 }
66 }
67 (Some(name), None) => includes.push(name.to_owned()),
68 _ => {}
69 }
70 Ok(())
71 }
72 "package" => {
73 let name = elem.attr_required("name")?;
74 packages.push(name.to_owned());
75 Ok(())
76 }
77 "namespace" => self.read_namespace(
78 parser,
79 elem,
80 std::mem::take(&mut packages),
81 std::mem::take(&mut includes),
82 ),
83 "format" => parser.ignore_element(),
84 "attribute" => parser.ignore_element(),
85 _ => Err(parser.unexpected_element(elem)),
86 })?;
87 Ok(())
88 }
89
90 fn read_namespace(
91 &mut self,
92 parser: &mut XmlParser<'_>,
93 elem: &Element,
94 packages: Vec<String>,
95 c_includes: Vec<String>,
96 ) -> Result<(), String> {
97 let ns_name = elem.attr_required("name")?;
98 let ns_id = self.add_namespace(ns_name);
99
100 {
101 let ns = self.namespace_mut(ns_id);
102 ns.package_names = packages;
103 ns.c_includes = c_includes;
104 if let Some(s) = elem.attr("shared-library") {
105 ns.shared_library = s
106 .split(',')
107 .filter_map(|x| {
108 if !x.is_empty() {
109 Some(String::from(x))
110 } else {
111 None
112 }
113 })
114 .collect();
115 }
116 if let Some(s) = elem.attr("identifier-prefixes") {
117 ns.identifier_prefixes = s.split(',').map(String::from).collect();
118 }
119 if let Some(s) = elem.attr("symbol-prefixes") {
120 ns.symbol_prefixes = s.split(',').map(String::from).collect();
121 }
122 }
123
124 trace!(
125 "Reading {}-{}",
126 ns_name,
127 elem.attr("version").unwrap_or("?")
128 );
129
130 parser.elements(|parser, elem| {
131 trace!("<{} name={:?}>", elem.name(), elem.attr("name"));
132 match elem.name() {
133 "class" => self.read_class(parser, ns_id, elem),
134 "record" => self.read_record_start(parser, ns_id, elem),
135 "union" => self.read_named_union(parser, ns_id, elem),
136 "interface" => self.read_interface(parser, ns_id, elem),
137 "callback" => self.read_named_callback(parser, ns_id, elem),
138 "bitfield" => self.read_bitfield(parser, ns_id, elem),
139 "enumeration" => self.read_enumeration(parser, ns_id, elem),
140 "function" => self.read_global_function(parser, ns_id, elem),
141 "constant" => self.read_constant(parser, ns_id, elem),
142 "alias" => self.read_alias(parser, ns_id, elem),
143 "boxed" | "function-macro" | "docsection" | "function-inline" => {
144 parser.ignore_element()
145 }
146 _ => {
147 warn!("<{} name={:?}>", elem.name(), elem.attr("name"));
148 parser.ignore_element()
149 }
150 }
151 })?;
152 Ok(())
153 }
154
155 fn read_class(
156 &mut self,
157 parser: &mut XmlParser<'_>,
158 ns_id: u16,
159 elem: &Element,
160 ) -> Result<(), String> {
161 let class_name = elem.attr_required("name")?;
162 let c_type = self.read_object_c_type(parser, elem)?;
163 let symbol_prefix = elem.attr_required("symbol-prefix").map(ToOwned::to_owned)?;
164 let type_struct = elem.attr("type-struct").map(ToOwned::to_owned);
165 let get_type = elem.attr_required("get-type")?;
166 let version = self.read_version(parser, ns_id, elem)?;
167 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
168 let is_fundamental = elem.attr("fundamental").is_some_and(|x| x == "1");
169 let (ref_fn, unref_fn) = if is_fundamental {
170 (
171 elem.attr("ref-func").map(ToOwned::to_owned),
172 elem.attr("unref-func").map(ToOwned::to_owned),
173 )
174 } else {
175 (None, None)
176 };
177
178 let is_abstract = elem.attr("abstract").is_some_and(|x| x == "1");
179 let final_type = elem.attr("final").is_some_and(|x| x == "1");
180
181 let mut fns = Vec::new();
182 let mut signals = Vec::new();
183 let mut properties = Vec::new();
184 let mut impls = Vec::new();
185 let mut fields = Vec::new();
186 let mut vfns = Vec::new();
187 let mut doc = None;
188 let mut doc_deprecated = None;
189 let mut union_count = 1;
190
191 parser.elements(|parser, elem| match elem.name() {
192 "constructor" | "function" | "method" => {
193 self.read_function_to_vec(parser, ns_id, elem, &mut fns)
194 }
195 "implements" => self.read_type(parser, ns_id, elem).map(|r| {
196 impls.push(r.0);
197 }),
198 "signal" => self
199 .read_signal(parser, ns_id, elem)
200 .map(|s| signals.push(s)),
201 "property" => self
202 .read_property(parser, ns_id, elem, &symbol_prefix)
203 .map(|p| {
204 if let Some(p) = p {
205 properties.push(p);
206 }
207 }),
208 "field" => self.read_field(parser, ns_id, elem).map(|f| {
209 fields.push(f);
210 }),
211 "virtual-method" => self
212 .read_virtual_method(parser, ns_id, elem)
213 .map(|v| vfns.push(v)),
214 "doc" => parser.text().map(|t| doc = Some(t)),
215 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
216 "doc-version" => parser.ignore_element(),
217 "source-position" => parser.ignore_element(),
218 "union" => self
219 .read_union(parser, ns_id, elem, Some(class_name), Some(c_type))
220 .map(|mut u| {
221 let field_name = if let Some(field_name) = elem.attr("name") {
222 field_name.into()
223 } else {
224 format!("u{union_count}")
225 };
226
227 u = Union {
228 name: format!("{class_name}_{field_name}"),
229 c_type: Some(format!("{c_type}_{field_name}")),
230 ..u
231 };
232
233 let u_doc = u.doc.clone();
234 let ctype = u.c_type.clone();
235
236 fields.push(Field {
237 name: field_name,
238 typ: Type::union(self, u, ns_id),
239 doc: u_doc,
240 c_type: ctype,
241 ..Field::default()
242 });
243 union_count += 1;
244 }),
245 "attribute" => parser.ignore_element(),
246 _ => Err(parser.unexpected_element(elem)),
247 })?;
248
249 let parent = elem
250 .attr("parent")
251 .map(|s| self.find_or_stub_type(ns_id, s));
252 let typ = Type::Class(Class {
253 name: class_name.into(),
254 c_type: c_type.into(),
255 type_struct,
256 c_class_type: None, glib_get_type: get_type.into(),
258 fields,
259 functions: fns,
260 virtual_methods: vfns,
261 signals,
262 properties,
263 parent,
264 implements: impls,
265 final_type,
266 doc,
267 doc_deprecated,
268 version,
269 deprecated_version,
270 symbol_prefix,
271 is_abstract,
272 is_fundamental,
273 ref_fn,
274 unref_fn,
275 });
276 self.add_type(ns_id, class_name, typ);
277 Ok(())
278 }
279
280 fn read_record_start(
281 &mut self,
282 parser: &mut XmlParser<'_>,
283 ns_id: u16,
284 elem: &Element,
285 ) -> Result<(), String> {
286 if let Some(typ) = self.read_record(parser, ns_id, elem, None, None)? {
287 let name = typ.get_name();
288 self.add_type(ns_id, &name, typ);
289 }
290 Ok(())
291 }
292
293 fn read_record(
294 &mut self,
295 parser: &mut XmlParser<'_>,
296 ns_id: u16,
297 elem: &Element,
298 parent_name_prefix: Option<&str>,
299 parent_ctype_prefix: Option<&str>,
300 ) -> Result<Option<Type>, String> {
301 let record_name = elem.attr("name").unwrap_or_default();
302 if record_name.starts_with('_') {
304 parser.ignore_element()?;
305 return Ok(None);
306 }
307 let is_class_record = record_name.ends_with("Class");
308
309 let c_type = elem.attr("type").unwrap_or_default();
310 let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned);
311 let get_type = elem.attr("get-type").map(ToOwned::to_owned);
312 let gtype_struct_for = elem.attr("is-gtype-struct-for");
313 let version = self.read_version(parser, ns_id, elem)?;
314 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
315 let pointer = elem.attr_bool("pointer", false);
316 let disguised = elem.attr_bool("disguised", false);
317
318 let mut fields = Vec::new();
319 let mut fns = Vec::new();
320 let mut doc = None;
321 let mut doc_deprecated = None;
322 let mut union_count = 1;
323
324 parser.elements(|parser, elem| match elem.name() {
325 "constructor" | "function" | "method" => {
326 self.read_function_to_vec(parser, ns_id, elem, &mut fns)
327 }
328 "union" => self
329 .read_union(parser, ns_id, elem, Some(record_name), Some(c_type))
330 .map(|mut u| {
331 let field_name = if let Some(field_name) = elem.attr("name") {
332 field_name.into()
333 } else {
334 format!("u{union_count}")
335 };
336
337 u = Union {
338 name: format!(
339 "{}{}_{}",
340 parent_name_prefix.map_or_else(String::new, |s| { format!("{s}_") }),
341 record_name,
342 field_name
343 ),
344 c_type: Some(format!(
345 "{}{}_{}",
346 parent_ctype_prefix.map_or_else(String::new, |s| { format!("{s}_") }),
347 c_type,
348 field_name
349 )),
350 ..u
351 };
352
353 let u_doc = u.doc.clone();
354 let ctype = u.c_type.clone();
355
356 fields.push(Field {
357 name: field_name,
358 typ: Type::union(self, u, ns_id),
359 doc: u_doc,
360 c_type: ctype,
361 ..Field::default()
362 });
363 union_count += 1;
364 }),
365 "field" => {
366 self.read_field(parser, ns_id, elem).map(|mut f| {
367 if c_type == "GDate" {
369 if f.name == "julian_days" {
370 fields.push(f);
371 } else if f.name == "julian" {
372 f.name = "flags_dmy".into();
373 f.typ = TypeId::tid_uint32();
374 f.c_type = Some("guint".into());
375 f.bits = None;
376 fields.push(f);
377 } else {
378 }
380 return;
381 }
382 if c_type == "GValue" && f.name == "data" {
384 f.c_type = Some("GValue_data".into());
385 }
386 fields.push(f);
387 })
388 }
389 "doc" => parser.text().map(|t| doc = Some(t)),
390 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
391 "doc-version" => parser.ignore_element(),
392 "source-position" => parser.ignore_element(),
393 "attribute" => parser.ignore_element(),
394 "method-inline" => parser.ignore_element(),
395 _ => Err(parser.unexpected_element(elem)),
396 })?;
397
398 let typ = Type::Record(Record {
399 name: record_name.into(),
400 c_type: c_type.into(),
401 glib_get_type: get_type,
402 functions: if is_class_record && gtype_struct_for.is_some() {
403 fns.into_iter()
404 .map(|mut f| {
405 f.kind = FunctionKind::ClassMethod;
406 f
407 })
408 .collect::<Vec<_>>()
409 } else {
410 fns
411 },
412 gtype_struct_for: gtype_struct_for.map(|s| s.into()),
413 fields,
414 version,
415 deprecated_version,
416 doc,
417 doc_deprecated,
418 disguised,
419 pointer,
420 symbol_prefix,
421 });
422
423 Ok(Some(typ))
424 }
425
426 fn read_named_union(
427 &mut self,
428 parser: &mut XmlParser<'_>,
429 ns_id: u16,
430 elem: &Element,
431 ) -> Result<(), String> {
432 elem.attr_required("name")?;
434
435 self.read_union(parser, ns_id, elem, None, None)
436 .and_then(|mut u| {
437 assert_ne!(u.name, "");
438 if u.name == "_Value__data__union" {
440 u.c_type = Some("GValue_data".into());
441 } else if u.c_type.is_none() {
442 return Err(parser.fail("Missing union c:type"));
443 }
444 let union_name = u.name.clone();
445 self.add_type(ns_id, &union_name, Type::Union(u));
446 Ok(())
447 })
448 }
449
450 fn read_union(
451 &mut self,
452 parser: &mut XmlParser<'_>,
453 ns_id: u16,
454 elem: &Element,
455 parent_name_prefix: Option<&str>,
456 parent_ctype_prefix: Option<&str>,
457 ) -> Result<Union, String> {
458 let union_name = elem.attr("name").unwrap_or("");
459 let c_type = self.read_object_c_type(parser, elem).unwrap_or("");
460 let get_type = elem.attr("get-type").map(|s| s.into());
461 let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned);
462
463 let mut fields = Vec::new();
464 let mut fns = Vec::new();
465 let mut doc = None;
466 let mut struct_count = 1;
467
468 parser.elements(|parser, elem| match elem.name() {
469 "source-position" => parser.ignore_element(),
470 "field" => self.read_field(parser, ns_id, elem).map(|f| {
471 fields.push(f);
472 }),
473 "constructor" | "function" | "method" => {
474 self.read_function_to_vec(parser, ns_id, elem, &mut fns)
475 }
476 "record" => {
477 let mut r = match self.read_record(
478 parser,
479 ns_id,
480 elem,
481 parent_name_prefix,
482 parent_ctype_prefix,
483 )? {
484 Some(Type::Record(r)) => r,
485 _ => return Ok(()),
486 };
487
488 let field_name = if let Some(field_name) = elem.attr("name") {
489 field_name.into()
490 } else {
491 format!("s{struct_count}")
492 };
493
494 r = Record {
495 name: format!(
496 "{}{}_{}",
497 parent_name_prefix.map_or_else(String::new, |s| { format!("{s}_") }),
498 union_name,
499 field_name
500 ),
501 c_type: format!(
502 "{}{}_{}",
503 parent_ctype_prefix.map_or_else(String::new, |s| { format!("{s}_") }),
504 c_type,
505 field_name
506 ),
507 ..r
508 };
509
510 let r_doc = r.doc.clone();
511 let ctype = r.c_type.clone();
512
513 fields.push(Field {
514 name: field_name,
515 typ: Type::record(self, r, ns_id),
516 doc: r_doc,
517 c_type: Some(ctype),
518 ..Field::default()
519 });
520
521 struct_count += 1;
522
523 Ok(())
524 }
525 "doc" => parser.text().map(|t| doc = Some(t)),
526 "attribute" => parser.ignore_element(),
527 _ => Err(parser.unexpected_element(elem)),
528 })?;
529
530 Ok(Union {
531 name: union_name.into(),
532 c_type: Some(c_type.into()),
533 glib_get_type: get_type,
534 fields,
535 functions: fns,
536 doc,
537 symbol_prefix,
538 })
539 }
540
541 fn read_virtual_method(
542 &mut self,
543 parser: &mut XmlParser,
544 ns_id: u16,
545 elem: &Element,
546 ) -> Result<Function, String> {
547 let method_name = elem.attr_required("name")?;
548 let version = self.read_version(parser, ns_id, elem)?;
549 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
550 let c_identifier = elem.attr("identifier").or_else(|| elem.attr("name"));
551 let mut params = Vec::new();
552 let mut ret = None;
553 let mut doc = None;
554 let mut doc_deprecated = None;
555
556 parser.elements(|parser, elem| match elem.name() {
557 "parameters" => self
558 .read_parameters(parser, ns_id, true, true)
559 .map(|mut ps| params.append(&mut ps)),
560 "return-value" => {
561 if ret.is_some() {
562 return Err(parser.fail("Too many <return-value> elements"));
563 }
564 self.read_parameter(parser, ns_id, elem, true, false)
565 .map(|p| ret = Some(p))
566 }
567 "source-position" => parser.ignore_element(),
568 "doc" => parser.text().map(|t| doc = Some(t)),
569 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
570 "doc-version" => parser.ignore_element(),
571 "attribute" => parser.ignore_element(),
572 _ => Err(parser.unexpected_element(elem)),
573 })?;
574
575 let throws = elem.attr_bool("throws", false);
576 if throws {
577 params.push(Parameter {
578 name: "error".into(),
579 typ: self.find_or_stub_type(ns_id, "GLib.Error"),
580 c_type: "GError**".into(),
581 instance_parameter: false,
582 direction: ParameterDirection::Out,
583 transfer: Transfer::Full,
584 caller_allocates: false,
585 nullable: Nullable(true),
586 array_length: None,
587 is_error: true,
588 doc: None,
589 scope: ParameterScope::None,
590 closure: None,
591 destroy: None,
592 });
593 }
594
595 if let Some(ret) = ret {
596 Ok(Function {
597 name: method_name.into(),
598 c_identifier: c_identifier.map(|s| s.into()),
599 kind: FunctionKind::VirtualMethod,
600 parameters: params,
601 ret,
602 throws,
603 version,
604 deprecated_version,
605 doc,
606 doc_deprecated,
607 get_property: None,
608 set_property: None,
609 finish_func: None,
610 async_func: None,
611 sync_func: None,
612 })
613 } else {
614 Err(parser.fail("Missing <return-value> element"))
615 }
616 }
617
618 fn read_field(
619 &mut self,
620 parser: &mut XmlParser<'_>,
621 ns_id: u16,
622 elem: &Element,
623 ) -> Result<Field, String> {
624 let field_name = elem.attr_required("name")?;
625 let private = elem.attr_bool("private", false);
626 let bits = elem.attr("bits").and_then(|s| s.parse().ok());
627
628 let mut typ = None;
629 let mut doc = None;
630
631 parser.elements(|parser, elem| match elem.name() {
632 "type" | "array" => {
633 if typ.is_some() {
634 return Err(parser.fail("Too many <type> elements"));
635 }
636 self.read_type(parser, ns_id, elem).map(|t| {
637 typ = Some(t);
638 })
639 }
640 "callback" => {
641 if typ.is_some() {
642 return Err(parser.fail("Too many <type> elements"));
643 }
644 self.read_function(parser, ns_id, elem.name(), elem, true)
645 .map(|f| {
646 typ = Some((Type::function(self, f), None, None));
647 })
648 }
649 "doc" => parser.text().map(|t| doc = Some(t)),
650 "source-position" => parser.ignore_element(),
651 "attribute" => parser.ignore_element(),
652 _ => Err(parser.unexpected_element(elem)),
653 })?;
654
655 if let Some((tid, c_type, array_length)) = typ {
656 Ok(Field {
657 name: field_name.into(),
658 typ: tid,
659 c_type,
660 private,
661 bits,
662 array_length,
663 doc,
664 })
665 } else {
666 Err(parser.fail("Missing <type> element"))
667 }
668 }
669
670 fn read_named_callback(
671 &mut self,
672 parser: &mut XmlParser<'_>,
673 ns_id: u16,
674 elem: &Element,
675 ) -> Result<(), String> {
676 self.read_function_if_not_moved(parser, ns_id, elem.name(), elem, true)?
677 .map(|func| {
678 let name = func.name.clone();
679 self.add_type(ns_id, &name, Type::Function(func))
680 });
681
682 Ok(())
683 }
684
685 fn read_interface(
686 &mut self,
687 parser: &mut XmlParser<'_>,
688 ns_id: u16,
689 elem: &Element,
690 ) -> Result<(), String> {
691 let interface_name = elem.attr_required("name")?;
692 let c_type = self.read_object_c_type(parser, elem)?;
693 let symbol_prefix = elem.attr_required("symbol-prefix").map(ToOwned::to_owned)?;
694 let type_struct = elem.attr("type-struct").map(ToOwned::to_owned);
695 let get_type = elem.attr_required("get-type")?;
696 let version = self.read_version(parser, ns_id, elem)?;
697 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
698
699 let mut fns = Vec::new();
700 let mut vfns = Vec::new();
701 let mut signals = Vec::new();
702 let mut properties = Vec::new();
703 let mut prereqs = Vec::new();
704 let mut doc = None;
705 let mut doc_deprecated = None;
706
707 parser.elements(|parser, elem| match elem.name() {
708 "constructor" | "function" | "method" => {
709 self.read_function_to_vec(parser, ns_id, elem, &mut fns)
710 }
711 "prerequisite" => self.read_type(parser, ns_id, elem).map(|r| {
712 prereqs.push(r.0);
713 }),
714 "signal" => self
715 .read_signal(parser, ns_id, elem)
716 .map(|s| signals.push(s)),
717 "property" => self
718 .read_property(parser, ns_id, elem, &symbol_prefix)
719 .map(|p| {
720 if let Some(p) = p {
721 properties.push(p);
722 }
723 }),
724 "doc" => parser.text().map(|t| doc = Some(t)),
725 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
726 "doc-version" => parser.ignore_element(),
727 "virtual-method" => self
728 .read_virtual_method(parser, ns_id, elem)
729 .map(|v| vfns.push(v)),
730 "source-position" => parser.ignore_element(),
731 "attribute" => parser.ignore_element(),
732 _ => Err(parser.unexpected_element(elem)),
733 })?;
734
735 let typ = Type::Interface(Interface {
736 name: interface_name.into(),
737 c_type: c_type.into(),
738 type_struct,
739 c_class_type: None, glib_get_type: get_type.into(),
741 functions: fns,
742 virtual_methods: vfns,
743 signals,
744 properties,
745 prerequisites: prereqs,
746 doc,
747 doc_deprecated,
748 version,
749 deprecated_version,
750 symbol_prefix,
751 });
752 self.add_type(ns_id, interface_name, typ);
753 Ok(())
754 }
755
756 fn read_bitfield(
757 &mut self,
758 parser: &mut XmlParser<'_>,
759 ns_id: u16,
760 elem: &Element,
761 ) -> Result<(), String> {
762 let bitfield_name = elem.attr_required("name")?;
763 let c_type = self.read_object_c_type(parser, elem)?;
764 let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned);
765 let get_type = elem.attr("get-type").map(|s| s.into());
766 let version = self.read_version(parser, ns_id, elem)?;
767 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
768
769 let mut members = Vec::new();
770 let mut fns = Vec::new();
771 let mut doc = None;
772 let mut doc_deprecated = None;
773
774 parser.elements(|parser, elem| match elem.name() {
775 "member" => self
776 .read_member(parser, ns_id, elem)
777 .map(|m| members.push(m)),
778 "constructor" | "function" | "method" => {
779 self.read_function_to_vec(parser, ns_id, elem, &mut fns)
780 }
781 "doc" => parser.text().map(|t| doc = Some(t)),
782 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
783 "doc-version" => parser.ignore_element(),
784 "source-position" => parser.ignore_element(),
785 "attribute" => parser.ignore_element(),
786 _ => Err(parser.unexpected_element(elem)),
787 })?;
788
789 let typ = Type::Bitfield(Bitfield {
790 name: bitfield_name.into(),
791 c_type: c_type.into(),
792 members,
793 functions: fns,
794 version,
795 deprecated_version,
796 doc,
797 doc_deprecated,
798 glib_get_type: get_type,
799 symbol_prefix,
800 });
801 self.add_type(ns_id, bitfield_name, typ);
802 Ok(())
803 }
804
805 fn read_enumeration(
806 &mut self,
807 parser: &mut XmlParser<'_>,
808 ns_id: u16,
809 elem: &Element,
810 ) -> Result<(), String> {
811 let enum_name = elem.attr_required("name")?;
812 let c_type = self.read_object_c_type(parser, elem)?;
813 let symbol_prefix = elem.attr("symbol-prefix").map(ToOwned::to_owned);
814 let get_type = elem.attr("get-type").map(|s| s.into());
815 let version = self.read_version(parser, ns_id, elem)?;
816 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
817 let error_domain = elem
818 .attr("error-domain")
819 .map(|s| ErrorDomain::Quark(String::from(s)));
820
821 let mut members = Vec::new();
822 let mut fns = Vec::new();
823 let mut doc = None;
824 let mut doc_deprecated = None;
825
826 parser.elements(|parser, elem| match elem.name() {
827 "member" => self
828 .read_member(parser, ns_id, elem)
829 .map(|m| members.push(m)),
830 "constructor" | "function" | "method" => {
831 self.read_function_to_vec(parser, ns_id, elem, &mut fns)
832 }
833 "doc" => parser.text().map(|t| doc = Some(t)),
834 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
835 "doc-version" => parser.ignore_element(),
836 "source-position" => parser.ignore_element(),
837 "attribute" => parser.ignore_element(),
838 _ => Err(parser.unexpected_element(elem)),
839 })?;
840
841 let typ = Type::Enumeration(Enumeration {
842 name: enum_name.into(),
843 c_type: c_type.into(),
844 members,
845 functions: fns,
846 version,
847 deprecated_version,
848 doc,
849 doc_deprecated,
850 error_domain,
851 glib_get_type: get_type,
852 symbol_prefix,
853 });
854 self.add_type(ns_id, enum_name, typ);
855 Ok(())
856 }
857
858 fn read_global_function(
859 &mut self,
860 parser: &mut XmlParser<'_>,
861 ns_id: u16,
862 elem: &Element,
863 ) -> Result<(), String> {
864 self.read_function_if_not_moved(parser, ns_id, "global", elem, false)
865 .map(|func| {
866 if let Some(func) = func {
867 self.add_function(ns_id, func);
868 }
869 })
870 }
871
872 fn read_constant(
873 &mut self,
874 parser: &mut XmlParser<'_>,
875 ns_id: u16,
876 elem: &Element,
877 ) -> Result<(), String> {
878 let const_name = elem.attr_required("name")?;
879 let c_identifier = elem.attr_required("type")?;
880 let value = elem.attr_required("value")?;
881 let version = self.read_version(parser, ns_id, elem)?;
882 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
883
884 let mut inner = None;
885 let mut doc = None;
886 let mut doc_deprecated = None;
887
888 parser.elements(|parser, elem| match elem.name() {
889 "type" | "array" => {
890 if inner.is_some() {
891 return Err(parser.fail_with_position(
892 "Too many <type> inner elements in <constant> element",
893 elem.position(),
894 ));
895 }
896 let (typ, c_type, array_length) = self.read_type(parser, ns_id, elem)?;
897 if let Some(c_type) = c_type {
898 inner = Some((typ, c_type, array_length));
899 } else {
900 return Err(parser.fail_with_position(
901 "Missing <constant> element's c:type",
902 elem.position(),
903 ));
904 }
905 Ok(())
906 }
907 "doc" => parser.text().map(|t| doc = Some(t)),
908 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
909 "doc-version" => parser.ignore_element(),
910 "source-position" => parser.ignore_element(),
911 "attribute" => parser.ignore_element(),
912 _ => Err(parser.unexpected_element(elem)),
913 })?;
914
915 if let Some((typ, c_type, _array_length)) = inner {
916 self.add_constant(
917 ns_id,
918 Constant {
919 name: const_name.into(),
920 c_identifier: c_identifier.into(),
921 typ,
922 c_type,
923 value: value.into(),
924 version,
925 deprecated_version,
926 doc,
927 doc_deprecated,
928 },
929 );
930 Ok(())
931 } else {
932 Err(parser.fail_with_position(
933 "Missing <type> element inside <constant> element",
934 elem.position(),
935 ))
936 }
937 }
938
939 fn read_alias(
940 &mut self,
941 parser: &mut XmlParser<'_>,
942 ns_id: u16,
943 elem: &Element,
944 ) -> Result<(), String> {
945 let alias_name = elem.attr_required("name")?;
946 let c_identifier = elem.attr_required("type")?;
947
948 let mut inner = None;
949 let mut doc = None;
950 let mut doc_deprecated = None;
951
952 parser.elements(|parser, elem| match elem.name() {
953 "source-position" => parser.ignore_element(),
954 "type" | "array" => {
955 if inner.is_some() {
956 return Err(parser.fail_with_position(
957 "Too many <type> inner elements in <alias> element",
958 elem.position(),
959 ));
960 }
961 let (typ, c_type, array_length) = self.read_type(parser, ns_id, elem)?;
962 if let Some(c_type) = c_type {
963 inner = Some((typ, c_type, array_length));
964 } else {
965 return Err(parser.fail("Missing <alias> target's c:type"));
966 }
967 Ok(())
968 }
969 "doc" => parser.text().map(|t| doc = Some(t)),
970 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
971 "doc-version" => parser.ignore_element(),
972 "attribute" => parser.ignore_element(),
973 _ => Err(parser.unexpected_element(elem)),
974 })?;
975
976 if let Some((typ, c_type, _array_length)) = inner {
977 let typ = Type::Alias(Alias {
978 name: alias_name.into(),
979 c_identifier: c_identifier.into(),
980 typ,
981 target_c_type: c_type,
982 doc,
983 doc_deprecated,
984 });
985 self.add_type(ns_id, alias_name, typ);
986 Ok(())
987 } else {
988 Err(parser.fail_with_position(
989 "Missing <type> element inside <alias> element",
990 elem.position(),
991 ))
992 }
993 }
994
995 fn read_member(
996 &mut self,
997 parser: &mut XmlParser<'_>,
998 ns_id: u16,
999 elem: &Element,
1000 ) -> Result<Member, String> {
1001 let member_name = elem.attr_required("name")?;
1002 let value = elem.attr_required("value")?;
1003 let c_identifier = elem.attr("identifier").map(|x| x.into());
1004 let version = self.read_version(parser, ns_id, elem)?;
1005 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
1006
1007 let mut doc = None;
1008 let mut doc_deprecated = None;
1009
1010 parser.elements(|parser, elem| match elem.name() {
1011 "doc" => parser.text().map(|t| doc = Some(t)),
1012 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
1013 "doc-version" => parser.ignore_element(),
1014 "attribute" => parser.ignore_element(),
1015 _ => Err(parser.unexpected_element(elem)),
1016 })?;
1017
1018 Ok(Member {
1019 name: member_name.into(),
1020 value: value.into(),
1021 doc,
1022 doc_deprecated,
1023 c_identifier: c_identifier.unwrap_or_else(|| member_name.into()),
1024 status: crate::config::gobjects::GStatus::Generate,
1025 version,
1026 deprecated_version,
1027 })
1028 }
1029
1030 fn read_function(
1031 &mut self,
1032 parser: &mut XmlParser<'_>,
1033 ns_id: u16,
1034 kind_str: &str,
1035 elem: &Element,
1036 is_callback: bool,
1037 ) -> Result<Function, String> {
1038 let fn_name = elem.attr_required("name")?;
1039 let c_identifier = elem.attr("identifier").or_else(|| elem.attr("type"));
1040 let kind = FunctionKind::from_str(kind_str).map_err(|why| parser.fail(&why))?;
1041 let is_method = kind == FunctionKind::Method;
1042 let version = self.read_version(parser, ns_id, elem)?;
1043 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
1044 let mut gtk_get_property = None;
1045 let mut gtk_set_property = None;
1046 let finish_func = c_identifier.and_then(|c_identifier| {
1047 elem.attr("finish-func").map(|finish_func_name| {
1048 format!(
1049 "{}{finish_func_name}",
1050 c_identifier.strip_suffix(&fn_name).unwrap()
1051 )
1052 })
1053 });
1054 let async_func = elem.attr("async-func").map(ToString::to_string);
1055 let sync_func = elem.attr("sync-func").map(ToString::to_string);
1056
1057 let mut params = Vec::new();
1058 let mut ret = None;
1059 let mut doc = None;
1060 let mut doc_deprecated = None;
1061
1062 parser.elements(|parser, elem| match elem.name() {
1063 "parameters" => self
1064 .read_parameters(parser, ns_id, false, is_method)
1065 .map(|mut ps| params.append(&mut ps)),
1066 "return-value" => {
1067 if ret.is_some() {
1068 return Err(parser.fail_with_position(
1069 "Too many <return-value> elements inside <function> element",
1070 elem.position(),
1071 ));
1072 }
1073 ret = Some(self.read_parameter(parser, ns_id, elem, false, is_method)?);
1074 Ok(())
1075 }
1076 "doc" => parser.text().map(|t| doc = Some(t)),
1077 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
1078 "doc-version" => parser.ignore_element(),
1079 "source-position" => parser.ignore_element(),
1080 "attribute" => {
1081 if let (Some(name), Some(value)) = (elem.attr("name"), elem.attr("value")) {
1082 match name {
1083 "org.gtk.Method.get_property" => {
1084 gtk_get_property = Some(value.to_string());
1085 Ok(())
1086 }
1087 "org.gtk.Method.set_property" => {
1088 gtk_set_property = Some(value.to_string());
1089 Ok(())
1090 }
1091 _ => parser.ignore_element(),
1092 }
1093 } else {
1094 parser.ignore_element()
1095 }
1096 }
1097 _ => Err(parser.unexpected_element(elem)),
1098 })?;
1099
1100 let get_property = gtk_get_property.or(elem.attr("get-property").map(ToString::to_string));
1101 let set_property = gtk_set_property.or(elem.attr("set-property").map(ToString::to_string));
1102 if is_callback && params.last().map(|x| x.closure.is_none()).unwrap_or(false) {
1105 params.last_mut().unwrap().closure = Some(2000);
1106 }
1107
1108 let throws = elem.attr_bool("throws", false);
1109 if throws {
1110 params.push(Parameter {
1111 name: "error".into(),
1112 typ: self.find_or_stub_type(ns_id, "GLib.Error"),
1113 c_type: "GError**".into(),
1114 instance_parameter: false,
1115 direction: ParameterDirection::Out,
1116 transfer: Transfer::Full,
1117 caller_allocates: false,
1118 nullable: Nullable(true),
1119 array_length: None,
1120 is_error: true,
1121 doc: None,
1122 scope: ParameterScope::None,
1123 closure: None,
1124 destroy: None,
1125 });
1126 }
1127 if let Some(ret) = ret {
1128 Ok(Function {
1129 name: fn_name.into(),
1130 c_identifier: c_identifier.map(|s| s.into()),
1131 kind,
1132 parameters: params,
1133 ret,
1134 throws,
1135 version,
1136 deprecated_version,
1137 doc,
1138 doc_deprecated,
1139 get_property,
1140 set_property,
1141 finish_func,
1142 async_func,
1143 sync_func,
1144 })
1145 } else {
1146 Err(parser.fail_with_position(
1147 "Missing <return-value> element in <function> element",
1148 elem.position(),
1149 ))
1150 }
1151 }
1152
1153 fn read_function_to_vec(
1154 &mut self,
1155 parser: &mut XmlParser<'_>,
1156 ns_id: u16,
1157 elem: &Element,
1158 fns: &mut Vec<Function>,
1159 ) -> Result<(), String> {
1160 if let Some(f) = self.read_function_if_not_moved(parser, ns_id, elem.name(), elem, false)? {
1161 fns.push(f);
1162 }
1163 Ok(())
1164 }
1165
1166 fn read_function_if_not_moved(
1167 &mut self,
1168 parser: &mut XmlParser<'_>,
1169 ns_id: u16,
1170 kind_str: &str,
1171 elem: &Element,
1172 is_callback: bool,
1173 ) -> Result<Option<Function>, String> {
1174 if elem.attr("moved-to").is_some() {
1175 return parser.ignore_element().map(|_| None);
1176 }
1177 self.read_function(parser, ns_id, kind_str, elem, is_callback)
1178 .and_then(|f| {
1179 if f.c_identifier.is_none() {
1180 return Err(parser.fail_with_position(
1181 &format!(
1182 "Missing c:identifier attribute in <{}> element",
1183 elem.name()
1184 ),
1185 elem.position(),
1186 ));
1187 }
1188 Ok(Some(f))
1189 })
1190 }
1191
1192 fn read_signal(
1193 &mut self,
1194 parser: &mut XmlParser<'_>,
1195 ns_id: u16,
1196 elem: &Element,
1197 ) -> Result<Signal, String> {
1198 let signal_name = elem.attr_required("name")?;
1199 let is_action = elem.attr_bool("action", false);
1200 let is_detailed = elem.attr_bool("detailed", false);
1201 let version = self.read_version(parser, ns_id, elem)?;
1202 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
1203
1204 let mut params = Vec::new();
1205 let mut ret = None;
1206 let mut doc = None;
1207 let mut doc_deprecated = None;
1208
1209 parser.elements(|parser, elem| match elem.name() {
1210 "parameters" => self
1211 .read_parameters(parser, ns_id, true, false)
1212 .map(|mut ps| params.append(&mut ps)),
1213 "return-value" => {
1214 if ret.is_some() {
1215 return Err(parser.fail_with_position(
1216 "Too many <return-value> elements in <signal> element",
1217 elem.position(),
1218 ));
1219 }
1220 self.read_parameter(parser, ns_id, elem, true, false)
1221 .map(|p| ret = Some(p))
1222 }
1223 "doc" => parser.text().map(|t| doc = Some(t)),
1224 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
1225 "doc-version" => parser.ignore_element(),
1226 "source-position" => parser.ignore_element(),
1227 "attribute" => parser.ignore_element(),
1228 _ => Err(parser.unexpected_element(elem)),
1229 })?;
1230 if let Some(ret) = ret {
1231 Ok(Signal {
1232 name: signal_name.into(),
1233 parameters: params,
1234 ret,
1235 is_action,
1236 is_detailed,
1237 version,
1238 deprecated_version,
1239 doc,
1240 doc_deprecated,
1241 })
1242 } else {
1243 Err(parser.fail_with_position(
1244 "Missing <return-value> element in <signal> element",
1245 elem.position(),
1246 ))
1247 }
1248 }
1249
1250 fn read_parameters(
1251 &mut self,
1252 parser: &mut XmlParser<'_>,
1253 ns_id: u16,
1254 allow_no_ctype: bool,
1255 for_method: bool,
1256 ) -> Result<Vec<Parameter>, String> {
1257 parser.elements(|parser, elem| match elem.name() {
1258 "parameter" | "instance-parameter" => {
1259 self.read_parameter(parser, ns_id, elem, allow_no_ctype, for_method)
1260 }
1261 _ => Err(parser.unexpected_element(elem)),
1262 })
1263 }
1264
1265 fn read_parameter(
1266 &mut self,
1267 parser: &mut XmlParser<'_>,
1268 ns_id: u16,
1269 elem: &Element,
1270 allow_no_ctype: bool,
1271 for_method: bool,
1272 ) -> Result<Parameter, String> {
1273 let param_name = elem.attr("name").unwrap_or("");
1274 let instance_parameter = elem.name() == "instance-parameter";
1275 let transfer = elem
1276 .attr_from_str("transfer-ownership")?
1277 .unwrap_or(Transfer::None);
1278 let nullable = elem.attr_bool("nullable", false);
1279 let scope = elem.attr_from_str("scope")?.unwrap_or(ParameterScope::None);
1280 let closure = elem.attr_from_str("closure")?;
1281 let destroy = elem.attr_from_str("destroy")?;
1282 let caller_allocates = elem.attr_bool("caller-allocates", false);
1283 let direction = if elem.name() == "return-value" {
1284 Ok(ParameterDirection::Return)
1285 } else {
1286 ParameterDirection::from_str(elem.attr("direction").unwrap_or("in"))
1287 .map_err(|why| parser.fail_with_position(&why, elem.position()))
1288 }?;
1289
1290 let mut typ = None;
1291 let mut varargs = false;
1292 let mut doc = None;
1293
1294 parser.elements(|parser, elem| match elem.name() {
1295 "type" | "array" => {
1296 if typ.is_some() {
1297 return Err(parser.fail_with_position(
1298 &format!("Too many <type> elements in <{}> element", elem.name()),
1299 elem.position(),
1300 ));
1301 }
1302 typ = Some(self.read_type(parser, ns_id, elem)?);
1303 if let Some((tid, None, _)) = typ {
1304 if allow_no_ctype {
1305 typ = Some((tid, Some(EMPTY_CTYPE.to_owned()), None));
1306 } else {
1307 return Err(parser.fail_with_position(
1308 &format!("Missing c:type attribute in <{}> element", elem.name()),
1309 elem.position(),
1310 ));
1311 }
1312 }
1313 Ok(())
1314 }
1315 "varargs" => {
1316 varargs = true;
1317 parser.ignore_element()
1318 }
1319 "doc" => parser.text().map(|t| doc = Some(t)),
1320 "attribute" => parser.ignore_element(),
1321 _ => Err(parser.unexpected_element(elem)),
1322 })?;
1323
1324 if let Some((tid, c_type, mut array_length)) = typ {
1325 if for_method {
1326 array_length = array_length.map(|l| l + 1);
1327 }
1328 Ok(Parameter {
1329 name: param_name.into(),
1330 typ: tid,
1331 c_type: c_type.unwrap(),
1332 instance_parameter,
1333 direction,
1334 transfer,
1335 caller_allocates,
1336 nullable: Nullable(nullable),
1337 array_length,
1338 is_error: false,
1339 doc,
1340 scope,
1341 closure,
1342 destroy,
1343 })
1344 } else if varargs {
1345 Ok(Parameter {
1346 name: String::new(),
1347 typ: self.find_type(INTERNAL_NAMESPACE, "varargs").unwrap(),
1348 c_type: String::new(),
1349 instance_parameter,
1350 direction: Default::default(),
1351 transfer: Transfer::None,
1352 caller_allocates: false,
1353 nullable: Nullable(false),
1354 array_length: None,
1355 is_error: false,
1356 doc,
1357 scope,
1358 closure,
1359 destroy,
1360 })
1361 } else {
1362 Err(parser.fail_with_position(
1363 &format!("Missing <type> element in <{}> element", elem.name()),
1364 elem.position(),
1365 ))
1366 }
1367 }
1368
1369 fn read_property(
1370 &mut self,
1371 parser: &mut XmlParser<'_>,
1372 ns_id: u16,
1373 elem: &Element,
1374 symbol_prefix: &str,
1375 ) -> Result<Option<Property>, String> {
1376 let prop_name = elem.attr_required("name")?;
1377 let readable = elem.attr_bool("readable", true);
1378 let writable = elem.attr_bool("writable", false);
1379 let construct = elem.attr_bool("construct", false);
1380 let construct_only = elem.attr_bool("construct-only", false);
1381 let transfer = Transfer::from_str(elem.attr("transfer-ownership").unwrap_or("none"))
1382 .map_err(|why| parser.fail_with_position(&why, elem.position()))?;
1383
1384 let version = self.read_version(parser, ns_id, elem)?;
1385 let deprecated_version = self.read_deprecated_version(parser, ns_id, elem)?;
1386 let mut has_empty_type_tag = false;
1387 let mut typ = None;
1388 let mut doc = None;
1389 let mut doc_deprecated = None;
1390 let mut gtk_getter = None;
1391 let mut gtk_setter = None;
1392
1393 parser.elements(|parser, elem| match elem.name() {
1394 "type" | "array" => {
1395 if typ.is_some() {
1396 return Err(parser.fail_with_position(
1397 "Too many <type> elements in <property> element",
1398 elem.position(),
1399 ));
1400 }
1401 if !elem.has_attrs() && elem.name() == "type" {
1402 has_empty_type_tag = true;
1404 return parser.ignore_element();
1405 }
1406 typ = Some(self.read_type(parser, ns_id, elem)?);
1407 if let Some((tid, None, _)) = typ {
1408 typ = Some((tid, Some(EMPTY_CTYPE.to_owned()), None));
1409 }
1410 Ok(())
1411 }
1412 "doc" => parser.text().map(|t| doc = Some(t)),
1413 "doc-deprecated" => parser.text().map(|t| doc_deprecated = Some(t)),
1414 "doc-version" => parser.ignore_element(),
1415 "source-position" => parser.ignore_element(),
1416 "attribute" => {
1417 if let (Some(name), Some(value)) = (elem.attr("name"), elem.attr("value")) {
1418 match name {
1419 "org.gtk.Property.get" => {
1420 gtk_getter = value
1421 .split(symbol_prefix)
1422 .last()
1423 .and_then(|p| p.strip_prefix('_'))
1424 .map(|p| p.to_string());
1425 Ok(())
1426 }
1427 "org.gtk.Property.set" => {
1428 gtk_setter = value
1429 .split(symbol_prefix)
1430 .last()
1431 .and_then(|p| p.strip_prefix('_'))
1432 .map(|p| p.to_string());
1433 Ok(())
1434 }
1435 _ => parser.ignore_element(),
1436 }
1437 } else {
1438 parser.ignore_element()
1439 }
1440 }
1441 _ => Err(parser.unexpected_element(elem)),
1442 })?;
1443
1444 let getter = gtk_getter.or(elem.attr("getter").map(ToString::to_string));
1445 let setter = gtk_setter.or(elem.attr("setter").map(ToString::to_string));
1446 if has_empty_type_tag {
1447 return Ok(None);
1448 }
1449
1450 if let Some((tid, c_type, _array_length)) = typ {
1451 Ok(Some(Property {
1452 name: prop_name.into(),
1453 readable,
1454 writable,
1455 construct,
1456 construct_only,
1457 transfer,
1458 typ: tid,
1459 c_type,
1460 version,
1461 deprecated_version,
1462 doc,
1463 doc_deprecated,
1464 getter,
1465 setter,
1466 }))
1467 } else {
1468 Err(parser.fail_with_position(
1469 "Missing <type> element in <property> element",
1470 elem.position(),
1471 ))
1472 }
1473 }
1474
1475 fn read_type(
1476 &mut self,
1477 parser: &mut XmlParser<'_>,
1478 ns_id: u16,
1479 elem: &Element,
1480 ) -> Result<(TypeId, Option<String>, Option<u32>), String> {
1481 let type_name = elem
1482 .attr("name")
1483 .or_else(|| {
1484 if elem.name() == "array" {
1485 Some("array")
1486 } else {
1487 None
1488 }
1489 })
1490 .ok_or_else(|| {
1491 parser.fail_with_position(
1492 "<type> element is missing a name attribute",
1493 elem.position(),
1494 )
1495 })?;
1496 let c_type = elem.attr("type").map(|s| s.into());
1497 let array_length = elem.attr("length").and_then(|s| s.parse().ok());
1498
1499 let inner = parser.elements(|parser, elem| match elem.name() {
1500 "type" | "array" => self.read_type(parser, ns_id, elem),
1501 _ => Err(parser.unexpected_element(elem)),
1502 })?;
1503
1504 if inner.is_empty() || type_name == "GLib.ByteArray" {
1505 if type_name == "array" {
1506 Err(parser.fail_with_position(
1507 "<type> element is missing an inner element type",
1508 elem.position(),
1509 ))
1510 } else if type_name == "gboolean"
1511 && c_type
1512 .as_ref()
1513 .is_some_and(|c_type| c_type == "_Bool" || c_type == "bool")
1514 {
1515 Ok((self.find_or_stub_type(ns_id, "bool"), c_type, array_length))
1516 } else {
1517 Ok((
1518 self.find_or_stub_type(ns_id, type_name),
1519 c_type,
1520 array_length,
1521 ))
1522 }
1523 } else {
1524 let tid = if type_name == "array" {
1525 let inner_type = &inner[0];
1526 Type::c_array(
1527 self,
1528 inner_type.0,
1529 elem.attr("fixed-size").and_then(|n| n.parse().ok()),
1530 inner_type.1.clone(),
1531 )
1532 } else {
1533 let inner = inner.iter().map(|r| r.0).collect();
1534 Type::container(self, type_name, inner).ok_or_else(|| {
1535 parser.fail_with_position("Unknown container type", elem.position())
1536 })?
1537 };
1538 Ok((tid, c_type, array_length))
1539 }
1540 }
1541
1542 fn read_version(
1543 &mut self,
1544 parser: &XmlParser<'_>,
1545 ns_id: u16,
1546 elem: &Element,
1547 ) -> Result<Option<Version>, String> {
1548 self.read_version_attribute(parser, ns_id, elem, "version")
1549 }
1550
1551 fn read_deprecated_version(
1552 &mut self,
1553 parser: &XmlParser<'_>,
1554 ns_id: u16,
1555 elem: &Element,
1556 ) -> Result<Option<Version>, String> {
1557 self.read_version_attribute(parser, ns_id, elem, "deprecated-version")
1558 }
1559
1560 fn read_version_attribute(
1561 &mut self,
1562 parser: &XmlParser<'_>,
1563 ns_id: u16,
1564 elem: &Element,
1565 attr: &str,
1566 ) -> Result<Option<Version>, String> {
1567 if let Some(v) = elem.attr(attr) {
1568 match v.parse() {
1569 Ok(v) => {
1570 self.register_version(ns_id, v);
1571 Ok(Some(v))
1572 }
1573 Err(e) => Err(parser.fail(&format!("Invalid `{attr}` attribute: {e}"))),
1574 }
1575 } else {
1576 Ok(None)
1577 }
1578 }
1579
1580 fn read_object_c_type<'a>(
1581 &mut self,
1582 parser: &XmlParser<'_>,
1583 elem: &'a Element,
1584 ) -> Result<&'a str, String> {
1585 elem.attr("type")
1586 .or_else(|| elem.attr("type-name"))
1587 .ok_or_else(|| {
1588 parser.fail(&format!(
1589 "Missing `c:type`/`glib:type-name` attributes on element <{}>",
1590 elem.name()
1591 ))
1592 })
1593 }
1594}
1595
1596fn make_file_name(dir: &Path, name: &str) -> PathBuf {
1597 let mut path = dir.to_path_buf();
1598 let name = format!("{name}.gir");
1599 path.push(name);
1600 path
1601}