Commit a8313fbc authored by Ryan Hunt's avatar Ryan Hunt
Browse files

Refactor Item for more precise multiple item with #[Cfg] semantics

Fixes #52.
parent a964ef08
......@@ -8,20 +8,20 @@ use std::path;
use std::fs;
use bindgen::config::{Config, Language};
use bindgen::ir::{Item, Function};
use bindgen::ir::{ItemContainer, Function};
use bindgen::monomorph::TemplateSpecialization;
use bindgen::writer::{ListType, Source, SourceWriter};
pub struct Bindings {
config: Config,
items: Vec<Item>,
items: Vec<ItemContainer>,
functions: Vec<Function>,
template_specializations: Vec<TemplateSpecialization>,
}
impl Bindings {
pub fn new(config: Config,
items: Vec<Item>,
items: Vec<ItemContainer>,
functions: Vec<Function>,
template_specializations: Vec<TemplateSpecialization>) -> Bindings {
Bindings {
......@@ -92,11 +92,11 @@ impl Bindings {
for item in &self.items {
out.new_line_if_not_start();
match item {
&Item::Enum(ref x) => x.write(&self.config, &mut out),
&Item::Struct(ref x) => x.write(&self.config, &mut out),
&Item::OpaqueItem(ref x) => x.write(&self.config, &mut out),
&Item::Typedef(ref x) => x.write(&self.config, &mut out),
&Item::Specialization(_) => {
&ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
&ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
&ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
&ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
&ItemContainer::Specialization(_) => {
unreachable!("should not encounter a specialization in a generated library")
}
}
......
......@@ -2,7 +2,6 @@
* 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::BTreeMap;
use std::mem;
use std::path;
......@@ -11,7 +10,7 @@ use syn;
use bindgen::cargo::Cargo;
use bindgen::config::Config;
use bindgen::ir::{AnnotationSet, Cfg, Documentation, Enum, Function};
use bindgen::ir::{OpaqueItem, Specialization, Struct, Typedef};
use bindgen::ir::{ItemMap, OpaqueItem, Specialization, Struct, Typedef};
use bindgen::library::Library;
use bindgen::rust_lib;
use bindgen::utilities::{SynAbiHelpers, SynItemHelpers};
......@@ -21,11 +20,11 @@ pub struct LibraryBuilder {
config: Config,
srcs: Vec<path::PathBuf>,
lib: Option<Cargo>,
enums: BTreeMap<String, Vec<Enum>>,
structs: BTreeMap<String, Vec<Struct>>,
opaque_items: BTreeMap<String, OpaqueItem>,
typedefs: BTreeMap<String, Typedef>,
specializations: BTreeMap<String, Specialization>,
enums: ItemMap<Enum>,
structs: ItemMap<Struct>,
opaque_items: ItemMap<OpaqueItem>,
typedefs: ItemMap<Typedef>,
specializations: ItemMap<Specialization>,
functions: Vec<Function>,
}
......@@ -35,11 +34,11 @@ impl LibraryBuilder {
config: Config::default(),
srcs: Vec::new(),
lib: None,
enums: BTreeMap::new(),
structs: BTreeMap::new(),
opaque_items: BTreeMap::new(),
typedefs: BTreeMap::new(),
specializations: BTreeMap::new(),
enums: ItemMap::new(),
structs: ItemMap::new(),
opaque_items: ItemMap::new(),
typedefs: ItemMap::new(),
specializations: ItemMap::new(),
functions: Vec::new(),
}
}
......@@ -52,7 +51,7 @@ impl LibraryBuilder {
pub fn with_std_types(mut self) -> LibraryBuilder {
{
let mut add_opaque = |name: &str, generic_params: Vec<&str>| {
self.opaque_items.insert(name.to_owned(), OpaqueItem {
self.opaque_items.try_insert(OpaqueItem {
name: name.to_owned(),
generic_params: generic_params.iter()
.map(|x| (*x).to_owned())
......@@ -277,26 +276,17 @@ impl LibraryBuilder {
Ok(st) => {
info!("take {}::{}", crate_name, &item.ident);
if !self.structs.contains_key(&struct_name) {
self.structs.insert(struct_name.clone(),
Vec::new());
}
let structs = self.structs.get_mut(&struct_name).unwrap();
if structs.len() == 0 ||
st.cfg.is_some() {
structs.push(st);
}
self.structs.try_insert(st);
}
Err(msg) => {
info!("take {}::{} - opaque ({})",
crate_name,
&item.ident,
msg);
self.opaque_items.insert(struct_name.clone(),
OpaqueItem::new(struct_name,
generics,
&item.attrs,
mod_cfg));
self.opaque_items.try_insert(OpaqueItem::new(struct_name,
generics,
&item.attrs,
mod_cfg));
}
}
}
......@@ -324,23 +314,14 @@ impl LibraryBuilder {
mod_cfg) {
Ok(en) => {
info!("take {}::{}", crate_name, &item.ident);
if !self.enums.contains_key(&enum_name) {
self.enums.insert(enum_name.clone(),
Vec::new());
}
let enums = self.enums.get_mut(&enum_name).unwrap();
if enums.len() == 0 ||
en.cfg.is_some() {
enums.push(en);
}
self.enums.try_insert(en);
}
Err(msg) => {
info!("take {}::{} - opaque ({})", crate_name, &item.ident, msg);
self.opaque_items.insert(enum_name.clone(),
OpaqueItem::new(enum_name,
generics,
&item.attrs,
mod_cfg));
self.opaque_items.try_insert(OpaqueItem::new(enum_name,
generics,
&item.attrs,
mod_cfg));
}
}
}
......@@ -364,7 +345,7 @@ impl LibraryBuilder {
{
Ok(typedef) => {
info!("take {}::{}", crate_name, &item.ident);
self.typedefs.insert(alias_name, typedef);
self.typedefs.try_insert(typedef);
return;
}
Err(msg) => msg,
......@@ -380,7 +361,7 @@ impl LibraryBuilder {
mod_cfg) {
Ok(spec) => {
info!("take {}::{}", crate_name, &item.ident);
self.specializations.insert(alias_name, spec);
self.specializations.try_insert(spec);
return;
}
Err(msg) => msg,
......
......@@ -5,11 +5,11 @@
use std::collections::HashSet;
use std::cmp::Ordering;
use bindgen::ir::{Item, Path};
use bindgen::ir::{ItemContainer, Path};
/// A dependency list is used for gathering what order to output the types.
pub struct Dependencies {
pub order: Vec<Item>,
pub order: Vec<ItemContainer>,
pub items: HashSet<Path>,
}
......@@ -24,15 +24,15 @@ impl Dependencies {
pub fn sort(&mut self) {
// Sort enums and opaque structs into their own layers because they don't
// depend on each other or anything else.
let ordering = |a: &Item, b: &Item| {
let ordering = |a: &ItemContainer, b: &ItemContainer| {
match (a, b) {
(&Item::Enum(ref x), &Item::Enum(ref y)) => x.name.cmp(&y.name),
(&Item::Enum(_), _) => Ordering::Less,
(_, &Item::Enum(_)) => Ordering::Greater,
(&ItemContainer::Enum(ref x), &ItemContainer::Enum(ref y)) => x.name.cmp(&y.name),
(&ItemContainer::Enum(_), _) => Ordering::Less,
(_, &ItemContainer::Enum(_)) => Ordering::Greater,
(&Item::OpaqueItem(ref x), &Item::OpaqueItem(ref y)) => x.name.cmp(&y.name),
(&Item::OpaqueItem(_), _) => Ordering::Less,
(_, &Item::OpaqueItem(_)) => Ordering::Greater,
(&ItemContainer::OpaqueItem(ref x), &ItemContainer::OpaqueItem(ref y)) => x.name.cmp(&y.name),
(&ItemContainer::OpaqueItem(_), _) => Ordering::Less,
(_, &ItemContainer::OpaqueItem(_)) => Ordering::Greater,
_ => Ordering::Equal,
}
......
......@@ -7,7 +7,8 @@ use std::io::Write;
use syn;
use bindgen::config::{Config, Language};
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, Repr};
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, ItemContainer, Item, Repr, Specialization};
use bindgen::library::Library;
use bindgen::rename::{IdentifierType, RenameRule};
use bindgen::utilities::{find_first_some};
use bindgen::writer::{Source, SourceWriter};
......@@ -85,8 +86,41 @@ impl Enum {
documentation: Documentation::load(attrs),
})
}
}
impl Item for Enum {
fn name(&self) -> &str {
&self.name
}
fn cfg(&self) -> &Option<Cfg> {
&self.cfg
}
fn annotations(&self) -> &AnnotationSet {
&self.annotations
}
fn annotations_mut(&mut self) -> &mut AnnotationSet {
&mut self.annotations
}
fn container(&self) -> ItemContainer {
ItemContainer::Enum(self.clone())
}
fn specialize(&self, _: &Library, aliasee: &Specialization) -> Result<Box<Item>, String> {
Ok(Box::new(Enum {
name: aliasee.name.clone(),
repr: self.repr.clone(),
values: self.values.clone(),
cfg: aliasee.cfg.clone(),
annotations: aliasee.annotations.clone(),
documentation: aliasee.documentation.clone(),
}))
}
pub fn rename_values(&mut self, config: &Config) {
fn rename_for_config(&mut self, config: &Config) {
if config.enumeration.prefix_with_name ||
self.annotations.bool("prefix-with-name").unwrap_or(false)
{
......
......@@ -70,7 +70,7 @@ impl Function {
}
}
pub fn rename_args(&mut self, config: &Config) {
pub fn rename_for_config(&mut self, config: &Config) {
let rules = [self.annotations.parse_atom::<RenameRule>("rename-all"),
config.function.rename_args];
......
......@@ -2,13 +2,33 @@
* 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::BTreeMap;
use std::mem;
use bindgen::config::Config;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{Enum, OpaqueItem, Specialization, Struct, Typedef};
use bindgen::ir::{AnnotationSet, Cfg, Enum, OpaqueItem, Specialization, Struct, Type, Typedef};
use bindgen::library::Library;
use bindgen::monomorph::Monomorphs;
/// An item is any type of rust item besides a function
pub trait Item {
fn name(&self) -> &str;
fn cfg(&self) -> &Option<Cfg>;
fn annotations(&self) -> &AnnotationSet;
fn annotations_mut(&mut self) -> &mut AnnotationSet;
fn container(&self) -> ItemContainer;
fn specialize(&self, library: &Library, aliasee: &Specialization) -> Result<Box<Item>, String>;
fn rename_for_config(&mut self, _config: &Config) { }
fn add_dependencies(&self, _library: &Library, _out: &mut Dependencies) { }
fn instantiate_monomorph(&self, _generics: &Vec<Type>, _library: &Library, _out: &mut Monomorphs) { }
}
#[derive(Debug, Clone)]
pub enum Item {
pub enum ItemContainer {
OpaqueItem(OpaqueItem),
Struct(Struct),
Enum(Enum),
......@@ -16,19 +36,178 @@ pub enum Item {
Specialization(Specialization),
}
impl Item {
pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
impl ItemContainer {
pub fn deref(&self) -> &Item {
match self {
&Item::Struct(ref x) => {
x.add_dependencies(library, out);
},
&Item::Typedef(ref x) => {
x.add_dependencies(library, out);
},
&Item::Specialization(..) => {
unreachable!();
},
&ItemContainer::OpaqueItem(ref x) => x,
&ItemContainer::Struct(ref x) => x,
&ItemContainer::Enum(ref x) => x,
&ItemContainer::Typedef(ref x) => x,
&ItemContainer::Specialization(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: BTreeMap<String, ItemValue<T>>,
}
impl<T: Item> ItemMap<T> {
pub fn new() -> ItemMap<T> {
ItemMap {
data: BTreeMap::new(),
}
}
pub fn clear(&mut self) {
self.data.clear();
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn try_insert(&mut self, item: T) -> bool {
match (item.cfg().is_some(), self.data.get_mut(item.name())) {
(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;
}
_ => { }
}
if item.cfg().is_some() {
self.data.insert(item.name().to_owned(),
ItemValue::Cfg(vec![item]));
} else {
self.data.insert(item.name().to_owned(),
ItemValue::Single(item));
}
true
}
pub fn get_items(&self, name: &str) -> Option<Vec<ItemContainer>> {
match self.data.get(name) {
Some(&ItemValue::Cfg(ref items)) => {
Some(items.iter()
.map(|x| x.container())
.collect())
}
Some(&ItemValue::Single(ref item)) => {
Some(vec![item.container()])
}
None => None,
}
}
pub fn filter<F>(&mut self, callback: F)
where F: Fn(&T) -> bool
{
let data = mem::replace(&mut self.data, BTreeMap::new());
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.len() > 0 {
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 {
&mut ItemValue::Cfg(ref mut items) => {
for item in items {
callback(item);
}
}
&mut ItemValue::Single(ref mut item) => {
callback(item)
}
}
}
}
#[allow(dead_code)]
pub fn for_items<F>(&self, name: &str, mut callback: F)
where F: FnMut(&T)
{
match self.data.get(name) {
Some(&ItemValue::Cfg(ref items)) => {
for item in items {
callback(item);
}
}
Some(&ItemValue::Single(ref item)) => {
callback(item);
}
None => { }
}
}
pub fn for_items_mut<F>(&mut self, name: &str, mut callback: F)
where F: FnMut(&mut T)
{
match self.data.get_mut(name) {
Some(&mut ItemValue::Cfg(ref mut items)) => {
for item in items {
callback(item);
}
}
Some(&mut ItemValue::Single(ref mut item)) => {
callback(item);
}
None => { }
}
}
}
......@@ -7,7 +7,9 @@ use std::io::Write;
use syn;
use bindgen::config::{Config, Language};
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, Path, Type};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, ItemContainer, Item, Path, Specialization, Type};
use bindgen::library::Library;
use bindgen::mangle;
use bindgen::monomorph::Monomorphs;
use bindgen::writer::{Source, SourceWriter};
......@@ -54,6 +56,46 @@ impl OpaqueItem {
}
}
impl Item for OpaqueItem {
fn name(&self) -> &str {
&self.name
}
fn cfg(&self) -> &Option<Cfg> {
&self.cfg
}
fn annotations(&self) -> &AnnotationSet {
&self.annotations
}
fn annotations_mut(&mut self) -> &mut AnnotationSet {
&mut self.annotations
}
fn container(&self) -> ItemContainer {
ItemContainer::OpaqueItem(self.clone())
}
fn specialize(&self, _: &Library, aliasee: &Specialization) -> Result<Box<Item>, String> {
if aliasee.aliased.generics.len() !=
self.generic_params.len() {
return Err(format!("incomplete specialization"));
}
Ok(Box::new(OpaqueItem {
name: aliasee.name.clone(),
generic_params: aliasee.generic_params.clone(),
cfg: aliasee.cfg.clone(),
annotations: aliasee.annotations.clone(),
documentation: aliasee.documentation.clone(),
}))
}
fn add_dependencies(&self, _: &Library, _: &mut Dependencies) {
}
}
impl Source for OpaqueItem {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.cfg.write_before(config, out);
......
......@@ -4,8 +4,9 @@
use syn;
use bindgen::ir::{AnnotationSet, Cfg, Documentation, Enum};
use bindgen::ir::{GenericPath, Item, OpaqueItem, PrimitiveType, Struct, Typedef};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, Documentation};
use bindgen::ir::{GenericPath, ItemContainer, Item, PrimitiveType};
use bindgen::library::Library;
/// A type alias that generates a copy of its aliasee with a new name. If the type
......@@ -55,8 +56,8 @@ impl Specialization {
}
}
pub fn specialize(&self, library: &Library) -> Result<Option<Item>, String> {
if let Some(items) = library.get_item(&self.aliased.name) {
pub fn resolve_specialization(&self, library: &Library) -> Result<Box<Item>, String> {
if let Some(items) = library.get_items(&self.aliased.name) {
assert!(items.len() > 0);
if items.len() > 1 {
......@@ -64,83 +65,20 @@ impl Specialization {
}
match items[0] {
Item::OpaqueItem(ref aliased) => {
if self.aliased.generics.len() !=
aliased.generic_params.len() {
return Err(format!("incomplete specialization"));
}
Ok(Some(Item::OpaqueItem(OpaqueItem {
name: self.name.clone(),
generic_params: self.generic_params.clone(),
cfg: self.cfg.clone(),
annotations: self.annotations.clone(),
documentation: self.documentation.clone(),
})))
ItemContainer::OpaqueItem(ref aliased) => {