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#[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)]
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 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 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}