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