blob: 16d98f55d896a4e39dc33717877f3e628e743233 [file] [log] [blame]
/* 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 => {}
}
}
}