Rename directive to annotation

This commit is contained in:
Ryan Hunt 2017-05-11 03:57:57 -04:00
parent 23380c3e77
commit b04df026d9
7 changed files with 121 additions and 117 deletions

View File

@ -11,7 +11,7 @@ This project can be used to generate C bindings for Rust code. It is currently b
* Builds bindings for a crate, its mods, its dependent crates, and their mods
* Only the necessary types for exposed functions are given bindings
* Can specify directives for controlling some aspects of binding
* Can specify annotations for controlling some aspects of binding
* Generic structs can be exposed using `type IntFoo = Foo<i32>;`
* Customizable formatting, can be used in C or C++ projects

View File

@ -1,45 +1,49 @@
use std::collections::HashMap;
use std::str::FromStr;
// A system for specifying properties on items. Annotations are
// given through document comments and parsed by this code.
//
// An annotation is in the form cbindgen:PROPERTY=VALUE
// Where PROPERTY depends on the item
// Where VALUE can be
// * list - [Item1, Item2, Item3, ...]
// * atom - Foo
// * bool - true,false
// Examples:
// * cbindgen:field-names=[mHandle, mNamespace]
// * cbindgen:function-postfix=WR_DESTRUCTOR_SAFE
/// A value specified by an annotation.
#[derive(Debug, Clone)]
pub enum DirectiveValue {
pub enum AnnotationValue {
List(Vec<String>),
Atom(Option<String>),
Bool(bool),
}
/// A simple system for specifying properties on items
///
/// a directive is given by cbindgen:PROPERTY=VALUE
/// where PROPERTY depends on the item
/// where VALUE can be
/// * list - [item1, item2, item3]
/// * atom - foo
/// * bool - true,false
/// Examples:
/// * cbindgen:field-names=[mHandle, mNamespace]
/// * cbindgen:function-postfix=WR_DESTRUCTOR_SAFE
/// A set of annotations specified by a document comment.
#[derive(Debug, Clone)]
pub struct DirectiveSet {
directives: HashMap<String, DirectiveValue>
pub struct AnnotationSet {
annotations: HashMap<String, AnnotationValue>
}
impl DirectiveSet {
pub fn new() -> DirectiveSet {
DirectiveSet {
directives: HashMap::new(),
impl AnnotationSet {
pub fn new() -> AnnotationSet {
AnnotationSet {
annotations: HashMap::new(),
}
}
pub fn parse(text: String) -> Result<DirectiveSet, String> {
let mut directives = HashMap::new();
pub fn parse(text: String) -> Result<AnnotationSet, String> {
let mut annotations = HashMap::new();
for line in text.lines().map(|x| x.trim_left_matches("///").trim()) {
if !line.starts_with("cbindgen:") {
continue;
}
let directive = &line[9..];
let parts: Vec<&str> = directive.split("=")
let annotation = &line[9..];
let parts: Vec<&str> = annotation.split("=")
.map(|x| x.trim())
.collect();
@ -50,47 +54,47 @@ impl DirectiveSet {
let name = parts[0];
if parts.len() == 1 {
directives.insert(name.to_string(), DirectiveValue::Bool(true));
annotations.insert(name.to_string(), AnnotationValue::Bool(true));
continue;
}
let value = parts[1];
if let Some(x) = parse_list(value) {
directives.insert(name.to_string(), DirectiveValue::List(x));
annotations.insert(name.to_string(), AnnotationValue::List(x));
continue;
}
if let Ok(x) = value.parse::<bool>() {
directives.insert(name.to_string(), DirectiveValue::Bool(x));
annotations.insert(name.to_string(), AnnotationValue::Bool(x));
continue;
}
directives.insert(name.to_string(), if value.len() == 0 {
DirectiveValue::Atom(None)
annotations.insert(name.to_string(), if value.len() == 0 {
AnnotationValue::Atom(None)
} else {
DirectiveValue::Atom(Some(value.to_string()))
AnnotationValue::Atom(Some(value.to_string()))
});
}
Ok(DirectiveSet {
directives: directives
Ok(AnnotationSet {
annotations: annotations
})
}
pub fn list(&self, name: &str) -> Option<Vec<String>> {
match self.directives.get(name) {
Some(&DirectiveValue::List(ref x)) => Some(x.clone()),
match self.annotations.get(name) {
Some(&AnnotationValue::List(ref x)) => Some(x.clone()),
_ => None,
}
}
pub fn atom(&self, name: &str) -> Option<Option<String>> {
match self.directives.get(name) {
Some(&DirectiveValue::Atom(ref x)) => Some(x.clone()),
match self.annotations.get(name) {
Some(&AnnotationValue::Atom(ref x)) => Some(x.clone()),
_ => None,
}
}
pub fn bool(&self, name: &str) -> Option<bool> {
match self.directives.get(name) {
Some(&DirectiveValue::Bool(ref x)) => Some(*x),
match self.annotations.get(name) {
Some(&AnnotationValue::Bool(ref x)) => Some(*x),
_ => None,
}
}
@ -98,8 +102,8 @@ impl DirectiveSet {
pub fn parse_atom<T>(&self, name: &str) -> Option<T>
where T: Default + FromStr
{
match self.directives.get(name) {
Some(&DirectiveValue::Atom(ref x)) => {
match self.annotations.get(name) {
Some(&AnnotationValue::Atom(ref x)) => {
Some(x.as_ref().map_or(T::default(), |y| { y.parse::<T>().ok().unwrap() }))
}
_ => None,

View File

@ -7,7 +7,7 @@ use std::str::FromStr;
use toml;
pub use bindgen::directive::*;
pub use bindgen::annotation::*;
pub use bindgen::rename::*;
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
@ -246,15 +246,15 @@ impl Config {
}
impl FunctionConfig {
pub fn prefix(&self, directives: &DirectiveSet) -> Option<String> {
if let Some(x) = directives.atom("prefix") {
pub fn prefix(&self, annotations: &AnnotationSet) -> Option<String> {
if let Some(x) = annotations.atom("prefix") {
return x;
}
self.prefix.clone()
}
pub fn postfix(&self, directives: &DirectiveSet) -> Option<String> {
if let Some(x) = directives.atom("postfix") {
pub fn postfix(&self, annotations: &AnnotationSet) -> Option<String> {
if let Some(x) = annotations.atom("postfix") {
return x;
}
self.postfix.clone()
@ -262,38 +262,38 @@ impl FunctionConfig {
}
impl StructConfig {
pub fn derive_eq(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("derive-eq") {
pub fn derive_eq(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-eq") {
return x;
}
self.derive_eq
}
pub fn derive_neq(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("derive-neq") {
pub fn derive_neq(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-neq") {
return x;
}
self.derive_neq
}
pub fn derive_lt(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("derive-lt") {
pub fn derive_lt(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-lt") {
return x;
}
self.derive_lt
}
pub fn derive_lte(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("derive-lte") {
pub fn derive_lte(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-lte") {
return x;
}
self.derive_lte
}
pub fn derive_gt(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("derive-gt") {
pub fn derive_gt(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-gt") {
return x;
}
self.derive_gt
}
pub fn derive_gte(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("derive-gte") {
pub fn derive_gte(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("derive-gte") {
return x;
}
self.derive_gte
@ -301,8 +301,8 @@ impl StructConfig {
}
impl EnumConfig {
pub fn add_sentinel(&self, directives: &DirectiveSet) -> bool {
if let Some(x) = directives.bool("add-sentinel") {
pub fn add_sentinel(&self, annotations: &AnnotationSet) -> bool {
if let Some(x) = annotations.bool("add-sentinel") {
return x;
}
self.add_sentinel

View File

@ -5,7 +5,7 @@ use syn::*;
use bindgen::cdecl;
use bindgen::config::{Config, Language, Layout};
use bindgen::directive::*;
use bindgen::annotation::*;
use bindgen::library::*;
use bindgen::rename::*;
use bindgen::syn_helpers::*;
@ -273,7 +273,7 @@ impl Type {
#[derive(Debug, Clone)]
pub struct Function {
pub name: String,
pub directives: DirectiveSet,
pub annotations: AnnotationSet,
pub ret: Option<Type>,
pub args: Vec<(String, Type)>,
pub extern_decl: bool,
@ -281,7 +281,7 @@ pub struct Function {
impl Function {
pub fn convert(name: String,
directives: DirectiveSet,
annotations: AnnotationSet,
decl: &FnDecl,
extern_decl: bool) -> ConvertResult<Function>
{
@ -291,7 +291,7 @@ impl Function {
Ok(Function {
name: name,
directives: directives,
annotations: annotations,
ret: ret,
args: args,
extern_decl: extern_decl,
@ -299,7 +299,7 @@ impl Function {
}
pub fn resolve(&mut self, config: &Config) {
let rules = [self.directives.parse_atom::<RenameRule>("rename-all"),
let rules = [self.annotations.parse_atom::<RenameRule>("rename-all"),
config.function.rename_args];
// TODO, cleanup
@ -338,14 +338,14 @@ impl Function {
// ... )
// POSTFIX ;
let prefix = config.function.prefix(&self.directives);
let prefix = config.function.prefix(&self.annotations);
let ret = match self.ret.as_ref() {
Some(ret) => ret.to_string(),
None => format!("void"),
};
let name = &self.name;
let args = self.args.iter().map(|x| x.1.to_string_with_ident(&x.0)).collect::<Vec<_>>();
let postfix = config.function.postfix(&self.directives);
let postfix = config.function.postfix(&self.annotations);
let option_1: usize = prefix.as_ref().map_or(0, |x| x.len()) +
ret.len() +
@ -419,14 +419,14 @@ impl Function {
#[derive(Debug, Clone)]
pub struct Struct {
pub name: String,
pub directives: DirectiveSet,
pub annotations: AnnotationSet,
pub fields: Vec<(String, Type)>,
pub generic_params: Vec<PathRef>,
}
impl Struct {
pub fn convert(name: String,
directives: DirectiveSet,
annotations: AnnotationSet,
decl: &VariantData,
generics: &Generics) -> ConvertResult<Struct>
{
@ -456,14 +456,14 @@ impl Struct {
Ok(Struct {
name: name,
directives: directives,
annotations: annotations,
fields: fields,
generic_params: generic_params,
})
}
pub fn resolve(&mut self, config: &Config) {
let rules = [self.directives.parse_atom::<RenameRule>("rename-all"),
let rules = [self.annotations.parse_atom::<RenameRule>("rename-all"),
config.structure.rename_fields];
// TODO, cleanup
@ -473,7 +473,7 @@ impl Struct {
rules[1]
};
if let Some(o) = self.directives.list("field-names") {
if let Some(o) = self.annotations.list("field-names") {
let mut overriden_fields = Vec::new();
for (i, &(ref name, ref ty)) in self.fields.iter().enumerate() {
@ -546,27 +546,27 @@ impl Struct {
out.close_brace(false);
};
if config.structure.derive_eq(&self.directives) &&
if config.structure.derive_eq(&self.annotations) &&
!self.fields.is_empty() && self.fields.iter().all(|x| x.1.can_cmp_eq()) {
emit_op("==", "&&");
}
if config.structure.derive_neq(&self.directives) &&
if config.structure.derive_neq(&self.annotations) &&
!self.fields.is_empty() && self.fields.iter().all(|x| x.1.can_cmp_eq()) {
emit_op("!=", "||");
}
if config.structure.derive_lt(&self.directives) &&
if config.structure.derive_lt(&self.annotations) &&
self.fields.len() == 1 && self.fields[0].1.can_cmp_order() {
emit_op("<", "&&");
}
if config.structure.derive_lte(&self.directives) &&
if config.structure.derive_lte(&self.annotations) &&
self.fields.len() == 1 && self.fields[0].1.can_cmp_order() {
emit_op("<=", "&&");
}
if config.structure.derive_gt(&self.directives) &&
if config.structure.derive_gt(&self.annotations) &&
self.fields.len() == 1 && self.fields[0].1.can_cmp_order() {
emit_op(">", "&&");
}
if config.structure.derive_gte(&self.directives) &&
if config.structure.derive_gte(&self.annotations) &&
self.fields.len() == 1 && self.fields[0].1.can_cmp_order() {
emit_op(">=", "&&");
}
@ -584,15 +584,15 @@ impl Struct {
#[derive(Debug, Clone)]
pub struct OpaqueStruct {
pub name: PathRef,
pub directives: DirectiveSet,
pub annotations: AnnotationSet,
}
impl OpaqueStruct {
pub fn new(name: String, directives: DirectiveSet) -> OpaqueStruct
pub fn new(name: String, annotations: AnnotationSet) -> OpaqueStruct
{
OpaqueStruct {
name: name,
directives: directives,
annotations: annotations,
}
}
@ -611,14 +611,14 @@ impl OpaqueStruct {
pub struct Enum {
pub name: String,
pub repr: Repr,
pub directives: DirectiveSet,
pub annotations: AnnotationSet,
pub values: Vec<(String, u64)>,
}
impl Enum {
pub fn convert(name: String,
repr: Repr,
directives: DirectiveSet,
annotations: AnnotationSet,
variants: &Vec<Variant>) -> ConvertResult<Enum>
{
if repr != Repr::U32 &&
@ -656,7 +656,7 @@ impl Enum {
}
}
if let Some(variants) = directives.list("enum-trailing-values") {
if let Some(variants) = annotations.list("enum-trailing-values") {
for variant in variants {
values.push((variant, current));
current = current + 1;
@ -666,13 +666,13 @@ impl Enum {
Ok(Enum {
name: name,
repr: repr,
directives: directives,
annotations: annotations,
values: values,
})
}
pub fn resolve(&mut self, config: &Config) {
let rules = [self.directives.parse_atom::<RenameRule>("rename-all"),
let rules = [self.annotations.parse_atom::<RenameRule>("rename-all"),
config.enumeration.rename_variants];
// TODO, cleanup
@ -711,7 +711,7 @@ impl Enum {
}
out.write(&format!("{} = {},", value.0, value.1));
}
if config.enumeration.add_sentinel(&self.directives) {
if config.enumeration.add_sentinel(&self.annotations) {
out.new_line();
out.new_line();
out.write("Sentinel /* this must be last for serialization purposes. */");
@ -728,14 +728,14 @@ impl Enum {
#[derive(Debug, Clone)]
pub struct Specialization {
pub name: String,
pub directives: DirectiveSet,
pub annotations: AnnotationSet,
pub aliased: PathRef,
pub generic_values: Vec<Type>,
}
impl Specialization {
pub fn convert(name: String,
directives: DirectiveSet,
annotations: AnnotationSet,
ty: &Ty) -> ConvertResult<Specialization>
{
match ty {
@ -748,7 +748,7 @@ impl Specialization {
Ok(Specialization {
name: name,
directives: directives,
annotations: annotations,
aliased: path,
generic_values: generics,
})
@ -773,7 +773,7 @@ impl Specialization {
PathValue::OpaqueStruct(_) => {
Ok(PathValue::OpaqueStruct(OpaqueStruct {
name: self.name.clone(),
directives: self.directives.clone(),
annotations: self.annotations.clone(),
}))
}
PathValue::Struct(aliased) => {
@ -788,7 +788,7 @@ impl Specialization {
Ok(PathValue::Struct(Struct {
name: self.name.clone(),
directives: self.directives.clone(),
annotations: self.annotations.clone(),
fields: aliased.fields.iter()
.map(|x| (x.0.clone(), x.1.specialize(&mappings)))
.collect(),
@ -799,21 +799,21 @@ impl Specialization {
Ok(PathValue::Enum(Enum {
name: self.name.clone(),
repr: aliased.repr.clone(),
directives: self.directives.clone(),
annotations: self.annotations.clone(),
values: aliased.values.clone(),
}))
}
PathValue::Typedef(aliased) => {
Ok(PathValue::Typedef(Typedef {
name: self.name.clone(),
directives: self.directives.clone(),
annotations: self.annotations.clone(),
aliased: aliased.aliased.clone(),
}))
}
PathValue::Specialization(aliased) => {
Specialization {
name: self.name.clone(),
directives: self.directives.clone(),
annotations: self.annotations.clone(),
aliased: aliased.aliased.clone(),
generic_values: aliased.generic_values.clone(),
}.specialize(config, library)
@ -830,17 +830,17 @@ impl Specialization {
#[derive(Debug, Clone)]
pub struct Typedef {
pub name: String,
pub directives: DirectiveSet,
pub annotations: AnnotationSet,
pub aliased: Type,
}
impl Typedef {
pub fn convert(name: String,
directives: DirectiveSet,
annotations: AnnotationSet,
ty: &Ty) -> ConvertResult<Typedef> {
Ok(Typedef {
name: name,
directives: directives,
annotations: annotations,
aliased: try!(Type::convert(ty)),
})
}

View File

@ -7,7 +7,7 @@ use syn::*;
use bindgen::config;
use bindgen::config::{Config, Language};
use bindgen::directive::*;
use bindgen::annotation::*;
use bindgen::items::*;
use bindgen::rust_lib;
use bindgen::syn_helpers::*;
@ -110,15 +110,15 @@ impl<'a> Library<'a> {
match foreign_item.node {
ForeignItemKind::Fn(ref decl,
ref _generic) => {
let directives = match DirectiveSet::parse(foreign_item.get_doc_attr()) {
let annotations = match AnnotationSet::parse(foreign_item.get_doc_attr()) {
Ok(x) => x,
Err(msg) => {
warn!("{}", msg);
DirectiveSet::new()
AnnotationSet::new()
}
};
match Function::convert(foreign_item.ident.to_string(), directives, decl, true) {
match Function::convert(foreign_item.ident.to_string(), annotations, decl, true) {
Ok(func) => {
info!("take {}::{}", mod_name, &foreign_item.ident);
@ -140,15 +140,15 @@ impl<'a> Library<'a> {
ref _generic,
ref _block) => {
if item.is_no_mangle() && abi.is_c() {
let directives = match DirectiveSet::parse(item.get_doc_attr()) {
let annotations = match AnnotationSet::parse(item.get_doc_attr()) {
Ok(x) => x,
Err(msg) => {
warn!("{}", msg);
DirectiveSet::new()
AnnotationSet::new()
}
};
match Function::convert(item.ident.to_string(), directives, decl, false) {
match Function::convert(item.ident.to_string(), annotations, decl, false) {
Ok(func) => {
info!("take {}::{}", mod_name, &item.ident);
@ -163,16 +163,16 @@ impl<'a> Library<'a> {
ItemKind::Struct(ref variant,
ref generics) => {
let struct_name = item.ident.to_string();
let directives = match DirectiveSet::parse(item.get_doc_attr()) {
let annotations = match AnnotationSet::parse(item.get_doc_attr()) {
Ok(x) => x,
Err(msg) => {
warn!("{}", msg);
DirectiveSet::new()
AnnotationSet::new()
}
};
if item.is_repr_c() {
match Struct::convert(struct_name.clone(), directives.clone(), variant, generics) {
match Struct::convert(struct_name.clone(), annotations.clone(), variant, generics) {
Ok(st) => {
info!("take {}::{}", mod_name, &item.ident);
library.structs.insert(struct_name,
@ -181,13 +181,13 @@ impl<'a> Library<'a> {
Err(msg) => {
info!("take {}::{} - opaque ({})", mod_name, &item.ident, msg);
library.opaque_structs.insert(struct_name.clone(),
OpaqueStruct::new(struct_name, directives));
OpaqueStruct::new(struct_name, annotations));
}
}
} else {
info!("take {}::{} - opaque (not marked as repr(C))", mod_name, &item.ident);
library.opaque_structs.insert(struct_name.clone(),
OpaqueStruct::new(struct_name, directives));
OpaqueStruct::new(struct_name, annotations));
}
}
ItemKind::Enum(ref variants, ref generics) => {
@ -199,15 +199,15 @@ impl<'a> Library<'a> {
}
let enum_name = item.ident.to_string();
let directives = match DirectiveSet::parse(item.get_doc_attr()) {
let annotations = match AnnotationSet::parse(item.get_doc_attr()) {
Ok(x) => x,
Err(msg) => {
warn!("{}", msg);
DirectiveSet::new()
AnnotationSet::new()
}
};
match Enum::convert(enum_name.clone(), item.get_repr(), directives.clone(), variants) {
match Enum::convert(enum_name.clone(), item.get_repr(), annotations.clone(), variants) {
Ok(en) => {
info!("take {}::{}", mod_name, &item.ident);
library.enums.insert(enum_name, en);
@ -215,7 +215,7 @@ impl<'a> Library<'a> {
Err(msg) => {
info!("take {}::{} - opaque ({})", mod_name, &item.ident, msg);
library.opaque_structs.insert(enum_name.clone(),
OpaqueStruct::new(enum_name, directives));
OpaqueStruct::new(enum_name, annotations));
}
}
}
@ -228,15 +228,15 @@ impl<'a> Library<'a> {
}
let alias_name = item.ident.to_string();
let directives = match DirectiveSet::parse(item.get_doc_attr()) {
let annotations = match AnnotationSet::parse(item.get_doc_attr()) {
Ok(x) => x,
Err(msg) => {
warn!("{}", msg);
DirectiveSet::new()
AnnotationSet::new()
}
};
let fail1 = match Specialization::convert(alias_name.clone(), directives.clone(), ty) {
let fail1 = match Specialization::convert(alias_name.clone(), annotations.clone(), ty) {
Ok(spec) => {
info!("take {}::{}", mod_name, &item.ident);
library.specializations.insert(alias_name, spec);
@ -244,7 +244,7 @@ impl<'a> Library<'a> {
}
Err(msg) => msg,
};
let fail2 = match Typedef::convert(alias_name.clone(), directives, ty) {
let fail2 = match Typedef::convert(alias_name.clone(), annotations, ty) {
Ok(typedef) => {
info!("take {}::{}", mod_name, &item.ident);
library.typedefs.insert(alias_name, typedef);

View File

@ -29,7 +29,7 @@ macro_rules! deserialize_enum_str {
mod cdecl;
mod config;
mod directive;
mod annotation;
mod items;
mod library;
mod rename;