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 pub fn make_trait(&mut self, trait_name: &str) {
55 self.make_in_prelude();
56 self.name = trait_name.into();
57 }
58
59 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}