diff options
Diffstat (limited to 'src/bindgen/ir/item.rs')
-rw-r--r-- | src/bindgen/ir/item.rs | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs new file mode 100644 index 0000000..16d98f5 --- /dev/null +++ b/src/bindgen/ir/item.rs @@ -0,0 +1,250 @@ +/* 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 indexmap::IndexMap; +use std::mem; + +use crate::bindgen::config::Config; +use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; +use crate::bindgen::dependencies::Dependencies; +use crate::bindgen::ir::{ + AnnotationSet, Cfg, Constant, Enum, GenericArgument, OpaqueItem, Path, Static, Struct, Typedef, + Union, +}; +use crate::bindgen::library::Library; +use crate::bindgen::monomorph::Monomorphs; + +/// An item is any type of rust item besides a function +pub trait Item { + fn path(&self) -> &Path; + fn name(&self) -> &str { + self.path().name() + } + fn export_name(&self) -> &str { + self.name() + } + fn cfg(&self) -> Option<&Cfg>; + fn annotations(&self) -> &AnnotationSet; + fn annotations_mut(&mut self) -> &mut AnnotationSet; + + fn container(&self) -> ItemContainer; + + fn collect_declaration_types(&self, _resolver: &mut DeclarationTypeResolver) { + unimplemented!() + } + fn resolve_declaration_types(&mut self, _resolver: &DeclarationTypeResolver) { + unimplemented!() + } + fn rename_for_config(&mut self, _config: &Config) {} + fn add_dependencies(&self, _library: &Library, _out: &mut Dependencies) {} + fn instantiate_monomorph( + &self, + _generics: &[GenericArgument], + _library: &Library, + _out: &mut Monomorphs, + ) { + unreachable!("Cannot instantiate {} as a generic.", self.name()) + } +} + +#[derive(Debug, Clone)] +pub enum ItemContainer { + Constant(Constant), + Static(Static), + OpaqueItem(OpaqueItem), + Struct(Struct), + Union(Union), + Enum(Enum), + Typedef(Typedef), +} + +impl ItemContainer { + pub fn deref(&self) -> &dyn Item { + match *self { + ItemContainer::Constant(ref x) => x, + ItemContainer::Static(ref x) => x, + ItemContainer::OpaqueItem(ref x) => x, + ItemContainer::Struct(ref x) => x, + ItemContainer::Union(ref x) => x, + ItemContainer::Enum(ref x) => x, + ItemContainer::Typedef(ref x) => x, + } + } +} + +#[derive(Debug, Clone)] +pub enum ItemValue<T: Item> { + Cfg(Vec<T>), + Single(T), +} + +#[derive(Debug, Clone)] +pub struct ItemMap<T: Item> { + data: IndexMap<Path, ItemValue<T>>, +} + +impl<T: Item> Default for ItemMap<T> { + fn default() -> ItemMap<T> { + ItemMap { + data: Default::default(), + } + } +} + +impl<T: Item + Clone> ItemMap<T> { + pub fn rebuild(&mut self) { + let old = mem::take(self); + old.for_all_items(|x| { + self.try_insert(x.clone()); + }); + } + + pub fn try_insert(&mut self, item: T) -> bool { + match (item.cfg().is_some(), self.data.get_mut(item.path())) { + (true, Some(&mut ItemValue::Cfg(ref mut items))) => { + items.push(item); + return true; + } + (false, Some(&mut ItemValue::Cfg(_))) => { + return false; + } + (true, Some(&mut ItemValue::Single(_))) => { + return false; + } + (false, Some(&mut ItemValue::Single(_))) => { + return false; + } + _ => {} + } + + let path = item.path().clone(); + if item.cfg().is_some() { + self.data.insert(path, ItemValue::Cfg(vec![item])); + } else { + self.data.insert(path, ItemValue::Single(item)); + } + + true + } + + pub fn extend_with(&mut self, other: &ItemMap<T>) { + other.for_all_items(|x| { + self.try_insert(x.clone()); + }); + } + + pub fn to_vec(&self) -> Vec<T> { + let mut result = Vec::with_capacity(self.data.len()); + for container in self.data.values() { + match *container { + ItemValue::Cfg(ref items) => result.extend_from_slice(items), + ItemValue::Single(ref item) => { + result.push(item.clone()); + } + } + } + result + } + + pub fn get_items(&self, path: &Path) -> Option<Vec<ItemContainer>> { + Some(match *self.data.get(path)? { + ItemValue::Cfg(ref items) => items.iter().map(|x| x.container()).collect(), + ItemValue::Single(ref item) => vec![item.container()], + }) + } + + pub fn filter<F>(&mut self, callback: F) + where + F: Fn(&T) -> bool, + { + let data = mem::take(&mut self.data); + + for (name, container) in data { + match container { + ItemValue::Cfg(items) => { + let mut new_items = Vec::new(); + for item in items { + if !callback(&item) { + new_items.push(item); + } + } + if !new_items.is_empty() { + self.data.insert(name, ItemValue::Cfg(new_items)); + } + } + ItemValue::Single(item) => { + if !callback(&item) { + self.data.insert(name, ItemValue::Single(item)); + } + } + } + } + } + + pub fn for_all_items<F>(&self, mut callback: F) + where + F: FnMut(&T), + { + for container in self.data.values() { + match *container { + ItemValue::Cfg(ref items) => { + for item in items { + callback(item); + } + } + ItemValue::Single(ref item) => callback(item), + } + } + } + + pub fn for_all_items_mut<F>(&mut self, mut callback: F) + where + F: FnMut(&mut T), + { + for container in self.data.values_mut() { + match *container { + ItemValue::Cfg(ref mut items) => { + for item in items { + callback(item); + } + } + ItemValue::Single(ref mut item) => callback(item), + } + } + } + + pub fn for_items<F>(&self, path: &Path, mut callback: F) + where + F: FnMut(&T), + { + match self.data.get(path) { + Some(ItemValue::Cfg(items)) => { + for item in items { + callback(item); + } + } + Some(ItemValue::Single(item)) => { + callback(item); + } + None => {} + } + } + + pub fn for_items_mut<F>(&mut self, path: &Path, mut callback: F) + where + F: FnMut(&mut T), + { + match self.data.get_mut(path) { + Some(&mut ItemValue::Cfg(ref mut items)) => { + for item in items { + callback(item); + } + } + Some(&mut ItemValue::Single(ref mut item)) => { + callback(item); + } + None => {} + } + } +} |