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