Commit 07eae4c1 authored by Ingvar Stepanyan's avatar Ingvar Stepanyan Committed by Ryan Hunt

Implement support for repr(C, Int)

Fixes #119
parent 3053d442
......@@ -10,7 +10,7 @@ use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies;
use bindgen::library::Library;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, GenericPath, Item,
ItemContainer, Repr, Struct, Type};
ItemContainer, Repr, ReprStyle, ReprType, Struct, Type};
use bindgen::rename::{IdentifierType, RenameRule};
use bindgen::utilities::find_first_some;
use bindgen::writer::{Source, SourceWriter};
......@@ -132,20 +132,8 @@ impl Enum {
attrs: &Vec<syn::Attribute>,
mod_cfg: &Option<Cfg>,
) -> Result<Enum, String> {
const VALID_REPR: &[Repr] = &[
Repr::C,
Repr::USize,
Repr::U32,
Repr::U16,
Repr::U8,
Repr::ISize,
Repr::I32,
Repr::I16,
Repr::I8,
];
let repr = Repr::load(attrs);
if !VALID_REPR.contains(&repr) {
if repr == Repr::RUST {
return Err("Enum not marked with a valid repr(prim) or repr(C).".to_owned());
}
......@@ -153,7 +141,7 @@ impl Enum {
let mut is_tagged = false;
for variant in values {
let variant = EnumVariant::load(repr != Repr::C, variant, mod_cfg)?;
let variant = EnumVariant::load(repr.style == ReprStyle::Rust, variant, mod_cfg)?;
is_tagged = is_tagged || variant.body.is_some();
variants.push(variant);
}
......@@ -214,7 +202,7 @@ impl Item for Enum {
if config.language == Language::C && self.tag.is_some() {
// it makes sense to always prefix Tag with type name in C
let new_tag = format!("{}_Tag", self.name);
if self.repr != Repr::C {
if self.repr.style == ReprStyle::Rust {
for variant in &mut self.variants {
if let Some((_, ref mut body)) = variant.body {
body.fields[0].1 = Type::Path(GenericPath {
......@@ -281,27 +269,26 @@ impl Item for Enum {
impl Source for Enum {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
let size = match self.repr {
Repr::C => None,
Repr::USize => Some("uintptr_t"),
Repr::U32 => Some("uint32_t"),
Repr::U16 => Some("uint16_t"),
Repr::U8 => Some("uint8_t"),
Repr::ISize => Some("intptr_t"),
Repr::I32 => Some("int32_t"),
Repr::I16 => Some("int16_t"),
Repr::I8 => Some("int8_t"),
_ => unreachable!(),
};
let size = self.repr.ty.map(|ty| match ty {
ReprType::USize => "uintptr_t",
ReprType::U32 => "uint32_t",
ReprType::U16 => "uint16_t",
ReprType::U8 => "uint8_t",
ReprType::ISize => "intptr_t",
ReprType::I32 => "int32_t",
ReprType::I16 => "int16_t",
ReprType::I8 => "int8_t",
});
self.cfg.write_before(config, out);
self.documentation.write(config, out);
let is_tagged = self.tag.is_some();
let separate_tag = self.repr.style == ReprStyle::C;
if is_tagged && config.language == Language::Cxx {
out.write(if size.is_some() { "union " } else { "struct " });
out.write(if separate_tag { "struct " } else { "union " });
write!(out, "{}", self.name);
out.open_brace();
}
......@@ -373,7 +360,7 @@ impl Source for Enum {
write!(out, "{} tag;", enum_name);
out.new_line();
if size.is_none() {
if separate_tag {
out.write("union");
out.open_brace();
}
......@@ -389,7 +376,7 @@ impl Source for Enum {
write!(out, "{} {};", body.name, field_name);
}
if size.is_none() {
if separate_tag {
out.close_brace(true);
}
......
......@@ -5,9 +5,19 @@
use syn;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Repr {
None,
pub enum ReprStyle {
Rust,
C,
}
impl Default for ReprStyle {
fn default() -> Self {
ReprStyle::Rust
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ReprType {
U8,
U16,
U32,
......@@ -18,113 +28,57 @@ pub enum Repr {
ISize,
}
impl Repr {
pub fn load(attrs: &Vec<syn::Attribute>) -> Repr {
if Repr::has_attr(Repr::repr_c(), attrs) {
Repr::C
} else if Repr::has_attr(Repr::repr_usize(), attrs) {
Repr::USize
} else if Repr::has_attr(Repr::repr_u32(), attrs) {
Repr::U32
} else if Repr::has_attr(Repr::repr_u16(), attrs) {
Repr::U16
} else if Repr::has_attr(Repr::repr_u8(), attrs) {
Repr::U8
} else if Repr::has_attr(Repr::repr_isize(), attrs) {
Repr::ISize
} else if Repr::has_attr(Repr::repr_i32(), attrs) {
Repr::I32
} else if Repr::has_attr(Repr::repr_i16(), attrs) {
Repr::I16
} else if Repr::has_attr(Repr::repr_i8(), attrs) {
Repr::I8
} else {
Repr::None
}
}
fn has_attr(meta: syn::MetaItem, attrs: &Vec<syn::Attribute>) -> bool {
attrs.iter().any(|x| !x.is_sugared_doc && x.value == meta)
}
fn repr_c() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("C"))),
],
)
}
fn repr_usize() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("usize"))),
],
)
}
fn repr_u32() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("u32"))),
],
)
}
fn repr_u16() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("u16"))),
],
)
}
fn repr_u8() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("u8"))),
],
)
}
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Repr {
pub style: ReprStyle,
pub ty: Option<ReprType>,
}
fn repr_isize() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("isize"))),
],
)
}
impl Repr {
pub const C: Self = Repr {
style: ReprStyle::C,
ty: None,
};
fn repr_i32() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("i32"))),
],
)
}
pub const RUST: Self = Repr {
style: ReprStyle::Rust,
ty: None,
fn repr_i16() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("i16"))),
],
)
}
};
fn repr_i8() -> syn::MetaItem {
syn::MetaItem::List(
syn::Ident::new("repr"),
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("i8"))),
],
)
pub fn load(attrs: &[syn::Attribute]) -> Repr {
attrs
.iter()
.filter_map(|attr| match *attr {
syn::Attribute {
style: syn::AttrStyle::Outer,
is_sugared_doc: false,
value: syn::MetaItem::List(ref id, ref nested)
} if id == "repr" => Some(nested),
_ => None,
})
.flat_map(|nested| nested)
.filter_map(|meta| match *meta {
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref id)) => Some(id.as_ref()),
_ => None,
})
.fold(Repr::default(), |mut acc, id| {
if id == "C" {
acc.style = ReprStyle::C;
} else {
acc.ty = Some(match id {
"u8" => ReprType::U8,
"u16" => ReprType::U16,
"u32" => ReprType::U32,
"usize" => ReprType::USize,
"i8" => ReprType::I8,
"i16" => ReprType::I16,
"i32" => ReprType::I32,
"isize" => ReprType::ISize,
_ => return acc
});
}
acc
})
}
}
......@@ -91,4 +91,28 @@ typedef union {
};
} G;
void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g);
enum H_Tag {
H_Foo,
H_Bar,
H_Baz,
};
typedef uint8_t H_Tag;
typedef struct {
int16_t _0;
} H_Foo_Body;
typedef struct {
uint8_t x;
int16_t y;
} H_Bar_Body;
typedef union {
H_Tag tag;
union {
H_Foo_Body foo;
H_Bar_Body bar;
};
} H;
void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h);
......@@ -84,8 +84,31 @@ struct G {
};
};
struct H {
enum class Tag : uint8_t {
H_Foo,
H_Bar,
H_Baz,
};
struct H_Foo_Body {
int16_t _0;
};
struct H_Bar_Body {
uint8_t x;
int16_t y;
};
Tag tag;
union {
H_Foo_Body foo;
H_Bar_Body bar;
};
};
extern "C" {
void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g);
void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h);
} // extern "C"
......@@ -58,6 +58,14 @@ enum G {
Baz
}
/// cbindgen:prefix-with-name
#[repr(C, u8)]
enum H {
Foo(i16),
Bar { x: u8, y: i16 },
Baz
}
#[no_mangle]
pub extern "C" fn root(
o: *mut Opaque,
......@@ -67,5 +75,6 @@ pub extern "C" fn root(
d: D,
e: E,
f: F,
g: G
g: G,
h: H
) { }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment