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