libgir/
library.rs

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, 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/// Annotation describing lifetime requirements / guarantees of callback
67/// parameters, that is callback itself and associated user data.
68#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
69pub enum ParameterScope {
70    /// Parameter is not of callback type.
71    #[default]
72    None,
73    /// Used only for the duration of the call.
74    ///
75    /// Can be invoked multiple times.
76    Call,
77    /// Used for the duration of the asynchronous call.
78    ///
79    /// Invoked exactly once when asynchronous call completes.
80    Async,
81    /// Used until notified with associated destroy notify parameter.
82    ///
83    /// Can be invoked multiple times.
84    Notified,
85    /// Forever scope
86    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    // Same encoding as Filename but can contains any string
241    // Not defined in GLib directly
242    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    // TODO: this is temporary name, change it when type added to GLib
311    ("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    /// A 'pointer' record is one where the c:type is a typedef that
452    /// doesn't look like a pointer, but is internally: typedef struct _X *X;
453    pub pointer: bool,
454    /// A 'disguised' record is one where the c:type is a typedef to
455    /// a struct whose content and size are unknown, it is :typedef struct _X X;
456    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    /// Index of the user data parameter associated with the callback.
538    pub closure: Option<usize>,
539    /// Index of the destroy notification parameter associated with the
540    /// callback.
541    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    /// Specific to fundamental types
618    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    /// If the type is an Alias containing a basic, it'll return true (whereas
873    /// `is_basic` won't).
874    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    /// C headers, relative to include directories provided by pkg-config
1002    /// --cflags.
1003    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)]
1060pub struct Library {
1061    pub namespaces: Vec<Namespace>,
1062    pub index: HashMap<String, u16>,
1063}
1064
1065impl Library {
1066    pub fn new(main_namespace_name: &str) -> Self {
1067        let mut library = Self {
1068            namespaces: Vec::new(),
1069            index: HashMap::new(),
1070        };
1071        assert_eq!(
1072            INTERNAL_NAMESPACE,
1073            library.add_namespace(INTERNAL_NAMESPACE_NAME)
1074        );
1075        for &(name, t) in BASIC {
1076            library.add_type(INTERNAL_NAMESPACE, name, Type::Basic(t));
1077        }
1078        assert_eq!(MAIN_NAMESPACE, library.add_namespace(main_namespace_name));
1079
1080        // For string_type override
1081        Type::c_array(&mut library, TypeId::tid_utf8(), None, None);
1082        Type::c_array(&mut library, TypeId::tid_filename(), None, None);
1083        Type::c_array(&mut library, TypeId::tid_os_string(), None, None);
1084
1085        library
1086    }
1087
1088    pub fn show_non_bound_types(&self, env: &Env) {
1089        let not_allowed_ending = [
1090            "Class",
1091            "Private",
1092            "Func",
1093            "Callback",
1094            "Accessible",
1095            "Iface",
1096            "Type",
1097            "Interface",
1098        ];
1099        let namespace_name = self.namespaces[MAIN_NAMESPACE as usize].name.clone();
1100        let mut parents = HashSet::new();
1101
1102        for x in self.namespace(MAIN_NAMESPACE).types.iter().flatten() {
1103            let name = x.get_name();
1104            let full_name = format!("{namespace_name}.{name}");
1105            let mut check_methods = true;
1106
1107            if !not_allowed_ending.iter().any(|s| name.ends_with(s))
1108                || x.is_enumeration()
1109                || x.is_bitfield()
1110            {
1111                let version = x.get_deprecated_version();
1112                let depr_version = version.unwrap_or(env.config.min_cfg_version);
1113                if !env.analysis.objects.contains_key(&full_name)
1114                    && !env.analysis.records.contains_key(&full_name)
1115                    && !env.config.objects.iter().any(|o| o.1.name == full_name)
1116                    && depr_version >= env.config.min_cfg_version
1117                {
1118                    check_methods = false;
1119                    if let Some(version) = version {
1120                        println!("[NOT GENERATED] {full_name} (deprecated in {version})");
1121                    } else {
1122                        println!("[NOT GENERATED] {full_name}");
1123                    }
1124                } else if let Type::Class(Class { properties, .. }) = x {
1125                    if !env
1126                        .config
1127                        .objects
1128                        .get(&full_name)
1129                        .is_some_and(|obj| obj.generate_builder)
1130                        && properties
1131                            .iter()
1132                            .any(|prop| prop.construct_only || prop.construct || prop.writable)
1133                    {
1134                        println!("[NOT GENERATED BUILDER] {full_name}Builder");
1135                    }
1136                }
1137            }
1138            if let (Some(tid), Some(gobject_id)) = (
1139                env.library.find_type(0, &full_name),
1140                env.library.find_type(0, "GObject.Object"),
1141            ) {
1142                for &super_tid in env.class_hierarchy.supertypes(tid) {
1143                    let ty = env.library.type_(super_tid);
1144                    let ns_id = super_tid.ns_id as usize;
1145                    let full_parent_name =
1146                        format!("{}.{}", self.namespaces[ns_id].name, ty.get_name());
1147                    if super_tid != gobject_id
1148                        && env
1149                            .type_status(&super_tid.full_name(&env.library))
1150                            .ignored()
1151                        && parents.insert(full_parent_name.clone())
1152                    {
1153                        if let Some(version) = ty.get_deprecated_version() {
1154                            println!(
1155                                "[NOT GENERATED PARENT] {full_parent_name} (deprecated in {version})"
1156                            );
1157                        } else {
1158                            println!("[NOT GENERATED PARENT] {full_parent_name}");
1159                        }
1160                    }
1161                }
1162                if check_methods {
1163                    self.not_bound_functions(
1164                        env,
1165                        &format!("{full_name}::"),
1166                        x.functions(),
1167                        "METHOD",
1168                    );
1169                }
1170            }
1171        }
1172        self.not_bound_functions(
1173            env,
1174            &format!("{namespace_name}."),
1175            &self.namespace(MAIN_NAMESPACE).functions,
1176            "FUNCTION",
1177        );
1178    }
1179
1180    fn not_bound_functions(&self, env: &Env, prefix: &str, functions: &[Function], kind: &str) {
1181        for func in functions {
1182            let version = func.deprecated_version;
1183            let depr_version = version.unwrap_or(env.config.min_cfg_version);
1184
1185            if depr_version < env.config.min_cfg_version {
1186                continue;
1187            }
1188
1189            let mut errors = func
1190                .parameters
1191                .iter()
1192                .filter_map(|p| {
1193                    let mut ty = env.library.type_(p.typ);
1194                    let mut ns_id = p.typ.ns_id as usize;
1195                    if let Some((t, n)) = ty.get_inner_type(env) {
1196                        ty = t;
1197                        ns_id = n as usize;
1198                    }
1199                    if ty.is_basic() {
1200                        return None;
1201                    }
1202                    let full_name = format!("{}.{}", self.namespaces[ns_id].name, ty.get_name());
1203                    if env.type_status(&p.typ.full_name(&env.library)).ignored()
1204                        && !env.analysis.objects.contains_key(&full_name)
1205                        && !env.analysis.records.contains_key(&full_name)
1206                        && !env.config.objects.iter().any(|o| o.1.name == full_name)
1207                    {
1208                        Some(full_name)
1209                    } else {
1210                        None
1211                    }
1212                })
1213                .collect::<Vec<_>>();
1214            {
1215                let mut ty = env.library.type_(func.ret.typ);
1216                let mut ns_id = func.ret.typ.ns_id as usize;
1217                if let Some((t, n)) = ty.get_inner_type(env) {
1218                    ty = t;
1219                    ns_id = n as usize;
1220                }
1221                if !ty.is_basic() {
1222                    let full_name = format!("{}.{}", self.namespaces[ns_id].name, ty.get_name());
1223                    if env
1224                        .type_status(&func.ret.typ.full_name(&env.library))
1225                        .ignored()
1226                        && !env.analysis.objects.contains_key(&full_name)
1227                        && !env.analysis.records.contains_key(&full_name)
1228                        && !env.config.objects.iter().any(|o| o.1.name == full_name)
1229                    {
1230                        errors.push(full_name);
1231                    }
1232                }
1233            }
1234            if !errors.is_empty() {
1235                let full_name = format!("{}{}", prefix, func.name);
1236                let deprecated_version = match version {
1237                    Some(dv) => format!(" (deprecated in {dv})"),
1238                    None => String::new(),
1239                };
1240                if errors.len() > 1 {
1241                    let end = errors.pop().unwrap();
1242                    let begin = errors.join(", ");
1243                    println!(
1244                        "[NOT GENERATED {kind}] {full_name}{deprecated_version} because of {begin} and {end}"
1245                    );
1246                } else {
1247                    println!(
1248                        "[NOT GENERATED {}] {}{} because of {}",
1249                        kind, full_name, deprecated_version, errors[0]
1250                    );
1251                }
1252            }
1253        }
1254    }
1255
1256    pub fn namespace(&self, ns_id: u16) -> &Namespace {
1257        &self.namespaces[ns_id as usize]
1258    }
1259
1260    pub fn namespace_mut(&mut self, ns_id: u16) -> &mut Namespace {
1261        &mut self.namespaces[ns_id as usize]
1262    }
1263
1264    pub fn find_namespace(&self, name: &str) -> Option<u16> {
1265        self.index.get(name).copied()
1266    }
1267
1268    pub fn add_namespace(&mut self, name: &str) -> u16 {
1269        if let Some(&id) = self.index.get(name) {
1270            id
1271        } else {
1272            let id = self.namespaces.len() as u16;
1273            self.namespaces.push(Namespace::new(name));
1274            self.index.insert(name.into(), id);
1275            id
1276        }
1277    }
1278
1279    pub fn add_constant(&mut self, ns_id: u16, c: Constant) {
1280        self.namespace_mut(ns_id).add_constant(c);
1281    }
1282
1283    pub fn add_function(&mut self, ns_id: u16, f: Function) {
1284        self.namespace_mut(ns_id).add_function(f);
1285    }
1286
1287    pub fn add_type(&mut self, ns_id: u16, name: &str, typ: Type) -> TypeId {
1288        TypeId {
1289            ns_id,
1290            id: self.namespace_mut(ns_id).add_type(name, Some(typ)),
1291        }
1292    }
1293
1294    #[allow(clippy::manual_map)]
1295    pub fn find_type(&self, current_ns_id: u16, name: &str) -> Option<TypeId> {
1296        let (mut ns, name) = split_namespace_name(name);
1297        if name == "GType" {
1298            ns = None;
1299        }
1300
1301        if let Some(ns) = ns {
1302            self.find_namespace(ns).and_then(|ns_id| {
1303                self.namespace(ns_id)
1304                    .find_type(name)
1305                    .map(|id| TypeId { ns_id, id })
1306            })
1307        } else if let Some(id) = self.namespace(current_ns_id).find_type(name) {
1308            Some(TypeId {
1309                ns_id: current_ns_id,
1310                id,
1311            })
1312        } else if let Some(id) = self.namespace(INTERNAL_NAMESPACE).find_type(name) {
1313            Some(TypeId {
1314                ns_id: INTERNAL_NAMESPACE,
1315                id,
1316            })
1317        } else {
1318            None
1319        }
1320    }
1321
1322    pub fn find_or_stub_type(&mut self, current_ns_id: u16, name: &str) -> TypeId {
1323        if let Some(tid) = self.find_type(current_ns_id, name) {
1324            return tid;
1325        }
1326
1327        let (ns, name) = split_namespace_name(name);
1328
1329        if let Some(ns) = ns {
1330            let ns_id = self
1331                .find_namespace(ns)
1332                .unwrap_or_else(|| self.add_namespace(ns));
1333            let ns = self.namespace_mut(ns_id);
1334            let id = ns
1335                .find_type(name)
1336                .unwrap_or_else(|| ns.add_type(name, None));
1337            return TypeId { ns_id, id };
1338        }
1339
1340        let id = self.namespace_mut(current_ns_id).add_type(name, None);
1341        TypeId {
1342            ns_id: current_ns_id,
1343            id,
1344        }
1345    }
1346
1347    pub fn type_(&self, tid: TypeId) -> &Type {
1348        self.namespace(tid.ns_id).type_(tid.id)
1349    }
1350
1351    pub fn type_mut(&mut self, tid: TypeId) -> &mut Type {
1352        self.namespace_mut(tid.ns_id).type_mut(tid.id)
1353    }
1354
1355    pub fn register_version(&mut self, ns_id: u16, version: Version) {
1356        self.namespace_mut(ns_id).versions.insert(version);
1357    }
1358
1359    pub fn types<'a>(&'a self) -> Box<dyn Iterator<Item = (TypeId, &'a Type)> + 'a> {
1360        Box::new(self.namespaces.iter().enumerate().flat_map(|(ns_id, ns)| {
1361            ns.types.iter().enumerate().filter_map(move |(id, type_)| {
1362                let tid = TypeId {
1363                    ns_id: ns_id as u16,
1364                    id: id as u32,
1365                };
1366                type_.as_ref().map(|t| (tid, t))
1367            })
1368        }))
1369    }
1370
1371    /// Types from a single namespace in alphabetical order.
1372    pub fn namespace_types<'a>(
1373        &'a self,
1374        ns_id: u16,
1375    ) -> Box<dyn Iterator<Item = (TypeId, &'a Type)> + 'a> {
1376        let ns = self.namespace(ns_id);
1377        Box::new(ns.index.values().map(move |&id| {
1378            (
1379                TypeId { ns_id, id },
1380                ns.types[id as usize].as_ref().unwrap(),
1381            )
1382        }))
1383    }
1384
1385    pub fn is_crate(&self, crate_name: &str) -> bool {
1386        self.namespace(MAIN_NAMESPACE).name == crate_name
1387    }
1388
1389    pub fn is_glib_crate(&self) -> bool {
1390        self.is_crate("GObject") || self.is_crate("GLib")
1391    }
1392}
1393
1394#[cfg(test)]
1395mod tests {
1396    use super::*;
1397
1398    #[test]
1399    fn basic_tids() {
1400        let lib = Library::new("Gtk");
1401
1402        assert_eq!(TypeId::tid_none().full_name(&lib), "*.None");
1403        assert_eq!(TypeId::tid_bool().full_name(&lib), "*.Boolean");
1404        assert_eq!(TypeId::tid_uint32().full_name(&lib), "*.UInt32");
1405        assert_eq!(TypeId::tid_c_bool().full_name(&lib), "*.Bool");
1406        assert_eq!(TypeId::tid_utf8().full_name(&lib), "*.Utf8");
1407        assert_eq!(TypeId::tid_filename().full_name(&lib), "*.Filename");
1408        assert_eq!(TypeId::tid_os_string().full_name(&lib), "*.OsString");
1409    }
1410}