1use gir_parser::{DocFormat, TransferOwnership, prelude::*};
2use std::{
3 cmp::{Ord, Ordering, PartialOrd},
4 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
5 fmt,
6 iter::Iterator,
7 str::FromStr,
8};
9
10use crate::{
11 analysis::conversion_type::ConversionType, config::gobjects::GStatus, env::Env,
12 nameutil::split_namespace_name, traits::*, version::Version,
13};
14
15#[derive(Default, Clone, Copy, Debug, Eq, PartialEq)]
16pub enum ParameterDirection {
17 None,
18 #[default]
19 In,
20 Out,
21 InOut,
22 Return,
23}
24
25impl From<gir_parser::Direction> for ParameterDirection {
26 fn from(value: gir_parser::Direction) -> Self {
27 match value {
28 gir_parser::Direction::In => Self::In,
29 gir_parser::Direction::Out => Self::Out,
30 gir_parser::Direction::InOut => Self::InOut,
31 }
32 }
33}
34
35impl ParameterDirection {
36 pub fn is_in(self) -> bool {
37 matches!(self, Self::In | Self::InOut)
38 }
39
40 pub fn is_out(self) -> bool {
41 matches!(self, Self::Out | Self::InOut)
42 }
43}
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub enum FunctionKind {
47 Constructor,
48 Function,
49 Method,
50 Global,
51 ClassMethod,
52 VirtualMethod,
53}
54
55#[derive(Default, Clone, Copy, Debug, Eq, PartialEq)]
56pub enum Concurrency {
57 #[default]
58 None,
59 Send,
60 SendSync,
61}
62
63impl FromStr for Concurrency {
64 type Err = String;
65 fn from_str(name: &str) -> Result<Self, String> {
66 match name {
67 "none" => Ok(Self::None),
68 "send" => Ok(Self::Send),
69 "send+sync" => Ok(Self::SendSync),
70 _ => Err(format!("Unknown concurrency kind '{name}'")),
71 }
72 }
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub enum Basic {
77 None,
78 Boolean,
79 Int8,
80 UInt8,
81 Int16,
82 UInt16,
83 Int32,
84 UInt32,
85 Int64,
86 UInt64,
87 Char,
88 UChar,
89 Short,
90 UShort,
91 Int,
92 UInt,
93 Long,
94 ULong,
95 Size,
96 SSize,
97 Float,
98 Double,
99 Pointer,
100 VarArgs,
101 UniChar,
102 Utf8,
103 Filename,
104 Type,
105 IntPtr,
106 UIntPtr,
107 TimeT,
108 OffT,
109 DevT,
110 GidT,
111 PidT,
112 SockLenT,
113 UidT,
114 OsString,
117 Bool,
118 Unsupported,
119}
120
121impl Basic {
122 pub fn requires_conversion(&self) -> bool {
123 !matches!(
124 self,
125 Self::Int8
126 | Self::UInt8
127 | Self::Int16
128 | Self::UInt16
129 | Self::Int32
130 | Self::UInt32
131 | Self::Int64
132 | Self::UInt64
133 | Self::Char
134 | Self::UChar
135 | Self::Short
136 | Self::UShort
137 | Self::Int
138 | Self::UInt
139 | Self::Long
140 | Self::ULong
141 | Self::Size
142 | Self::SSize
143 | Self::Float
144 | Self::Double
145 | Self::Bool
146 )
147 }
148}
149
150const BASIC: &[(&str, Basic)] = &[
151 ("none", Basic::None),
152 ("gboolean", Basic::Boolean),
153 ("gint8", Basic::Int8),
154 ("guint8", Basic::UInt8),
155 ("gint16", Basic::Int16),
156 ("guint16", Basic::UInt16),
157 ("gint32", Basic::Int32),
158 ("guint32", Basic::UInt32),
159 ("gint64", Basic::Int64),
160 ("guint64", Basic::UInt64),
161 ("gchar", Basic::Char),
162 ("guchar", Basic::UChar),
163 ("gshort", Basic::Short),
164 ("gushort", Basic::UShort),
165 ("gint", Basic::Int),
166 ("guint", Basic::UInt),
167 ("glong", Basic::Long),
168 ("gulong", Basic::ULong),
169 ("gsize", Basic::Size),
170 ("gssize", Basic::SSize),
171 ("gfloat", Basic::Float),
172 ("gdouble", Basic::Double),
173 ("long double", Basic::Unsupported),
174 ("gunichar", Basic::UniChar),
175 ("gconstpointer", Basic::Pointer),
176 ("gpointer", Basic::Pointer),
177 ("va_list", Basic::Unsupported),
178 ("varargs", Basic::VarArgs),
179 ("utf8", Basic::Utf8),
180 ("filename", Basic::Filename),
181 ("GType", Basic::Type),
182 ("gintptr", Basic::IntPtr),
183 ("guintptr", Basic::UIntPtr),
184 ("os_string", Basic::OsString),
186 ("bool", Basic::Bool),
187 ("time_t", Basic::TimeT),
188 ("off_t", Basic::OffT),
189 ("dev_t", Basic::DevT),
190 ("gid_t", Basic::GidT),
191 ("pid_t", Basic::PidT),
192 ("socklen_t", Basic::SockLenT),
193 ("uid_t", Basic::UidT),
194];
195
196#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
197pub struct TypeId {
198 pub ns_id: u16,
199 pub id: u32,
200}
201
202impl TypeId {
203 pub fn full_name(self, library: &Library) -> String {
204 let ns_name = &library.namespace(self.ns_id).name;
205 let type_ = &library.type_(self);
206 format!("{}.{}", ns_name, &type_.get_name())
207 }
208
209 pub fn tid_none() -> TypeId {
210 Default::default()
211 }
212
213 pub fn tid_bool() -> TypeId {
214 TypeId { ns_id: 0, id: 1 }
215 }
216
217 pub fn tid_uint32() -> TypeId {
218 TypeId { ns_id: 0, id: 7 }
219 }
220
221 pub fn tid_utf8() -> TypeId {
222 TypeId { ns_id: 0, id: 28 }
223 }
224
225 pub fn tid_filename() -> TypeId {
226 TypeId { ns_id: 0, id: 29 }
227 }
228
229 pub fn tid_os_string() -> TypeId {
230 TypeId { ns_id: 0, id: 33 }
231 }
232
233 pub fn tid_c_bool() -> TypeId {
234 TypeId { ns_id: 0, id: 34 }
235 }
236
237 pub fn is_basic_type(self, env: &Env) -> bool {
238 env.library.type_(self).is_basic_type(env)
239 }
240}
241
242#[derive(Debug)]
243pub struct Alias {
244 pub name: String,
245 pub c_identifier: String,
246 pub typ: TypeId,
247 pub target_c_type: String,
248 pub doc: Option<String>,
249 pub doc_deprecated: Option<String>,
250}
251
252#[derive(Debug)]
253pub struct Constant {
254 pub name: String,
255 pub c_identifier: String,
256 pub typ: TypeId,
257 pub c_type: String,
258 pub value: String,
259 pub version: Option<Version>,
260 pub deprecated_version: Option<Version>,
261 pub doc: Option<String>,
262 pub doc_deprecated: Option<String>,
263}
264
265#[derive(Debug)]
266pub struct Member {
267 pub name: String,
268 pub c_identifier: String,
269 pub value: String,
270 pub doc: Option<String>,
271 pub doc_deprecated: Option<String>,
272 pub status: GStatus,
273 pub version: Option<Version>,
274 pub deprecated_version: Option<Version>,
275}
276
277#[derive(Debug)]
278pub enum ErrorDomain {
279 Quark(String),
280 Function(String),
281}
282
283#[derive(Debug)]
284pub struct Enumeration {
285 pub name: String,
286 pub c_type: String,
287 pub members: Vec<Member>,
288 pub functions: Vec<Function>,
289 pub version: Option<Version>,
290 pub deprecated_version: Option<Version>,
291 pub doc: Option<String>,
292 pub doc_deprecated: Option<String>,
293 pub error_domain: Option<ErrorDomain>,
294 pub glib_get_type: Option<String>,
295}
296
297#[derive(Debug)]
298pub struct Bitfield {
299 pub name: String,
300 pub c_type: String,
301 pub members: Vec<Member>,
302 pub functions: Vec<Function>,
303 pub version: Option<Version>,
304 pub deprecated_version: Option<Version>,
305 pub doc: Option<String>,
306 pub doc_deprecated: Option<String>,
307 pub glib_get_type: Option<String>,
308}
309
310#[derive(Default, Debug)]
311pub struct Record {
312 pub name: String,
313 pub c_type: String,
314 pub symbol_prefix: Option<String>,
315 pub glib_get_type: Option<String>,
316 pub gtype_struct_for: Option<String>,
317 pub fields: Vec<Field>,
318 pub functions: Vec<Function>,
319 pub version: Option<Version>,
320 pub deprecated_version: Option<Version>,
321 pub doc: Option<String>,
322 pub doc_deprecated: Option<String>,
323 pub pointer: bool,
326 pub disguised: bool,
329}
330
331impl Record {
332 pub fn has_free(&self) -> bool {
333 self.functions.iter().any(|f| f.name == "free") || (self.has_copy() && self.has_destroy())
334 }
335
336 pub fn has_copy(&self) -> bool {
337 self.functions
338 .iter()
339 .any(|f| f.name == "copy" || f.name == "copy_into")
340 }
341
342 pub fn has_destroy(&self) -> bool {
343 self.functions.iter().any(|f| f.name == "destroy")
344 }
345
346 pub fn has_unref(&self) -> bool {
347 self.functions.iter().any(|f| f.name == "unref")
348 }
349
350 pub fn has_ref(&self) -> bool {
351 self.functions.iter().any(|f| f.name == "ref")
352 }
353}
354
355#[derive(Default, Debug)]
356pub struct Field {
357 pub name: String,
358 pub typ: TypeId,
359 pub c_type: Option<String>,
360 pub private: bool,
361 pub bits: Option<u8>,
362 pub array_length: Option<u32>,
363 pub doc: Option<String>,
364}
365
366#[derive(Default, Debug)]
367pub struct Union {
368 pub name: String,
369 pub c_type: Option<String>,
370 pub symbol_prefix: Option<String>,
371 pub glib_get_type: Option<String>,
372 pub fields: Vec<Field>,
373 pub functions: Vec<Function>,
374 pub doc: Option<String>,
375}
376
377#[derive(Debug)]
378pub struct Property {
379 pub name: String,
380 pub readable: bool,
381 pub writable: bool,
382 pub construct: bool,
383 pub construct_only: bool,
384 pub typ: TypeId,
385 pub c_type: Option<String>,
386 pub transfer: TransferOwnership,
387 pub version: Option<Version>,
388 pub deprecated_version: Option<Version>,
389 pub doc: Option<String>,
390 pub doc_deprecated: Option<String>,
391 pub getter: Option<String>,
392 pub setter: Option<String>,
393}
394
395#[derive(Clone, Debug)]
396pub enum Parameter {
397 Instance {
398 param: gir_parser::InstanceParameter,
399 tid: TypeId,
400 nullable_override: Option<bool>,
401 name_override: Option<String>,
402 c_type_override: Option<String>,
403 },
404 Return {
405 param: gir_parser::ReturnValue,
406 tid: TypeId,
407 nullable_override: Option<bool>,
408 name_override: Option<String>,
409 c_type_override: Option<String>,
410 array_length_offset: u32,
411 },
412 Default {
413 param: gir_parser::Parameter,
414 tid: TypeId,
415 nullable_override: Option<bool>,
416 name_override: Option<String>,
417 c_type_override: Option<String>,
418 array_length_offset: u32,
419 closure_override: Option<usize>,
420 },
421 Error(TypeId),
422 VarArgs(TypeId),
423 None(TypeId),
424}
425
426impl Parameter {
427 pub fn set_nullable(&mut self, is_nullable: bool) {
428 match self {
429 Self::Default {
430 nullable_override, ..
431 } => {
432 nullable_override.replace(is_nullable);
433 }
434 Parameter::Instance {
435 nullable_override, ..
436 } => {
437 nullable_override.replace(is_nullable);
438 }
439 Parameter::Return {
440 nullable_override, ..
441 } => {
442 nullable_override.replace(is_nullable);
443 }
444 _ => (),
445 }
446 }
447 pub fn set_c_type(&mut self, c_type: &str) {
448 match self {
449 Self::Default {
450 c_type_override, ..
451 } => {
452 c_type_override.replace(c_type.to_owned());
453 }
454 Parameter::Instance {
455 c_type_override, ..
456 } => {
457 c_type_override.replace(c_type.to_owned());
458 }
459 Parameter::Return {
460 c_type_override, ..
461 } => {
462 c_type_override.replace(c_type.to_owned());
463 }
464 _ => (),
465 }
466 }
467
468 pub fn set_name(&mut self, name: &str) {
469 match self {
470 Self::Default { name_override, .. } => {
471 name_override.replace(name.to_owned());
472 }
473 Parameter::Instance { name_override, .. } => {
474 name_override.replace(name.to_owned());
475 }
476 Parameter::Return { name_override, .. } => {
477 name_override.replace(name.to_owned());
478 }
479 _ => (),
480 }
481 }
482
483 pub fn destroy(&self) -> Option<usize> {
484 match self {
485 Parameter::Return { param, .. } => param.destroy(),
486 Parameter::Default { param, .. } => param.destroy(),
487 _ => None,
488 }
489 }
490
491 pub fn closure(&self) -> Option<usize> {
492 match self {
493 Parameter::Return { param, .. } => param.closure(),
494 Parameter::Default {
495 param,
496 closure_override,
497 ..
498 } => closure_override.or_else(|| param.closure()),
499 _ => None,
500 }
501 }
502
503 pub fn c_type(&self) -> &str {
504 match self {
505 Parameter::Instance {
506 param,
507 c_type_override,
508 ..
509 } => c_type_override
510 .as_deref()
511 .or(param.ty().and_then(|t| t.c_type())),
512 Parameter::Return {
513 param,
514 c_type_override,
515 ..
516 } => c_type_override.as_deref().or_else(|| match param.ty() {
517 gir_parser::AnyType::Array(a) => a.c_type(),
518 gir_parser::AnyType::Type(t) => t.c_type(),
519 }),
520 Parameter::Default {
521 param,
522 c_type_override,
523 ..
524 } => c_type_override.as_deref().or_else(|| {
525 param.ty().and_then(|t| match t {
526 gir_parser::ParameterType::VarArgs => None,
527 gir_parser::ParameterType::Array(a) => a.c_type(),
528 gir_parser::ParameterType::Type(t) => t.c_type(),
529 })
530 }),
531 Parameter::Error(_) => Some("GError**"),
532 Parameter::VarArgs(_) => None,
533 Parameter::None(_) => Some("none"),
534 }
535 .unwrap_or("")
536 }
537
538 pub fn scope(&self) -> Option<gir_parser::FunctionScope> {
539 match self {
540 Self::Instance { .. } => None,
541 Self::Return { param, .. } => param.scope(),
542 Self::Default { param, .. } => param.scope(),
543 Self::Error(_) => None,
544 Self::VarArgs(_) => None,
545 Self::None(_) => None,
546 }
547 }
548
549 pub fn array_length(&self) -> Option<u32> {
550 match self {
551 Self::Return {
552 param,
553 array_length_offset,
554 ..
555 } => match param.ty() {
556 gir_parser::AnyType::Array(array) => {
557 array.length().map(|l| l + array_length_offset)
558 }
559 _ => None,
560 },
561 Self::Default {
562 param,
563 array_length_offset,
564 ..
565 } => {
566 if let Some(ty) = param.ty() {
567 match ty {
568 gir_parser::ParameterType::Array(array) => {
569 array.length().map(|l| l + array_length_offset)
570 }
571 _ => None,
572 }
573 } else {
574 None
575 }
576 }
577 _ => None,
578 }
579 }
580
581 pub fn doc(&self) -> Option<&str> {
582 match self {
583 Self::Instance { param, .. } => param.doc().map(|d| d.text()),
584 Self::Return { param, .. } => param.doc().map(|d| d.text()),
585 Self::Default { param, .. } => param.doc().map(|d| d.text()),
586 _ => None,
587 }
588 }
589
590 pub fn none(tid: TypeId) -> Self {
591 Self::None(tid)
592 }
593
594 pub fn error(tid: TypeId) -> Self {
595 Self::Error(tid)
596 }
597
598 pub fn is_instance(&self) -> bool {
599 matches!(self, Self::Instance { .. })
600 }
601
602 pub fn is_return(&self) -> bool {
603 matches!(self, Self::Return { .. })
604 }
605
606 pub fn is_error(&self) -> bool {
607 matches!(self, Self::Error(_))
608 }
609
610 pub fn is_varargs(&self) -> bool {
611 matches!(self, Self::VarArgs(_))
612 }
613
614 pub fn name(&self) -> &str {
615 match self {
616 Self::Instance {
617 param,
618 name_override,
619 ..
620 } => name_override.as_deref().or(Some(param.name())),
621 Self::Default {
622 param,
623 name_override,
624 ..
625 } => name_override.as_deref().or(Some(param.name())),
626 Self::Return { name_override, .. } => name_override.as_deref(),
627 Self::Error(_) => Some("error"),
628 _ => None,
629 }
630 .unwrap_or("")
631 }
632
633 pub fn is_caller_allocates(&self) -> bool {
634 match self {
635 Self::Instance { param, .. } => param.is_caller_allocates(),
636 Self::Default { param, .. } => param.is_caller_allocates(),
637 _ => None,
638 }
639 .unwrap_or(false)
640 }
641
642 pub fn typ(&self) -> TypeId {
643 match self {
644 Self::Instance { tid, .. } => *tid,
645 Self::Return { tid, .. } => *tid,
646 Self::Default { tid, .. } => *tid,
647 Self::Error(tid) => *tid,
648 Self::VarArgs(tid) => *tid,
649 Self::None(tid) => *tid,
650 }
651 }
652
653 pub fn set_tid(&mut self, new_tid: TypeId) {
654 match self {
655 Self::Instance { tid, .. } | Self::Return { tid, .. } | Self::Default { tid, .. } => {
656 *tid = new_tid;
657 }
658 Self::Error(tid) | Self::VarArgs(tid) | Self::None(tid) => {
659 *tid = new_tid;
660 }
661 }
662 }
663
664 pub fn is_nullable(&self) -> bool {
665 match self {
666 Self::Instance {
667 nullable_override, ..
668 } => nullable_override.unwrap_or(false),
669 Self::Default {
670 param,
671 nullable_override,
672 ..
673 } => nullable_override.or(param.is_nullable()).unwrap_or(false),
674 Self::Return {
675 param,
676 nullable_override,
677 ..
678 } => nullable_override.or(param.is_nullable()).unwrap_or(false),
679 Self::Error(_) => true,
680 Self::VarArgs(_) => false,
681 Self::None(_) => false,
682 }
683 }
684
685 pub fn direction(&self) -> ParameterDirection {
686 match self {
687 Self::Instance { param, .. } => param
688 .direction()
689 .map(ParameterDirection::from)
690 .unwrap_or_default(),
691 Self::Default { param, .. } => param
692 .direction()
693 .map(ParameterDirection::from)
694 .unwrap_or_default(),
695 Self::Return { .. } => ParameterDirection::Return,
696 Self::Error(_) => ParameterDirection::Out,
697 Self::VarArgs(_) => ParameterDirection::default(),
698 Self::None(_) => ParameterDirection::default(),
699 }
700 }
701
702 pub fn transfer_ownership(&self) -> TransferOwnership {
703 match self {
704 Self::Instance { param, .. } => param.transfer_ownership(),
705 Self::Return { param, .. } => param.transfer_ownership(),
706 Self::Default { param, .. } => param.transfer_ownership(),
707 Self::Error(_) => Some(TransferOwnership::Full),
708 Self::VarArgs(_) | Self::None(_) => None,
709 }
710 .unwrap_or(TransferOwnership::None)
711 }
712}
713
714#[derive(Debug)]
715pub struct Function {
716 pub name: String,
717 pub c_identifier: String,
718 pub kind: FunctionKind,
719 pub parameters: Vec<Parameter>,
720 pub ret: Parameter,
721 pub throws: bool,
722 pub version: Option<Version>,
723 pub deprecated_version: Option<Version>,
724 pub doc: Option<String>,
725 pub doc_deprecated: Option<String>,
726 pub get_property: Option<String>,
727 pub set_property: Option<String>,
728 pub finish_func: Option<String>,
729 pub async_func: Option<String>,
730 pub sync_func: Option<String>,
731}
732
733#[derive(Debug)]
734pub struct Signal {
735 pub name: String,
736 pub parameters: Vec<Parameter>,
737 pub ret: Parameter,
738 pub is_action: bool,
739 pub is_detailed: bool,
740 pub version: Option<Version>,
741 pub deprecated_version: Option<Version>,
742 pub doc: Option<String>,
743 pub doc_deprecated: Option<String>,
744}
745
746#[derive(Default, Debug)]
747pub struct Interface {
748 pub name: String,
749 pub c_type: String,
750 pub symbol_prefix: String,
751 pub type_struct: Option<String>,
752 pub c_class_type: Option<String>,
753 pub glib_get_type: String,
754 pub functions: Vec<Function>,
755 pub virtual_methods: Vec<Function>,
756 pub signals: Vec<Signal>,
757 pub properties: Vec<Property>,
758 pub prerequisites: Vec<TypeId>,
759 pub version: Option<Version>,
760 pub deprecated_version: Option<Version>,
761 pub doc: Option<String>,
762 pub doc_deprecated: Option<String>,
763}
764
765#[derive(Default, Debug)]
766pub struct Class {
767 pub name: String,
768 pub c_type: String,
769 pub symbol_prefix: String,
770 pub type_struct: Option<String>,
771 pub c_class_type: Option<String>,
772 pub glib_get_type: String,
773 pub fields: Vec<Field>,
774 pub functions: Vec<Function>,
775 pub virtual_methods: Vec<Function>,
776 pub signals: Vec<Signal>,
777 pub properties: Vec<Property>,
778 pub parent: Option<TypeId>,
779 pub implements: Vec<TypeId>,
780 pub final_type: bool,
781 pub version: Option<Version>,
782 pub deprecated_version: Option<Version>,
783 pub doc: Option<String>,
784 pub doc_deprecated: Option<String>,
785 pub is_abstract: bool,
786 pub is_fundamental: bool,
787 pub ref_fn: Option<String>,
789 pub unref_fn: Option<String>,
790}
791
792#[derive(Debug)]
793pub struct Custom {
794 pub name: String,
795 pub conversion_type: ConversionType,
796}
797
798macro_rules! impl_lexical_ord {
799 () => ();
800 ($name:ident => $field:ident, $($more_name:ident => $more_field:ident,)*) => (
801 impl_lexical_ord!($($more_name => $more_field,)*);
802
803 impl PartialEq for $name {
804 fn eq(&self, other: &$name) -> bool {
805 self.$field.eq(&other.$field)
806 }
807 }
808
809 impl Eq for $name { }
810
811 impl PartialOrd for $name {
812 fn partial_cmp(&self, other: &$name) -> Option<Ordering> {
813 Some(self.cmp(other))
814 }
815 }
816
817 impl Ord for $name {
818 fn cmp(&self, other: &$name) -> Ordering {
819 self.$field.cmp(&other.$field)
820 }
821 }
822 );
823}
824
825impl_lexical_ord!(
826 Alias => c_identifier,
827 Bitfield => c_type,
828 Class => c_type,
829 Enumeration => c_type,
830 Function => c_identifier,
831 Interface => c_type,
832 Record => c_type,
833 Union => c_type,
834 Custom => name,
835);
836
837#[derive(Debug, Eq, PartialEq)]
838pub enum Type {
839 Basic(Basic),
840 Alias(Alias),
841 Enumeration(Enumeration),
842 Bitfield(Bitfield),
843 Record(Record),
844 Union(Union),
845 Function(Box<Function>),
846 Interface(Interface),
847 Class(Class),
848 Custom(Custom),
849 Array(TypeId),
850 CArray(TypeId),
851 FixedArray(TypeId, u16, Option<String>),
852 PtrArray(TypeId),
853 HashTable(TypeId, TypeId),
854 List(TypeId),
855 SList(TypeId),
856}
857
858impl fmt::Display for Type {
859 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860 f.write_str(match self {
861 Self::Basic(_) => "Basic",
862 Self::Alias(_) => "Alias",
863 Self::Enumeration(_) => "Enumeration",
864 Self::Bitfield(_) => "Bitfield",
865 Self::Record(_) => "Record",
866 Self::Union(_) => "Union",
867 Self::Function(_) => "Function",
868 Self::Interface(_) => "Interface",
869 Self::Class(_) => "Class",
870 Self::Custom(_) => "Custom",
871 Self::Array(_) => "Array",
872 Self::CArray(_) => "CArray",
873 Self::FixedArray(_, _, _) => "FixedArray",
874 Self::PtrArray(_) => "PtrArray",
875 Self::HashTable(_, _) => "HashTable",
876 Self::List(_) => "List",
877 Self::SList(_) => "SList",
878 })
879 }
880}
881
882impl Type {
883 pub fn get_name(&self) -> String {
884 match self {
885 Self::Basic(basic) => format!("{basic:?}"),
886 Self::Alias(alias) => alias.name.clone(),
887 Self::Enumeration(enum_) => enum_.name.clone(),
888 Self::Bitfield(bit_field) => bit_field.name.clone(),
889 Self::Record(rec) => rec.name.clone(),
890 Self::Union(u) => u.name.clone(),
891 Self::Function(func) => func.name.clone(),
892 Self::Interface(interface) => interface.name.clone(),
893 Self::Array(type_id) => format!("Array {type_id:?}"),
894 Self::Class(class) => class.name.clone(),
895 Self::Custom(custom) => custom.name.clone(),
896 Self::CArray(type_id) => format!("CArray {type_id:?}"),
897 Self::FixedArray(type_id, size, _) => format!("FixedArray {type_id:?}; {size}"),
898 Self::PtrArray(type_id) => format!("PtrArray {type_id:?}"),
899 Self::HashTable(key_type_id, value_type_id) => {
900 format!("HashTable {key_type_id:?}/{value_type_id:?}")
901 }
902 Self::List(type_id) => format!("List {type_id:?}"),
903 Self::SList(type_id) => format!("SList {type_id:?}"),
904 }
905 }
906
907 pub fn get_deprecated_version(&self) -> Option<Version> {
908 match self {
909 Self::Basic(_) => None,
910 Self::Alias(_) => None,
911 Self::Enumeration(enum_) => enum_.deprecated_version,
912 Self::Bitfield(bit_field) => bit_field.deprecated_version,
913 Self::Record(rec) => rec.deprecated_version,
914 Self::Union(_) => None,
915 Self::Function(func) => func.deprecated_version,
916 Self::Interface(interface) => interface.deprecated_version,
917 Self::Array(_) => None,
918 Self::Class(class) => class.deprecated_version,
919 Self::Custom(_) => None,
920 Self::CArray(_) => None,
921 Self::FixedArray(..) => None,
922 Self::PtrArray(_) => None,
923 Self::HashTable(_, _) => None,
924 Self::List(_) => None,
925 Self::SList(_) => None,
926 }
927 }
928
929 pub fn get_glib_name(&self) -> Option<&str> {
930 match self {
931 Self::Alias(alias) => Some(&alias.c_identifier),
932 Self::Enumeration(enum_) => Some(&enum_.c_type),
933 Self::Bitfield(bit_field) => Some(&bit_field.c_type),
934 Self::Record(rec) => Some(&rec.c_type),
935 Self::Union(union) => union.c_type.as_deref(),
936 Self::Function(func) => Some(&func.c_identifier),
937 Self::Interface(interface) => Some(&interface.c_type),
938 Self::Class(class) => Some(&class.c_type),
939 _ => None,
940 }
941 }
942
943 pub fn c_array(
944 library: &mut Library,
945 inner: TypeId,
946 size: Option<u16>,
947 c_type: Option<String>,
948 ) -> TypeId {
949 let name = Self::c_array_internal_name(inner, size, &c_type);
950 if let Some(size) = size {
951 library.add_type(
952 INTERNAL_NAMESPACE,
953 &name,
954 Self::FixedArray(inner, size, c_type),
955 )
956 } else {
957 library.add_type(INTERNAL_NAMESPACE, &name, Self::CArray(inner))
958 }
959 }
960
961 pub fn find_c_array(library: &Library, inner: TypeId, size: Option<u16>) -> TypeId {
962 let name = Self::c_array_internal_name(inner, size, &None);
963 library
964 .find_type(INTERNAL_NAMESPACE, &name)
965 .unwrap_or_else(|| panic!("No type for '*.{name}'"))
966 }
967
968 fn c_array_internal_name(inner: TypeId, size: Option<u16>, c_type: &Option<String>) -> String {
969 if let Some(size) = size {
970 format!("[#{inner:?}; {size};{c_type:?}]")
971 } else {
972 format!("[#{inner:?}]")
973 }
974 }
975
976 pub fn container(library: &mut Library, name: &str, mut inner: Vec<TypeId>) -> Option<TypeId> {
977 match (name, inner.len()) {
978 ("GLib.Array", 1) => {
979 let tid = inner.remove(0);
980 Some((format!("Array(#{tid:?})"), Self::Array(tid)))
981 }
982 ("GLib.PtrArray", 1) => {
983 let tid = inner.remove(0);
984 Some((format!("PtrArray(#{tid:?})"), Self::PtrArray(tid)))
985 }
986 ("GLib.HashTable", 2) => {
987 let k_tid = inner.remove(0);
988 let v_tid = inner.remove(0);
989 Some((
990 format!("HashTable(#{k_tid:?}, #{v_tid:?})"),
991 Self::HashTable(k_tid, v_tid),
992 ))
993 }
994 ("GLib.List", 1) => {
995 let tid = inner.remove(0);
996 Some((format!("List(#{tid:?})"), Self::List(tid)))
997 }
998 ("GLib.SList", 1) => {
999 let tid = inner.remove(0);
1000 Some((format!("SList(#{tid:?})"), Self::SList(tid)))
1001 }
1002 _ => None,
1003 }
1004 .map(|(name, typ)| library.add_type(INTERNAL_NAMESPACE, &name, typ))
1005 }
1006
1007 pub fn function(library: &mut Library, func: Function) -> TypeId {
1008 let mut param_tids: Vec<TypeId> = func.parameters.iter().map(|p| p.typ()).collect();
1009 param_tids.push(func.ret.typ());
1010 let typ = Self::Function(Box::new(func));
1011 library.add_type(INTERNAL_NAMESPACE, &format!("fn<#{param_tids:?}>"), typ)
1012 }
1013
1014 pub fn union(library: &mut Library, u: Union, ns_id: u16) -> TypeId {
1015 let field_tids: Vec<TypeId> = u.fields.iter().map(|f| f.typ).collect();
1016 let typ = Self::Union(u);
1017 library.add_type(ns_id, &format!("#{field_tids:?}"), typ)
1018 }
1019
1020 pub fn record(library: &mut Library, r: Record, ns_id: u16) -> TypeId {
1021 let field_tids: Vec<TypeId> = r.fields.iter().map(|f| f.typ).collect();
1022 let typ = Self::Record(r);
1023 library.add_type(ns_id, &format!("#{field_tids:?}"), typ)
1024 }
1025
1026 pub fn functions(&self) -> &[Function] {
1027 match self {
1028 Self::Enumeration(e) => &e.functions,
1029 Self::Bitfield(b) => &b.functions,
1030 Self::Record(r) => &r.functions,
1031 Self::Union(u) => &u.functions,
1032 Self::Interface(i) => &i.functions,
1033 Self::Class(c) => &c.functions,
1034 _ => &[],
1035 }
1036 }
1037
1038 pub fn is_basic(&self) -> bool {
1039 matches!(*self, Self::Basic(_))
1040 }
1041
1042 pub fn is_basic_type(&self, env: &Env) -> bool {
1045 match self {
1046 Self::Alias(x) => env.library.type_(x.typ).is_basic_type(env),
1047 x => x.is_basic(),
1048 }
1049 }
1050
1051 pub fn get_inner_type<'a>(&'a self, env: &'a Env) -> Option<(&'a Type, u16)> {
1052 match *self {
1053 Self::Array(t)
1054 | Self::CArray(t)
1055 | Self::FixedArray(t, ..)
1056 | Self::PtrArray(t)
1057 | Self::List(t)
1058 | Self::SList(t) => {
1059 let ty = env.type_(t);
1060 ty.get_inner_type(env).or(Some((ty, t.ns_id)))
1061 }
1062 _ => None,
1063 }
1064 }
1065
1066 pub fn is_function(&self) -> bool {
1067 matches!(*self, Self::Function(_))
1068 }
1069
1070 pub fn is_class(&self) -> bool {
1071 matches!(*self, Self::Class(_))
1072 }
1073
1074 pub fn is_interface(&self) -> bool {
1075 matches!(*self, Self::Interface(_))
1076 }
1077
1078 pub fn is_final_type(&self) -> bool {
1079 match *self {
1080 Self::Class(Class { final_type, .. }) => final_type,
1081 Self::Interface(..) => false,
1082 _ => true,
1083 }
1084 }
1085
1086 pub fn is_fundamental(&self) -> bool {
1087 match *self {
1088 Self::Class(Class { is_fundamental, .. }) => is_fundamental,
1089 _ => false,
1090 }
1091 }
1092
1093 pub fn is_abstract(&self) -> bool {
1094 match *self {
1095 Self::Class(Class { is_abstract, .. }) => is_abstract,
1096 _ => false,
1097 }
1098 }
1099
1100 pub fn is_enumeration(&self) -> bool {
1101 matches!(*self, Self::Enumeration(_))
1102 }
1103
1104 pub fn is_bitfield(&self) -> bool {
1105 matches!(*self, Self::Bitfield(_))
1106 }
1107}
1108
1109macro_rules! impl_maybe_ref {
1110 () => ();
1111 ($name:ident, $($more:ident,)*) => (
1112 impl_maybe_ref!($($more,)*);
1113
1114 impl MaybeRef<$name> for Type {
1115 fn maybe_ref(&self) -> Option<&$name> {
1116 if let Self::$name(x) = self { Some(x) } else { None }
1117 }
1118
1119 fn to_ref(&self) -> &$name {
1120 self.maybe_ref().unwrap_or_else(|| {
1121 panic!("{} is not a {}", self.get_name(), stringify!($name))
1122 })
1123 }
1124 }
1125 );
1126}
1127
1128impl_maybe_ref!(
1129 Alias,
1130 Bitfield,
1131 Class,
1132 Enumeration,
1133 Function,
1134 Basic,
1135 Interface,
1136 Record,
1137 Union,
1138);
1139
1140impl<U> MaybeRefAs for U {
1141 fn maybe_ref_as<T>(&self) -> Option<&T>
1142 where
1143 Self: MaybeRef<T>,
1144 {
1145 self.maybe_ref()
1146 }
1147
1148 fn to_ref_as<T>(&self) -> &T
1149 where
1150 Self: MaybeRef<T>,
1151 {
1152 self.to_ref()
1153 }
1154}
1155
1156#[derive(Debug, Default)]
1157pub struct Namespace {
1158 pub name: String,
1159 pub types: Vec<Option<Type>>,
1160 pub index: BTreeMap<String, u32>,
1161 pub glib_name_index: HashMap<String, u32>,
1162 pub constants: Vec<Constant>,
1163 pub functions: Vec<Function>,
1164 pub package_names: Vec<String>,
1165 pub versions: BTreeSet<Version>,
1166 pub doc: Option<String>,
1167 pub doc_deprecated: Option<String>,
1168 pub shared_library: Vec<String>,
1169 pub identifier_prefixes: Vec<String>,
1170 pub symbol_prefixes: Vec<String>,
1171 pub c_includes: Vec<String>,
1174}
1175
1176impl Namespace {
1177 fn new(name: &str) -> Self {
1178 Self {
1179 name: name.into(),
1180 ..Self::default()
1181 }
1182 }
1183
1184 fn add_constant(&mut self, c: Constant) {
1185 self.constants.push(c);
1186 }
1187
1188 fn add_function(&mut self, f: Function) {
1189 self.functions.push(f);
1190 }
1191
1192 fn type_(&self, id: u32) -> &Type {
1193 self.types[id as usize].as_ref().unwrap()
1194 }
1195
1196 fn type_mut(&mut self, id: u32) -> &mut Type {
1197 self.types[id as usize].as_mut().unwrap()
1198 }
1199
1200 fn add_type(&mut self, name: &str, typ: Option<Type>) -> u32 {
1201 let glib_name = typ
1202 .as_ref()
1203 .and_then(Type::get_glib_name)
1204 .map(ToOwned::to_owned);
1205 let id = if let Some(id) = self.find_type(name) {
1206 self.types[id as usize] = typ;
1207 id
1208 } else {
1209 let id = self.types.len() as u32;
1210 self.types.push(typ);
1211 self.index.insert(name.into(), id);
1212 id
1213 };
1214 if let Some(s) = glib_name {
1215 self.glib_name_index.insert(s, id);
1216 }
1217 id
1218 }
1219
1220 fn find_type(&self, name: &str) -> Option<u32> {
1221 self.index.get(name).copied()
1222 }
1223}
1224
1225pub const INTERNAL_NAMESPACE_NAME: &str = "*";
1226pub const INTERNAL_NAMESPACE: u16 = 0;
1227pub const MAIN_NAMESPACE: u16 = 1;
1228
1229#[derive(Debug, Default)]
1230pub struct Library {
1231 pub namespaces: Vec<Namespace>,
1232 pub index: HashMap<String, (u16, bool)>,
1233 pub doc_format: DocFormat,
1234}
1235
1236impl Library {
1237 pub fn new(main_namespace_name: &str) -> Self {
1238 let mut library = Self::default();
1239 assert_eq!(
1240 INTERNAL_NAMESPACE,
1241 library.add_namespace(INTERNAL_NAMESPACE_NAME, true)
1242 );
1243 for &(name, t) in BASIC {
1244 library.add_type(INTERNAL_NAMESPACE, name, Type::Basic(t));
1245 }
1246 assert_eq!(
1247 MAIN_NAMESPACE,
1248 library.add_namespace(main_namespace_name, false)
1249 );
1250
1251 Type::c_array(&mut library, TypeId::tid_utf8(), None, None);
1253 Type::c_array(&mut library, TypeId::tid_filename(), None, None);
1254 Type::c_array(&mut library, TypeId::tid_os_string(), None, None);
1255
1256 library
1257 }
1258
1259 pub fn show_non_bound_types(&self, env: &Env) {
1260 let not_allowed_ending = [
1261 "Class",
1262 "Private",
1263 "Func",
1264 "Callback",
1265 "Accessible",
1266 "Iface",
1267 "Type",
1268 "Interface",
1269 ];
1270 let namespace_name = self.namespaces[MAIN_NAMESPACE as usize].name.clone();
1271 let mut parents = HashSet::new();
1272
1273 for x in self.namespace(MAIN_NAMESPACE).types.iter().flatten() {
1274 let name = x.get_name();
1275 let full_name = format!("{namespace_name}.{name}");
1276 let mut check_methods = true;
1277
1278 if !not_allowed_ending.iter().any(|s| name.ends_with(s))
1279 || x.is_enumeration()
1280 || x.is_bitfield()
1281 {
1282 let version = x.get_deprecated_version();
1283 let depr_version = version.unwrap_or(env.config.min_cfg_version);
1284 if !env.analysis.objects.contains_key(&full_name)
1285 && !env.analysis.records.contains_key(&full_name)
1286 && !env.config.objects.iter().any(|o| o.1.name == full_name)
1287 && depr_version >= env.config.min_cfg_version
1288 {
1289 check_methods = false;
1290 if let Some(version) = version {
1291 println!("[NOT GENERATED] {full_name} (deprecated in {version})");
1292 } else {
1293 println!("[NOT GENERATED] {full_name}");
1294 }
1295 } else if let Type::Class(Class { properties, .. }) = x
1296 && !env
1297 .config
1298 .objects
1299 .get(&full_name)
1300 .is_some_and(|obj| obj.generate_builder)
1301 && properties
1302 .iter()
1303 .any(|prop| prop.construct_only || prop.construct || prop.writable)
1304 {
1305 println!("[NOT GENERATED BUILDER] {full_name}Builder");
1306 }
1307 }
1308 if let (Some(tid), Some(gobject_id)) = (
1309 env.library.find_type(0, &full_name),
1310 env.library.find_type(0, "GObject.Object"),
1311 ) {
1312 for &super_tid in env.class_hierarchy.supertypes(tid) {
1313 let ty = env.library.type_(super_tid);
1314 let ns_id = super_tid.ns_id as usize;
1315 let full_parent_name =
1316 format!("{}.{}", self.namespaces[ns_id].name, ty.get_name());
1317 if super_tid != gobject_id
1318 && env
1319 .type_status(&super_tid.full_name(&env.library))
1320 .ignored()
1321 && parents.insert(full_parent_name.clone())
1322 {
1323 if let Some(version) = ty.get_deprecated_version() {
1324 println!(
1325 "[NOT GENERATED PARENT] {full_parent_name} (deprecated in {version})"
1326 );
1327 } else {
1328 println!("[NOT GENERATED PARENT] {full_parent_name}");
1329 }
1330 }
1331 }
1332 if check_methods {
1333 self.not_bound_functions(
1334 env,
1335 &format!("{full_name}::"),
1336 x.functions(),
1337 "METHOD",
1338 );
1339 }
1340 }
1341 }
1342 self.not_bound_functions(
1343 env,
1344 &format!("{namespace_name}."),
1345 &self.namespace(MAIN_NAMESPACE).functions,
1346 "FUNCTION",
1347 );
1348 }
1349
1350 fn not_bound_functions(&self, env: &Env, prefix: &str, functions: &[Function], kind: &str) {
1351 for func in functions {
1352 let version = func.deprecated_version;
1353 let depr_version = version.unwrap_or(env.config.min_cfg_version);
1354
1355 if depr_version < env.config.min_cfg_version {
1356 continue;
1357 }
1358
1359 let mut errors = func
1360 .parameters
1361 .iter()
1362 .filter_map(|p| {
1363 let mut ty = env.library.type_(p.typ());
1364 let mut ns_id = p.typ().ns_id as usize;
1365 if let Some((t, n)) = ty.get_inner_type(env) {
1366 ty = t;
1367 ns_id = n as usize;
1368 }
1369 if ty.is_basic() {
1370 return None;
1371 }
1372 let full_name = format!("{}.{}", self.namespaces[ns_id].name, ty.get_name());
1373 if env.type_status(&p.typ().full_name(&env.library)).ignored()
1374 && !env.analysis.objects.contains_key(&full_name)
1375 && !env.analysis.records.contains_key(&full_name)
1376 && !env.config.objects.iter().any(|o| o.1.name == full_name)
1377 {
1378 Some(full_name)
1379 } else {
1380 None
1381 }
1382 })
1383 .collect::<Vec<_>>();
1384 {
1385 let mut ty = env.library.type_(func.ret.typ());
1386 let mut ns_id = func.ret.typ().ns_id as usize;
1387 if let Some((t, n)) = ty.get_inner_type(env) {
1388 ty = t;
1389 ns_id = n as usize;
1390 }
1391 if !ty.is_basic() {
1392 let full_name = format!("{}.{}", self.namespaces[ns_id].name, ty.get_name());
1393 if env
1394 .type_status(&func.ret.typ().full_name(&env.library))
1395 .ignored()
1396 && !env.analysis.objects.contains_key(&full_name)
1397 && !env.analysis.records.contains_key(&full_name)
1398 && !env.config.objects.iter().any(|o| o.1.name == full_name)
1399 {
1400 errors.push(full_name);
1401 }
1402 }
1403 }
1404 if !errors.is_empty() {
1405 let full_name = format!("{}{}", prefix, func.name);
1406 let deprecated_version = match version {
1407 Some(dv) => format!(" (deprecated in {dv})"),
1408 None => String::new(),
1409 };
1410 if errors.len() > 1 {
1411 let end = errors.pop().unwrap();
1412 let begin = errors.join(", ");
1413 println!(
1414 "[NOT GENERATED {kind}] {full_name}{deprecated_version} because of {begin} and {end}"
1415 );
1416 } else {
1417 println!(
1418 "[NOT GENERATED {}] {}{} because of {}",
1419 kind, full_name, deprecated_version, errors[0]
1420 );
1421 }
1422 }
1423 }
1424 }
1425
1426 pub fn namespace(&self, ns_id: u16) -> &Namespace {
1427 &self.namespaces[ns_id as usize]
1428 }
1429
1430 pub fn namespace_mut(&mut self, ns_id: u16) -> &mut Namespace {
1431 &mut self.namespaces[ns_id as usize]
1432 }
1433
1434 pub fn find_namespace(&self, name: &str) -> Option<(u16, bool)> {
1435 self.index.get(name).copied()
1436 }
1437
1438 pub fn add_namespace(&mut self, name: &str, parsed: bool) -> u16 {
1439 if let Some(&(id, _)) = self.index.get(name) {
1440 id
1441 } else {
1442 let id = self.namespaces.len() as u16;
1443 self.namespaces.push(Namespace::new(name));
1444 self.index.insert(name.into(), (id, parsed));
1445 id
1446 }
1447 }
1448
1449 pub fn add_constant(&mut self, ns_id: u16, c: Constant) {
1450 self.namespace_mut(ns_id).add_constant(c);
1451 }
1452
1453 pub fn add_function(&mut self, ns_id: u16, f: Function) {
1454 self.namespace_mut(ns_id).add_function(f);
1455 }
1456
1457 pub fn add_type(&mut self, ns_id: u16, name: &str, typ: Type) -> TypeId {
1458 TypeId {
1459 ns_id,
1460 id: self.namespace_mut(ns_id).add_type(name, Some(typ)),
1461 }
1462 }
1463
1464 #[allow(clippy::manual_map)]
1465 pub fn find_type(&self, current_ns_id: u16, name: &str) -> Option<TypeId> {
1466 let (mut ns, name) = split_namespace_name(name);
1467 if name == "GType" {
1468 ns = None;
1469 }
1470
1471 if let Some(ns) = ns {
1472 self.find_namespace(ns).and_then(|(ns_id, _)| {
1473 self.namespace(ns_id)
1474 .find_type(name)
1475 .map(|id| TypeId { ns_id, id })
1476 })
1477 } else if let Some(id) = self.namespace(current_ns_id).find_type(name) {
1478 Some(TypeId {
1479 ns_id: current_ns_id,
1480 id,
1481 })
1482 } else if let Some(id) = self.namespace(INTERNAL_NAMESPACE).find_type(name) {
1483 Some(TypeId {
1484 ns_id: INTERNAL_NAMESPACE,
1485 id,
1486 })
1487 } else {
1488 None
1489 }
1490 }
1491
1492 pub fn find_or_stub_type(&mut self, current_ns_id: u16, name: &str) -> TypeId {
1493 if let Some(tid) = self.find_type(current_ns_id, name) {
1494 return tid;
1495 }
1496
1497 let (ns, name) = split_namespace_name(name);
1498
1499 if let Some(ns) = ns {
1500 let (ns_id, _) = self
1501 .find_namespace(ns)
1502 .unwrap_or_else(|| (self.add_namespace(ns, false), false));
1503 let ns = self.namespace_mut(ns_id);
1504 let id = ns
1505 .find_type(name)
1506 .unwrap_or_else(|| ns.add_type(name, None));
1507 return TypeId { ns_id, id };
1508 }
1509
1510 let id = self.namespace_mut(current_ns_id).add_type(name, None);
1511 TypeId {
1512 ns_id: current_ns_id,
1513 id,
1514 }
1515 }
1516
1517 pub fn type_(&self, tid: TypeId) -> &Type {
1518 self.namespace(tid.ns_id).type_(tid.id)
1519 }
1520
1521 pub fn type_mut(&mut self, tid: TypeId) -> &mut Type {
1522 self.namespace_mut(tid.ns_id).type_mut(tid.id)
1523 }
1524
1525 pub fn register_version(&mut self, ns_id: u16, version: Version) {
1526 self.namespace_mut(ns_id).versions.insert(version);
1527 }
1528
1529 pub fn types<'a>(&'a self) -> Box<dyn Iterator<Item = (TypeId, &'a Type)> + 'a> {
1530 Box::new(self.namespaces.iter().enumerate().flat_map(|(ns_id, ns)| {
1531 ns.types.iter().enumerate().filter_map(move |(id, type_)| {
1532 let tid = TypeId {
1533 ns_id: ns_id as u16,
1534 id: id as u32,
1535 };
1536 type_.as_ref().map(|t| (tid, t))
1537 })
1538 }))
1539 }
1540
1541 pub fn namespace_types<'a>(
1543 &'a self,
1544 ns_id: u16,
1545 ) -> Box<dyn Iterator<Item = (TypeId, &'a Type)> + 'a> {
1546 let ns = self.namespace(ns_id);
1547 Box::new(ns.index.values().map(move |&id| {
1548 (
1549 TypeId { ns_id, id },
1550 ns.types[id as usize].as_ref().unwrap(),
1551 )
1552 }))
1553 }
1554
1555 pub fn is_crate(&self, crate_name: &str) -> bool {
1556 self.namespace(MAIN_NAMESPACE).name == crate_name
1557 }
1558
1559 pub fn is_glib_crate(&self) -> bool {
1560 self.is_crate("GObject") || self.is_crate("GLib")
1561 }
1562}
1563
1564#[cfg(test)]
1565mod tests {
1566 use super::*;
1567
1568 #[test]
1569 fn basic_tids() {
1570 let lib = Library::new("Gtk");
1571
1572 assert_eq!(TypeId::tid_none().full_name(&lib), "*.None");
1573 assert_eq!(TypeId::tid_bool().full_name(&lib), "*.Boolean");
1574 assert_eq!(TypeId::tid_uint32().full_name(&lib), "*.UInt32");
1575 assert_eq!(TypeId::tid_c_bool().full_name(&lib), "*.Bool");
1576 assert_eq!(TypeId::tid_utf8().full_name(&lib), "*.Utf8");
1577 assert_eq!(TypeId::tid_filename().full_name(&lib), "*.Filename");
1578 assert_eq!(TypeId::tid_os_string().full_name(&lib), "*.OsString");
1579 }
1580}