gir_parser/
namespace.rs

1use xmlserde_derives::XmlDeserialize;
2
3use crate::{
4    alias::Alias,
5    attribute::Attribute,
6    bitfield::BitField,
7    boxed::Boxed,
8    callback::Callback,
9    class::Class,
10    constant::Constant,
11    enums::Enumeration,
12    function::{Function, FunctionInline},
13    function_macro::FunctionMacro,
14    interface::Interface,
15    prelude::*,
16    record::Record,
17    union::Union,
18    version::Version,
19};
20
21#[derive(Clone, Debug, XmlDeserialize)]
22#[cfg_attr(test, derive(Default))]
23#[xmlserde(root = b"namespace")]
24#[xmlserde(deny_unknown_fields)]
25pub struct Namespace {
26    #[xmlserde(name = b"name", ty = "attr")]
27    name: String,
28    #[xmlserde(name = b"version", ty = "attr")]
29    version: Version,
30    #[xmlserde(name = b"c:identifier-prefixes", ty = "attr")]
31    c_identifier_prefixes: Option<String>,
32    // Deprecated, backwards compatibility only
33    #[xmlserde(name = b"c:prefix", ty = "attr")]
34    c_prefix: Option<String>,
35    #[xmlserde(name = b"c:symbol-prefixes", ty = "attr")]
36    c_symbol_prefixes: Option<String>,
37    #[xmlserde(name = b"shared-library", ty = "attr")]
38    shared_library: Option<String>,
39
40    #[xmlserde(name = b"alias", ty = "child")]
41    aliases: Vec<Alias>,
42    #[xmlserde(name = b"class", ty = "child")]
43    classes: Vec<Class>,
44    #[xmlserde(name = b"interface", ty = "child")]
45    interfaces: Vec<Interface>,
46    #[xmlserde(name = b"record", ty = "child")]
47    records: Vec<Record>,
48    #[xmlserde(name = b"enumeration", ty = "child")]
49    enums: Vec<Enumeration>,
50    #[xmlserde(name = b"function", ty = "child")]
51    functions_global: Vec<Function>,
52    #[xmlserde(name = b"function-inline", ty = "child")]
53    inline_functions: Vec<FunctionInline>,
54    #[xmlserde(name = b"function-macro", ty = "child")]
55    functions_macro: Vec<FunctionMacro>,
56    #[xmlserde(name = b"union", ty = "child")]
57    unions: Vec<Union>,
58    #[xmlserde(name = b"bitfield", ty = "child")]
59    flags: Vec<BitField>,
60    #[xmlserde(name = b"callback", ty = "child")]
61    callbacks: Vec<Callback>,
62    #[xmlserde(name = b"constant", ty = "child")]
63    constants: Vec<Constant>,
64    // Attributes: 0 or more
65    #[xmlserde(name = b"attribute", ty = "child")]
66    attributes: Vec<Attribute>,
67    #[xmlserde(name = b"glib:boxed", ty = "child")]
68    boxed: Vec<Boxed>,
69}
70
71impl Namespace {
72    pub fn name(&self) -> &str {
73        &self.name
74    }
75
76    pub fn version(&self) -> &Version {
77        &self.version
78    }
79
80    pub fn c_identifier_prefixes(&self) -> impl Iterator<Item = &str> {
81        self.c_identifier_prefixes
82            .as_ref()
83            .or(self.c_prefix.as_ref())
84            .filter(|ps| !ps.is_empty())
85            .map(|ps| ps.split(','))
86            .into_iter()
87            .flatten()
88    }
89
90    pub fn c_symbol_prefixes(&self) -> impl Iterator<Item = &str> {
91        self.c_symbol_prefixes
92            .as_ref()
93            .filter(|ps| !ps.is_empty())
94            .map(|ps| ps.split(','))
95            .into_iter()
96            .flatten()
97    }
98
99    pub fn shared_library(&self) -> Option<&str> {
100        self.shared_library.as_deref()
101    }
102
103    pub fn aliases(&self) -> &[Alias] {
104        &self.aliases
105    }
106
107    pub fn constants(&self) -> &[Constant] {
108        &self.constants
109    }
110
111    pub fn functions(&self) -> &[Function] {
112        &self.functions_global
113    }
114
115    pub fn inlined_functions(&self) -> &[FunctionInline] {
116        &self.inline_functions
117    }
118
119    pub fn macros(&self) -> &[FunctionMacro] {
120        &self.functions_macro
121    }
122
123    pub fn enums(&self) -> &[Enumeration] {
124        &self.enums
125    }
126
127    pub fn flags(&self) -> &[BitField] {
128        &self.flags
129    }
130
131    pub fn unions(&self) -> &[Union] {
132        &self.unions
133    }
134
135    pub fn boxed(&self) -> &[Boxed] {
136        &self.boxed
137    }
138
139    pub fn records(&self) -> &[Record] {
140        &self.records
141    }
142
143    pub fn classes(&self) -> &[Class] {
144        &self.classes
145    }
146
147    pub fn callbacks(&self) -> &[Callback] {
148        &self.callbacks
149    }
150
151    pub fn interfaces(&self) -> &[Interface] {
152        &self.interfaces
153    }
154
155    /// Copied from the old gir
156    pub fn link_name(&self) -> Option<&str> {
157        let mut s = self.shared_library.as_deref()?;
158
159        if s.starts_with("lib") {
160            s = &s[3..];
161        }
162
163        if let Some(offset) = s.rfind(".so") {
164            s = &s[..offset];
165        } else if let Some(offset) = s.rfind(".dll") {
166            s = &s[..offset];
167            if let Some(offset) = s.rfind('-') {
168                s = &s[..offset];
169            }
170        }
171
172        Some(s)
173    }
174}
175
176impl_attributable!(Namespace);
177
178#[cfg(test)]
179mod tests {
180    #[test]
181    fn shared_library_to_link_name() {
182        let mut namespace = super::Namespace::default();
183        let tests = [
184            ("libgtk-4-1.dll", "gtk-4"),
185            ("libatk-1.0.so.0", "atk-1.0"),
186            ("libgdk_pixbuf-2.0.so.0", "gdk_pixbuf-2.0"),
187        ];
188        for (shared_lib, expected_result) in tests {
189            namespace.shared_library = Some(shared_lib.to_owned());
190            assert_eq!(namespace.link_name(), Some(expected_result));
191        }
192    }
193}