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_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, 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 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 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 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 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 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, 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(""), None,
1082 None,
1083 None,
1084 None,
1085 None,
1086 )?;
1087 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 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}