1use crate::Error;
2use crate::backend::{IndentWriter, extract_namespaces_from_types, holds_opaque_without_ref, types_from_functions_types};
3use crate::lang::{Constant, Function, Type};
4use crate::pattern::LibraryPattern;
5use std::collections::HashSet;
6use std::fs::File;
7use std::path::Path;
8
9const FORBIDDEN_NAMES: [&str; 139] = [
10 "abstract",
11 "add",
12 "alias",
13 "allows",
14 "and",
15 "args",
16 "as",
17 "ascending",
18 "assert",
19 "async",
20 "await",
21 "base",
22 "bool",
23 "break",
24 "by",
25 "byte",
26 "case",
27 "catch",
28 "char",
29 "checked",
30 "class",
31 "const",
32 "continue",
33 "decimal",
34 "def",
35 "default",
36 "del",
37 "delegate",
38 "descending",
39 "do",
40 "double",
41 "dynamic",
42 "elif",
43 "else",
44 "enum",
45 "equals",
46 "event",
47 "except",
48 "explicit",
49 "extension",
50 "extern",
51 "false",
52 "False",
53 "field",
54 "file",
55 "finally",
56 "fixed",
57 "float",
58 "for",
59 "foreach",
60 "from",
61 "get",
62 "global",
63 "goto",
64 "group",
65 "if",
66 "implicit",
67 "import",
68 "in",
69 "init",
70 "int",
71 "interface",
72 "internal",
73 "into",
74 "is",
75 "join",
76 "lambda",
77 "let",
78 "lock",
79 "long",
80 "managed",
81 "nameof",
82 "namespace",
83 "new",
84 "nint",
85 "None",
86 "nonlocal",
87 "not",
88 "notnull",
89 "nuint",
90 "null",
91 "object",
92 "on",
93 "operator",
94 "or",
95 "orderby",
96 "out",
97 "override",
98 "params",
99 "partial",
100 "pass",
101 "private",
102 "protected",
103 "public",
104 "raise",
105 "readonly",
106 "record",
107 "ref",
108 "remove",
109 "required",
110 "return",
111 "sbyte",
112 "scoped",
113 "sealed",
114 "select",
115 "set",
116 "short",
117 "signed",
118 "sizeof",
119 "stackalloc",
120 "static",
121 "string",
122 "struct",
123 "switch",
124 "this",
125 "throw",
126 "true",
127 "True",
128 "try",
129 "typedef",
130 "typeof",
131 "uint",
132 "ulong",
133 "unchecked",
134 "unmanaged",
135 "unsafe",
136 "unsigned",
137 "ushort",
138 "using",
139 "value",
140 "var",
141 "virtual",
142 "void",
143 "volatile",
144 "when",
145 "where",
146 "while",
147 "with",
148 "yield",
149];
150
151#[derive(Debug)]
155pub enum Symbol {
156 Function(Function),
157 Constant(Constant),
158 Type(Type),
159 Pattern(LibraryPattern),
160}
161
162#[derive(Default, Debug)]
199pub struct InventoryBuilder {
200 functions: Vec<Function>,
201 ctypes: Vec<Type>,
202 constants: Vec<Constant>,
203 patterns: Vec<LibraryPattern>,
204 allow_reserved_names: bool,
205}
206
207impl InventoryBuilder {
208 #[must_use]
210 const fn new() -> Self {
211 Self { functions: Vec::new(), ctypes: Vec::new(), constants: Vec::new(), patterns: Vec::new(), allow_reserved_names: false }
212 }
213
214 #[must_use]
219 pub fn register(mut self, s: Symbol) -> Self {
220 match s {
221 Symbol::Function(x) => self.functions.push(x),
222 Symbol::Constant(x) => self.constants.push(x),
223 Symbol::Type(x) => self.ctypes.push(x),
224 Symbol::Pattern(x) => {
225 match &x {
226 LibraryPattern::Service(x) => {
227 self.functions.push(x.destructor().clone());
228 self.functions.extend(x.constructors().iter().cloned());
229 self.functions.extend(x.methods().iter().cloned());
230 }
231 LibraryPattern::Builtins(x) => {
232 self.functions.extend(x.functions().iter().cloned());
233 }
234 }
235 self.patterns.push(x);
236 }
237 }
238
239 self
240 }
241
242 #[must_use]
252 pub fn validate(self) -> Self {
253 for x in &self.functions {
255 let has_opaque_param = x.signature().params().iter().any(|x| holds_opaque_without_ref(x.the_type()));
256 assert!(!has_opaque_param, "Function `{}` has a (nested) opaque parameter. This can cause UB.", x.name());
257
258 let has_opaque_rval = holds_opaque_without_ref(x.signature().rval());
259 assert!(!has_opaque_rval, "Function `{}` has a (nested) opaque return value. This can cause UB.", x.name());
260 }
261
262 if !self.allow_reserved_names {
263 validate_symbol_names(&self.functions, &self.ctypes);
264 }
265
266 self
267 }
268
269 #[must_use]
277 pub fn allow_reserved_names(mut self) -> Self {
278 self.allow_reserved_names = true;
279 self
280 }
281
282 #[must_use]
284 pub fn build(self) -> Inventory {
285 Inventory::new(self.functions, self.constants, self.patterns, self.ctypes.as_slice())
286 }
287}
288
289#[derive(Clone, Debug, PartialOrd, PartialEq, Default)]
291pub struct Inventory {
292 functions: Vec<Function>,
293 ctypes: Vec<Type>,
294 constants: Vec<Constant>,
295 patterns: Vec<LibraryPattern>,
296 namespaces: Vec<String>,
297}
298
299#[derive(Clone, Debug, PartialEq)]
304pub enum InventoryItem<'a> {
305 Function(&'a Function),
306 CType(&'a Type),
307 Constant(&'a Constant),
308 Pattern(&'a LibraryPattern),
309 Namespace(&'a str),
310}
311
312impl Inventory {
313 pub(crate) fn new(functions: Vec<Function>, constants: Vec<Constant>, patterns: Vec<LibraryPattern>, extra_types: &[Type]) -> Self {
317 let mut ctypes = types_from_functions_types(&functions, extra_types);
318 let mut namespaces = HashSet::new();
319
320 extract_namespaces_from_types(&ctypes, &mut namespaces);
322 namespaces.extend(functions.iter().map(|x| x.meta().module().to_string()));
323 namespaces.extend(constants.iter().map(|x| x.meta().module().to_string()));
324
325 let mut namespaces = namespaces.iter().cloned().collect::<Vec<String>>();
326 namespaces.sort();
327
328 ctypes.sort();
332 Self { functions, ctypes, constants, patterns, namespaces }
335 }
336
337 #[must_use]
339 pub const fn builder() -> InventoryBuilder {
340 InventoryBuilder::new()
341 }
342
343 #[must_use]
345 pub fn functions(&self) -> &[Function] {
346 &self.functions
347 }
348
349 #[must_use]
352 pub fn ctypes(&self) -> &[Type] {
353 &self.ctypes
354 }
355
356 #[must_use]
358 pub fn constants(&self) -> &[Constant] {
359 &self.constants
360 }
361
362 #[must_use]
364 pub fn namespaces(&self) -> &[String] {
365 &self.namespaces
366 }
367
368 #[must_use]
371 pub fn patterns(&self) -> &[LibraryPattern] {
372 &self.patterns
373 }
374
375 #[must_use]
396 pub fn filter<P: FnMut(InventoryItem) -> bool>(&self, mut predicate: P) -> Self {
397 let functions: Vec<Function> = self.functions.iter().filter(|x| predicate(InventoryItem::Function(x))).cloned().collect();
398 let ctypes: Vec<Type> = self.ctypes.iter().filter(|x| predicate(InventoryItem::CType(x))).cloned().collect();
399 let constants: Vec<Constant> = self.constants.iter().filter(|x| predicate(InventoryItem::Constant(x))).cloned().collect();
400 let patterns: Vec<LibraryPattern> = self.patterns.iter().filter(|x| predicate(InventoryItem::Pattern(x))).cloned().collect();
401 let namespaces: Vec<String> = self.namespaces.iter().filter(|x| predicate(InventoryItem::Namespace(x))).cloned().collect();
402
403 Self { functions, ctypes, constants, patterns, namespaces }
404 }
405}
406
407pub trait Bindings {
411 fn write_to(&self, w: &mut IndentWriter) -> Result<(), Error>;
416
417 fn write_file<P: AsRef<Path>>(&self, file_name: P) -> Result<(), Error> {
422 let mut file = File::create(file_name)?;
423 let mut writer = IndentWriter::new(&mut file);
424
425 self.write_to(&mut writer)
426 }
427
428 fn to_string(&self) -> Result<String, Error> {
433 let mut vec = Vec::new();
434 let mut writer = IndentWriter::new(&mut vec);
435 self.write_to(&mut writer)?;
436 Ok(String::from_utf8(vec)?)
437 }
438}
439
440fn validate_symbol_names(functions: &[Function], ctypes: &[Type]) {
441 for func in functions {
443 let name = func.name().to_lowercase();
444 assert!(!FORBIDDEN_NAMES.contains(&name.as_str()), "Function `{name}` has a forbidden name that might cause issues in other languages.");
445
446 for param in func.signature().params() {
447 let param_name = param.name().to_lowercase();
448 assert!(
449 !FORBIDDEN_NAMES.contains(¶m_name.as_str()),
450 "Parameter `{param_name}` in function `{name}` has a forbidden name that might cause issues in other languages."
451 );
452 }
453 }
454
455 for ctype in ctypes {
457 match ctype {
458 Type::Composite(composite) => {
459 let type_name = composite.rust_name();
460 assert!(!FORBIDDEN_NAMES.contains(&type_name), "Type `{type_name}` has a forbidden name that might cause issues in other languages.");
461 for field in composite.fields() {
462 let field_name = field.name();
463 assert!(
464 !FORBIDDEN_NAMES.contains(&field_name),
465 "Field `{field_name}` in type `{type_name}` has a forbidden name that might cause issues in other languages."
466 );
467 }
468 }
469 Type::Enum(enum_type) => {
470 let type_name = enum_type.rust_name();
471 assert!(!FORBIDDEN_NAMES.contains(&type_name), "Enum `{type_name}` has a forbidden name that might cause issues in other languages.");
473 for variant in enum_type.variants() {
474 let variant_name = variant.name();
475 assert!(
476 !FORBIDDEN_NAMES.contains(&variant_name),
477 "Variant `{variant_name}` in enum `{type_name}` has a forbidden name that might cause issues in other languages."
478 );
479 }
480 }
481 Type::Opaque(opaque) => {
482 let type_name = opaque.rust_name();
483 assert!(!FORBIDDEN_NAMES.contains(&type_name), "Opaque type `{type_name}` has a forbidden name that might cause issues in other languages.");
484 }
485 _ => {}
486 }
487 }
488}