libgir/analysis/
symbols.rs

1use std::collections::HashMap;
2
3use crate::{
4    analysis::namespaces::{self, NsId},
5    case::CaseExt,
6    library::*,
7};
8
9#[derive(Clone, Debug, Default)]
10pub struct Symbol {
11    crate_name: Option<String>,
12    module_name: Option<String>,
13    owner_name: Option<String>,
14    name: String,
15    rust_prelude: bool,
16}
17
18impl Symbol {
19    pub fn parent(&self) -> String {
20        let mut ret = String::new();
21        if Some("gobject") == self.crate_name() {
22            ret.push_str("glib::");
23        } else {
24            if let Some(ref s) = self.crate_name {
25                ret.push_str(s);
26                ret.push_str("::");
27            }
28            if let Some(ref module) = self.module_name {
29                ret.push_str(module);
30                ret.push_str("::");
31            }
32        }
33        if let Some(ref s) = self.owner_name {
34            ret.push_str(s);
35            ret.push_str("::");
36        }
37        ret
38    }
39
40    pub fn full_rust_name(&self) -> String {
41        let mut ret = self.parent();
42        ret.push_str(&self.name);
43        ret
44    }
45
46    fn make_in_prelude(&mut self) {
47        assert!(
48            self.module_name.replace("prelude".to_string()).is_none(),
49            "{self:?} already had a module name set!"
50        );
51    }
52
53    /// Convert this symbol into a trait
54    pub fn make_trait(&mut self, trait_name: &str) {
55        self.make_in_prelude();
56        self.name = trait_name.into();
57    }
58
59    /// Convert this into a method of a trait
60    pub fn make_trait_method(&mut self, trait_name: &str) {
61        self.make_in_prelude();
62        self.owner_name = Some(trait_name.into());
63    }
64
65    pub fn crate_name(&self) -> Option<&str> {
66        self.crate_name.as_deref()
67    }
68
69    pub fn owner_name(&self) -> Option<&str> {
70        self.owner_name.as_deref()
71    }
72
73    pub fn name(&self) -> &str {
74        &self.name
75    }
76
77    pub fn is_rust_prelude(&self) -> bool {
78        self.rust_prelude
79    }
80}
81
82#[derive(Debug)]
83pub struct Info {
84    symbols: Vec<Symbol>,
85    c_name_index: HashMap<String, u32>,
86    tid_index: HashMap<Option<TypeId>, u32>,
87}
88
89pub fn run(library: &Library, namespaces: &namespaces::Info) -> Info {
90    let mut info = Info {
91        symbols: Vec::new(),
92        c_name_index: HashMap::new(),
93        tid_index: HashMap::new(),
94    };
95
96    info.insert(
97        "NULL",
98        Symbol {
99            name: "None".into(),
100            rust_prelude: true,
101            ..Default::default()
102        },
103        None,
104    );
105    info.insert(
106        "FALSE",
107        Symbol {
108            name: "false".into(),
109            rust_prelude: true,
110            ..Default::default()
111        },
112        None,
113    );
114    info.insert(
115        "TRUE",
116        Symbol {
117            name: "true".into(),
118            rust_prelude: true,
119            ..Default::default()
120        },
121        None,
122    );
123
124    for (ns_id, ns) in library.namespaces.iter().enumerate() {
125        let ns_id = ns_id as NsId;
126        if ns_id == namespaces::INTERNAL {
127            continue;
128        }
129
130        let crate_name = if ns_id == namespaces::MAIN {
131            None
132        } else {
133            Some(&namespaces[ns_id].crate_name)
134        };
135
136        for (pos, typ) in ns.types.iter().map(|t| t.as_ref().unwrap()).enumerate() {
137            let symbol = Symbol {
138                crate_name: crate_name.cloned(),
139                name: typ.get_name(),
140                ..Default::default()
141            };
142            let tid = TypeId {
143                ns_id,
144                id: pos as u32,
145            };
146
147            match typ {
148                Type::Alias(Alias { c_identifier, .. }) => {
149                    info.insert(c_identifier, symbol, Some(tid));
150                }
151                Type::Enumeration(Enumeration {
152                    name,
153                    c_type,
154                    members,
155                    functions,
156                    ..
157                })
158                | Type::Bitfield(Bitfield {
159                    name,
160                    c_type,
161                    members,
162                    functions,
163                    ..
164                }) => {
165                    info.insert(c_type, symbol, Some(tid));
166                    for member in members {
167                        let symbol = Symbol {
168                            crate_name: crate_name.cloned(),
169                            owner_name: Some(name.clone()),
170                            name: member.name.to_camel(),
171                            ..Default::default()
172                        };
173                        info.insert(&member.c_identifier, symbol, None);
174                    }
175                    for func in functions {
176                        let symbol = Symbol {
177                            crate_name: crate_name.cloned(),
178                            owner_name: Some(name.clone()),
179                            name: func.name.clone(),
180                            ..Default::default()
181                        };
182                        info.insert(func.c_identifier.as_ref().unwrap(), symbol, None);
183                    }
184                }
185                Type::Record(Record {
186                    name,
187                    c_type,
188                    functions,
189                    ..
190                })
191                | Type::Class(Class {
192                    name,
193                    c_type,
194                    functions,
195                    ..
196                })
197                | Type::Interface(Interface {
198                    name,
199                    c_type,
200                    functions,
201                    ..
202                }) => {
203                    info.insert(c_type, symbol, Some(tid));
204                    for func in functions {
205                        let symbol = Symbol {
206                            crate_name: crate_name.cloned(),
207                            owner_name: Some(name.clone()),
208                            name: func.name.clone(),
209                            ..Default::default()
210                        };
211                        info.insert(func.c_identifier.as_ref().unwrap(), symbol, None);
212                    }
213                }
214                _ => {}
215            }
216        }
217    }
218
219    info
220}
221
222impl Info {
223    pub fn by_c_name(&self, name: &str) -> Option<&Symbol> {
224        self.c_name_index
225            .get(name)
226            .map(|&id| &self.symbols[id as usize])
227    }
228
229    pub fn by_c_name_mut(&mut self, name: &str) -> Option<&mut Symbol> {
230        if let Some(&id) = self.c_name_index.get(name) {
231            Some(&mut self.symbols[id as usize])
232        } else {
233            None
234        }
235    }
236
237    pub fn by_tid(&self, tid: TypeId) -> Option<&Symbol> {
238        self.tid_index
239            .get(&Some(tid))
240            .map(|&id| &self.symbols[id as usize])
241    }
242
243    fn insert(&mut self, name: &str, symbol: Symbol, tid: Option<TypeId>) {
244        let id = self.symbols.len();
245        self.symbols.push(symbol);
246        self.c_name_index.insert(name.to_owned(), id as u32);
247        if tid.is_some() {
248            self.tid_index.insert(tid, id as u32);
249        }
250    }
251}