libgir/
parser.rs

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, // this will be resolved during postprocessing
257            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        // Records starting with `_` are intended to be private and should not be bound
303        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                    // Workaround for bitfields
368                    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                            // Skip
379                        }
380                        return;
381                    }
382                    // Workaround for wrong GValue c:type
383                    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        // Require a name here
433        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                // Workaround for missing c:type
439                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, // this will be resolved during postprocessing
740            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        // The last argument of a callback is ALWAYS user data, so it has to be marked as such
1103        // in case it's missing.
1104        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                    // defend from <type/>
1403                    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}