1use crate::lang::c::{CType, Function};
4use crate::patterns::TypePattern;
5use std::collections::{HashMap, HashSet};
6use std::iter::FromIterator;
7
8pub fn safe_name(name: &str) -> String {
18 let mut rval = name.to_string();
19
20 rval = rval.replace("fn(", "fn_");
21 rval = rval.replace("-> ()", "");
22 rval = rval.replace("->", "rval");
23 rval = rval.replace('(', "");
24 rval = rval.replace(')', "");
25 rval = rval.replace('*', "p");
26 rval = rval.replace(',', "_");
27 rval = rval.replace(' ', "_");
28
29 rval = rval.trim_end_matches('_').to_string();
30
31 rval
32}
33
34pub fn sort_types_by_dependencies(mut types: Vec<CType>) -> Vec<CType> {
37 let mut rval = Vec::new();
38
39 while !types.is_empty() {
49 let mut may_add_this_round = Vec::new();
51
52 for t in &types {
54 let needed_to_exist = t.embedded_types();
55
56 let t_is_sufficiently_fulfilled = needed_to_exist.iter().all(|x| {
57 rval.contains(x) || !types.contains(x)
61 });
62
63 if needed_to_exist.is_empty() || t_is_sufficiently_fulfilled {
65 may_add_this_round.push(t.clone());
66 }
67 }
68
69 types.retain(|x| !may_add_this_round.contains(x));
70 rval.append(&mut may_add_this_round);
71 }
72
73 rval
74}
75
76pub fn longest_common_prefix(functions: &[Function]) -> String {
94 let funcs_as_chars = functions.iter().map(|x| x.name().chars().collect::<Vec<_>>()).collect::<Vec<_>>();
95
96 let mut longest_common: Vec<char> = Vec::new();
97
98 if let Some(first) = funcs_as_chars.first() {
99 for (i, c) in first.iter().enumerate() {
100 for function in &funcs_as_chars {
101 if !function.get(i).map(|x| x == c).unwrap_or(false) {
102 return String::from_iter(&longest_common);
103 }
104 }
105 longest_common.push(*c);
106 }
107 }
108
109 String::from_iter(&longest_common)
110}
111
112pub(crate) fn ctypes_from_functions_types(functions: &[Function], extra_types: &[CType]) -> Vec<CType> {
114 let mut types = HashSet::new();
115
116 for function in functions {
117 ctypes_from_type_recursive(function.signature().rval(), &mut types);
118
119 for param in function.signature().params() {
120 ctypes_from_type_recursive(param.the_type(), &mut types);
121 }
122 }
123
124 for ty in extra_types {
125 ctypes_from_type_recursive(ty, &mut types);
126 }
127
128 types.iter().cloned().collect()
129}
130
131pub(crate) fn ctypes_from_type_recursive(start: &CType, types: &mut HashSet<CType>) {
133 types.insert(start.clone());
134
135 match start {
136 CType::Composite(inner) => {
137 for field in inner.fields() {
138 ctypes_from_type_recursive(field.the_type(), types);
139 }
140 }
141 CType::Array(inner) => ctypes_from_type_recursive(inner.array_type(), types),
142 CType::FnPointer(inner) => {
143 ctypes_from_type_recursive(inner.signature().rval(), types);
144 for param in inner.signature().params() {
145 ctypes_from_type_recursive(param.the_type(), types);
146 }
147 }
148 CType::ReadPointer(inner) => ctypes_from_type_recursive(inner, types),
149 CType::ReadWritePointer(inner) => ctypes_from_type_recursive(inner, types),
150 CType::Primitive(_) => {}
151 CType::Enum(_) => {}
152 CType::Opaque(_) => {}
153 CType::Pattern(x) => match x {
158 TypePattern::AsciiPointer => {}
159 TypePattern::FFIErrorEnum(_) => {}
160 TypePattern::NamedCallback(x) => {
161 let inner = x.fnpointer();
162 ctypes_from_type_recursive(inner.signature().rval(), types);
163 for param in inner.signature().params() {
164 ctypes_from_type_recursive(param.the_type(), types);
165 }
166 }
167 TypePattern::Slice(x) => {
168 for field in x.fields() {
169 ctypes_from_type_recursive(field.the_type(), types);
170 }
171 }
172 TypePattern::SliceMut(x) => {
173 for field in x.fields() {
174 ctypes_from_type_recursive(field.the_type(), types);
175 }
176 }
177 TypePattern::Option(x) => {
178 for field in x.fields() {
179 ctypes_from_type_recursive(field.the_type(), types);
180 }
181 }
182 TypePattern::Bool => {}
183 TypePattern::CChar => {}
184 TypePattern::APIVersion => {}
185 },
186 }
187}
188
189pub(crate) fn extract_namespaces_from_types(types: &[CType], into: &mut HashSet<String>) {
191 for t in types {
192 match t {
193 CType::Primitive(_) => {}
194 CType::Array(_) => {}
195
196 CType::Enum(x) => {
197 into.insert(x.meta().namespace().to_string());
198 }
199 CType::Opaque(x) => {
200 into.insert(x.meta().namespace().to_string());
201 }
202 CType::Composite(x) => {
203 into.insert(x.meta().namespace().to_string());
204 }
205 CType::FnPointer(_) => {}
206 CType::ReadPointer(_) => {}
207 CType::ReadWritePointer(_) => {}
208 CType::Pattern(x) => match x {
209 TypePattern::AsciiPointer => {}
210 TypePattern::APIVersion => {}
211 TypePattern::FFIErrorEnum(x) => {
212 into.insert(x.the_enum().meta().namespace().to_string());
213 }
214 TypePattern::Slice(x) => {
215 into.insert(x.meta().namespace().to_string());
216 }
217 TypePattern::SliceMut(x) => {
218 into.insert(x.meta().namespace().to_string());
219 }
220 TypePattern::Option(x) => {
221 into.insert(x.meta().namespace().to_string());
222 }
223 TypePattern::Bool => {}
224 TypePattern::CChar => {}
225 TypePattern::NamedCallback(_) => {}
226 },
227 }
228 }
229}
230
231#[derive(Clone, Debug, Eq, PartialEq)]
233pub struct NamespaceMappings {
234 mappings: HashMap<String, String>,
235}
236
237impl NamespaceMappings {
238 pub fn new(default: &str) -> Self {
240 let mut mappings = HashMap::new();
241 mappings.insert("".to_string(), default.to_string());
242 mappings.insert("_global".to_string(), default.to_string());
243
244 Self { mappings }
245 }
246
247 pub fn add(mut self, id: &str, value: &str) -> Self {
249 self.mappings.insert(id.to_string(), value.to_string());
250 self
251 }
252
253 pub fn default_namespace(&self) -> &str {
255 self.get("").expect("This must exist")
256 }
257
258 pub fn get(&self, id: &str) -> Option<&str> {
260 self.mappings.get(id).map(|x| x.as_str())
261 }
262}
263
264pub struct IdPrettifier {
266 tokens: Vec<String>,
267}
268
269impl IdPrettifier {
270 pub fn from_rust_lower(id: &str) -> Self {
272 Self {
273 tokens: id.split('_').map(|x| x.to_string()).collect(),
274 }
275 }
276
277 pub fn to_camel_case(&self) -> String {
278 self.tokens
279 .iter()
280 .map(|x| {
281 x.chars()
282 .enumerate()
283 .map(|(i, x)| if i == 0 { x.to_ascii_uppercase() } else { x })
284 .collect::<String>()
285 })
286 .collect::<Vec<_>>()
287 .join("")
288 }
289}
290
291pub fn is_global_type(t: &CType) -> bool {
302 match t {
303 CType::Primitive(_) => true,
304 CType::Array(x) => is_global_type(x.array_type()),
305 CType::Enum(_) => false,
306 CType::Opaque(_) => false,
307 CType::Composite(_) => false,
308 CType::FnPointer(_) => false,
309 CType::ReadPointer(x) => is_global_type(x),
310 CType::ReadWritePointer(x) => is_global_type(x),
311 CType::Pattern(x) => match x {
312 TypePattern::AsciiPointer => true,
313 TypePattern::APIVersion => false,
314 TypePattern::FFIErrorEnum(_) => false,
315 TypePattern::Slice(x) => x.fields().iter().all(|x| is_global_type(x.the_type())),
316 TypePattern::SliceMut(x) => x.fields().iter().all(|x| is_global_type(x.the_type())),
317 TypePattern::Option(x) => x.fields().iter().all(|x| is_global_type(x.the_type())),
318 TypePattern::Bool => true,
319 TypePattern::CChar => true,
320 TypePattern::NamedCallback(_) => false,
321 },
322 }
323}
324
325#[macro_export]
333macro_rules! here {
334 () => {
335 concat!(file!(), ":", line!())
336 };
337}
338
339#[cfg(feature = "log")]
341#[inline(always)]
342pub fn log_error<S: AsRef<str>, F: Fn() -> S>(f: F) {
343 log::error!("{}", f().as_ref());
344}
345
346#[cfg(not(feature = "log"))]
348#[inline(always)]
349pub fn log_error<S: AsRef<str>, F: Fn() -> S>(_f: F) {}
350
351#[cfg(test)]
352mod test {
353 use crate::util::IdPrettifier;
354
355 #[test]
356 fn is_pretty() {
357 assert_eq!(IdPrettifier::from_rust_lower("hello_world").to_camel_case(), "HelloWorld");
358 assert_eq!(IdPrettifier::from_rust_lower("single").to_camel_case(), "Single");
359 }
360}