Skip to main content

libgir/
parser.rs

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