summaryrefslogtreecommitdiffstats
path: root/src/bindgen/library.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/bindgen/library.rs446
1 files changed, 446 insertions, 0 deletions
diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs
new file mode 100644
index 0000000..cb4cfbd
--- /dev/null
+++ b/src/bindgen/library.rs
@@ -0,0 +1,446 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::collections::HashMap;
+use std::path::PathBuf;
+
+use crate::bindgen::bindings::Bindings;
+use crate::bindgen::config::{Config, Language, SortKey};
+use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
+use crate::bindgen::dependencies::Dependencies;
+use crate::bindgen::error::Error;
+use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap};
+use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union};
+use crate::bindgen::monomorph::Monomorphs;
+use crate::bindgen::ItemType;
+
+#[derive(Debug, Clone)]
+pub struct Library {
+ config: Config,
+ constants: ItemMap<Constant>,
+ globals: ItemMap<Static>,
+ enums: ItemMap<Enum>,
+ structs: ItemMap<Struct>,
+ unions: ItemMap<Union>,
+ opaque_items: ItemMap<OpaqueItem>,
+ typedefs: ItemMap<Typedef>,
+ functions: Vec<Function>,
+ source_files: Vec<PathBuf>,
+}
+
+impl Library {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ config: Config,
+ constants: ItemMap<Constant>,
+ globals: ItemMap<Static>,
+ enums: ItemMap<Enum>,
+ structs: ItemMap<Struct>,
+ unions: ItemMap<Union>,
+ opaque_items: ItemMap<OpaqueItem>,
+ typedefs: ItemMap<Typedef>,
+ functions: Vec<Function>,
+ source_files: Vec<PathBuf>,
+ ) -> Library {
+ Library {
+ config,
+ constants,
+ globals,
+ enums,
+ structs,
+ unions,
+ opaque_items,
+ typedefs,
+ functions,
+ source_files,
+ }
+ }
+
+ pub fn generate(mut self) -> Result<Bindings, Error> {
+ self.transfer_annotations();
+ self.simplify_standard_types();
+
+ match self.config.function.sort_by.unwrap_or(self.config.sort_by) {
+ SortKey::Name => self.functions.sort_by(|x, y| x.path.cmp(&y.path)),
+ SortKey::None => { /* keep input order */ }
+ }
+
+ if self.config.language != Language::Cxx {
+ self.instantiate_monomorphs();
+ }
+ self.remove_excluded();
+ if self.config.language == Language::C {
+ self.resolve_declaration_types();
+ }
+
+ self.rename_items();
+
+ let mut dependencies = Dependencies::new();
+
+ for function in &self.functions {
+ function.add_dependencies(&self, &mut dependencies);
+ }
+ self.globals.for_all_items(|global| {
+ global.add_dependencies(&self, &mut dependencies);
+ });
+ self.constants.for_all_items(|constant| {
+ constant.add_dependencies(&self, &mut dependencies);
+ });
+ for name in &self.config.export.include {
+ let path = Path::new(name.clone());
+ if let Some(items) = self.get_items(&path) {
+ if dependencies.items.insert(path) {
+ for item in &items {
+ item.deref().add_dependencies(&self, &mut dependencies);
+ }
+ for item in items {
+ dependencies.order.push(item);
+ }
+ }
+ }
+ }
+
+ dependencies.sort();
+
+ let items = dependencies.order;
+ let constants = if self.config.export.should_generate(ItemType::Constants) {
+ let mut constants = self.constants.to_vec();
+ match self.config.constant.sort_by.unwrap_or(self.config.sort_by) {
+ SortKey::Name => constants.sort_by(|x, y| x.path.cmp(&y.path)),
+ SortKey::None => { /* keep input order */ }
+ }
+ constants
+ } else {
+ vec![]
+ };
+
+ let globals = if self.config.export.should_generate(ItemType::Globals) {
+ let mut globals = self.globals.to_vec();
+ match self.config.constant.sort_by.unwrap_or(self.config.sort_by) {
+ SortKey::Name => globals.sort_by(|x, y| x.path.cmp(&y.path)),
+ SortKey::None => { /* keep input order */ }
+ }
+ globals
+ } else {
+ vec![]
+ };
+ let functions = if self.config.export.should_generate(ItemType::Functions) {
+ self.functions
+ } else {
+ vec![]
+ };
+
+ Ok(Bindings::new(
+ self.config,
+ self.structs,
+ self.typedefs,
+ constants,
+ globals,
+ items,
+ functions,
+ self.source_files,
+ false,
+ ))
+ }
+
+ pub fn get_items(&self, p: &Path) -> Option<Vec<ItemContainer>> {
+ macro_rules! find {
+ ($field:ident, $kind:ident) => {
+ if self.config.export.should_generate(ItemType::$kind) {
+ if let Some(x) = self.$field.get_items(p) {
+ return Some(x);
+ }
+ }
+ };
+ }
+
+ find!(enums, Enums);
+ find!(structs, Structs);
+ find!(unions, Unions);
+ find!(opaque_items, OpaqueItems);
+ find!(typedefs, Typedefs);
+
+ None
+ }
+
+ pub fn get_config(&self) -> &Config {
+ &self.config
+ }
+
+ fn remove_excluded(&mut self) {
+ let config = &self.config;
+ // FIXME: interpret `config.export.exclude` as `Path`s.
+ self.functions
+ .retain(|x| !config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.enums
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.structs
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.unions
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.opaque_items
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.typedefs
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.globals
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ self.constants
+ .filter(|x| config.export.exclude.iter().any(|y| y == x.path().name()));
+ }
+
+ fn transfer_annotations(&mut self) {
+ let mut annotations = HashMap::new();
+
+ self.typedefs.for_all_items_mut(|x| {
+ x.transfer_annotations(&mut annotations);
+ });
+
+ for (alias_path, annotations) in annotations {
+ // TODO
+ let mut transferred = false;
+
+ self.enums.for_items_mut(&alias_path, |x| {
+ if x.annotations().is_empty() {
+ *x.annotations_mut() = annotations.clone();
+ transferred = true;
+ } else {
+ warn!(
+ "Can't transfer annotations from typedef to alias ({}) \
+ that already has annotations.",
+ alias_path
+ );
+ }
+ });
+ if transferred {
+ continue;
+ }
+ self.structs.for_items_mut(&alias_path, |x| {
+ if x.annotations().is_empty() {
+ *x.annotations_mut() = annotations.clone();
+ transferred = true;
+ } else {
+ warn!(
+ "Can't transfer annotations from typedef to alias ({}) \
+ that already has annotations.",
+ alias_path
+ );
+ }
+ });
+ if transferred {
+ continue;
+ }
+ self.unions.for_items_mut(&alias_path, |x| {
+ if x.annotations().is_empty() {
+ *x.annotations_mut() = annotations.clone();
+ transferred = true;
+ } else {
+ warn!(
+ "Can't transfer annotations from typedef to alias ({}) \
+ that already has annotations.",
+ alias_path
+ );
+ }
+ });
+ if transferred {
+ continue;
+ }
+ self.opaque_items.for_items_mut(&alias_path, |x| {
+ if x.annotations().is_empty() {
+ *x.annotations_mut() = annotations.clone();
+ transferred = true;
+ } else {
+ warn!(
+ "Can't transfer annotations from typedef to alias ({}) \
+ that already has annotations.",
+ alias_path
+ );
+ }
+ });
+ if transferred {
+ continue;
+ }
+ self.typedefs.for_items_mut(&alias_path, |x| {
+ if x.annotations().is_empty() {
+ *x.annotations_mut() = annotations.clone();
+ transferred = true;
+ } else {
+ warn!(
+ "Can't transfer annotations from typedef to alias ({}) \
+ that already has annotations.",
+ alias_path
+ );
+ }
+ });
+ if transferred {
+ continue;
+ }
+ }
+ }
+
+ fn rename_items(&mut self) {
+ let config = &self.config;
+
+ self.globals
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.globals.rebuild();
+
+ self.constants
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.constants.rebuild();
+
+ self.structs
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.structs.rebuild();
+
+ self.unions
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.unions.rebuild();
+
+ self.enums
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.enums.rebuild();
+
+ self.opaque_items
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.opaque_items.rebuild();
+
+ self.typedefs
+ .for_all_items_mut(|x| x.rename_for_config(config));
+ self.typedefs.rebuild();
+
+ for item in &mut self.functions {
+ item.rename_for_config(&self.config);
+ }
+ }
+
+ fn resolve_declaration_types(&mut self) {
+ if !self.config.style.generate_tag() {
+ return;
+ }
+
+ let mut resolver = DeclarationTypeResolver::default();
+
+ self.structs.for_all_items(|x| {
+ x.collect_declaration_types(&mut resolver);
+ });
+
+ self.enums.for_all_items(|x| {
+ x.collect_declaration_types(&mut resolver);
+ });
+
+ self.unions.for_all_items(|x| {
+ x.collect_declaration_types(&mut resolver);
+ });
+
+ self.typedefs.for_all_items(|x| {
+ x.collect_declaration_types(&mut resolver);
+ });
+
+ // NOTE: Intentionally last, so that in case there's an opaque type
+ // which is conflicting with a non-opaque one, the later wins.
+ self.opaque_items.for_all_items(|x| {
+ x.collect_declaration_types(&mut resolver);
+ });
+
+ self.enums
+ .for_all_items_mut(|x| x.resolve_declaration_types(&resolver));
+
+ self.structs
+ .for_all_items_mut(|x| x.resolve_declaration_types(&resolver));
+
+ self.unions
+ .for_all_items_mut(|x| x.resolve_declaration_types(&resolver));
+
+ self.typedefs
+ .for_all_items_mut(|x| x.resolve_declaration_types(&resolver));
+
+ self.globals
+ .for_all_items_mut(|x| x.resolve_declaration_types(&resolver));
+
+ for item in &mut self.functions {
+ item.resolve_declaration_types(&resolver);
+ }
+ }
+
+ fn simplify_standard_types(&mut self) {
+ let config = &self.config;
+
+ self.structs.for_all_items_mut(|x| {
+ x.simplify_standard_types(config);
+ });
+ self.enums.for_all_items_mut(|x| {
+ x.simplify_standard_types(config);
+ });
+ self.unions.for_all_items_mut(|x| {
+ x.simplify_standard_types(config);
+ });
+ self.globals.for_all_items_mut(|x| {
+ x.simplify_standard_types(config);
+ });
+ self.typedefs.for_all_items_mut(|x| {
+ x.simplify_standard_types(config);
+ });
+ for x in &mut self.functions {
+ x.simplify_standard_types(config);
+ }
+ }
+
+ fn instantiate_monomorphs(&mut self) {
+ // Collect a list of monomorphs
+ let mut monomorphs = Monomorphs::default();
+
+ self.structs.for_all_items(|x| {
+ x.add_monomorphs(self, &mut monomorphs);
+ });
+ self.unions.for_all_items(|x| {
+ x.add_monomorphs(self, &mut monomorphs);
+ });
+ self.enums.for_all_items(|x| {
+ x.add_monomorphs(self, &mut monomorphs);
+ });
+ self.typedefs.for_all_items(|x| {
+ x.add_monomorphs(self, &mut monomorphs);
+ });
+ for x in &self.functions {
+ x.add_monomorphs(self, &mut monomorphs);
+ }
+
+ // Insert the monomorphs into self
+ for monomorph in monomorphs.drain_structs() {
+ self.structs.try_insert(monomorph);
+ }
+ for monomorph in monomorphs.drain_unions() {
+ self.unions.try_insert(monomorph);
+ }
+ for monomorph in monomorphs.drain_opaques() {
+ self.opaque_items.try_insert(monomorph);
+ }
+ for monomorph in monomorphs.drain_typedefs() {
+ self.typedefs.try_insert(monomorph);
+ }
+ for monomorph in monomorphs.drain_enums() {
+ self.enums.try_insert(monomorph);
+ }
+
+ // Remove structs and opaque items that are generic
+ self.opaque_items.filter(|x| x.generic_params.len() > 0);
+ self.structs.filter(|x| x.generic_params.len() > 0);
+ self.unions.filter(|x| x.generic_params.len() > 0);
+ self.enums.filter(|x| x.generic_params.len() > 0);
+ self.typedefs.filter(|x| x.generic_params.len() > 0);
+
+ // Mangle the paths that remain
+ self.unions
+ .for_all_items_mut(|x| x.mangle_paths(&monomorphs));
+ self.structs
+ .for_all_items_mut(|x| x.mangle_paths(&monomorphs));
+ self.enums
+ .for_all_items_mut(|x| x.mangle_paths(&monomorphs));
+ self.typedefs
+ .for_all_items_mut(|x| x.mangle_paths(&monomorphs));
+ for x in &mut self.functions {
+ x.mangle_paths(&monomorphs);
+ }
+ }
+}