| /* 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 => {} |
| } |
| } |
| } |