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, 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/// 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, 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        // For string_type override
1079        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    /// Types from a single namespace in alphabetical order.
1369    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}