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}; ...@@ -10,7 +10,7 @@ use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies; use bindgen::dependencies::Dependencies;
use bindgen::library::Library; use bindgen::library::Library;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, GenericPath, Item, 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::rename::{IdentifierType, RenameRule};
use bindgen::utilities::find_first_some; use bindgen::utilities::find_first_some;
use bindgen::writer::{Source, SourceWriter}; use bindgen::writer::{Source, SourceWriter};
...@@ -132,20 +132,8 @@ impl Enum { ...@@ -132,20 +132,8 @@ impl Enum {
attrs: &Vec<syn::Attribute>, attrs: &Vec<syn::Attribute>,
mod_cfg: &Option<Cfg>, mod_cfg: &Option<Cfg>,
) -> Result<Enum, String> { ) -> 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); 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()); return Err("Enum not marked with a valid repr(prim) or repr(C).".to_owned());
} }
...@@ -153,7 +141,7 @@ impl Enum { ...@@ -153,7 +141,7 @@ impl Enum {
let mut is_tagged = false; let mut is_tagged = false;
for variant in values { 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(); is_tagged = is_tagged || variant.body.is_some();
variants.push(variant); variants.push(variant);
} }
...@@ -214,7 +202,7 @@ impl Item for Enum { ...@@ -214,7 +202,7 @@ impl Item for Enum {
if config.language == Language::C && self.tag.is_some() { if config.language == Language::C && self.tag.is_some() {
// it makes sense to always prefix Tag with type name in C // it makes sense to always prefix Tag with type name in C
let new_tag = format!("{}_Tag", self.name); let new_tag = format!("{}_Tag", self.name);
if self.repr != Repr::C { if self.repr.style == ReprStyle::Rust {
for variant in &mut self.variants { for variant in &mut self.variants {
if let Some((_, ref mut body)) = variant.body { if let Some((_, ref mut body)) = variant.body {
body.fields[0].1 = Type::Path(GenericPath { body.fields[0].1 = Type::Path(GenericPath {
...@@ -281,27 +269,26 @@ impl Item for Enum { ...@@ -281,27 +269,26 @@ impl Item for Enum {
impl Source for Enum { impl Source for Enum {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
let size = match self.repr { let size = self.repr.ty.map(|ty| match ty {
Repr::C => None, ReprType::USize => "uintptr_t",
Repr::USize => Some("uintptr_t"), ReprType::U32 => "uint32_t",
Repr::U32 => Some("uint32_t"), ReprType::U16 => "uint16_t",
Repr::U16 => Some("uint16_t"), ReprType::U8 => "uint8_t",
Repr::U8 => Some("uint8_t"), ReprType::ISize => "intptr_t",
Repr::ISize => Some("intptr_t"), ReprType::I32 => "int32_t",
Repr::I32 => Some("int32_t"), ReprType::I16 => "int16_t",
Repr::I16 => Some("int16_t"), ReprType::I8 => "int8_t",
Repr::I8 => Some("int8_t"), });
_ => unreachable!(),
};
self.cfg.write_before(config, out); self.cfg.write_before(config, out);
self.documentation.write(config, out); self.documentation.write(config, out);
let is_tagged = self.tag.is_some(); let is_tagged = self.tag.is_some();
let separate_tag = self.repr.style == ReprStyle::C;
if is_tagged && config.language == Language::Cxx { 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); write!(out, "{}", self.name);
out.open_brace(); out.open_brace();
} }
...@@ -373,7 +360,7 @@ impl Source for Enum { ...@@ -373,7 +360,7 @@ impl Source for Enum {
write!(out, "{} tag;", enum_name); write!(out, "{} tag;", enum_name);
out.new_line(); out.new_line();
if size.is_none() { if separate_tag {
out.write("union"); out.write("union");
out.open_brace(); out.open_brace();
} }
...@@ -389,7 +376,7 @@ impl Source for Enum { ...@@ -389,7 +376,7 @@ impl Source for Enum {
write!(out, "{} {};", body.name, field_name); write!(out, "{} {};", body.name, field_name);
} }
if size.is_none() { if separate_tag {
out.close_brace(true); out.close_brace(true);
} }
......
...@@ -5,9 +5,19 @@ ...@@ -5,9 +5,19 @@
use syn; use syn;
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub enum Repr { pub enum ReprStyle {
None, Rust,
C, C,
}
impl Default for ReprStyle {
fn default() -> Self {
ReprStyle::Rust
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ReprType {
U8, U8,
U16, U16,
U32, U32,
...@@ -18,113 +28,57 @@ pub enum Repr { ...@@ -18,113 +28,57 @@ pub enum Repr {
ISize, ISize,
} }
impl Repr { #[derive(Debug, Copy, Clone, PartialEq, Default)]
pub fn load(attrs: &Vec<syn::Attribute>) -> Repr { pub struct Repr {
if Repr::has_attr(Repr::repr_c(), attrs) { pub style: ReprStyle,
Repr::C pub ty: Option<ReprType>,
} 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"))),
],
)
}
fn repr_isize() -> syn::MetaItem { impl Repr {
syn::MetaItem::List( pub const C: Self = Repr {
syn::Ident::new("repr"), style: ReprStyle::C,
vec![ ty: None,
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("isize"))), };
],
)
}
fn repr_i32() -> syn::MetaItem { pub const RUST: Self = Repr {
syn::MetaItem::List( style: ReprStyle::Rust,
syn::Ident::new("repr"), ty: None,
vec![
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("i32"))),
],
)
}
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 { pub fn load(attrs: &[syn::Attribute]) -> Repr {
syn::MetaItem::List( attrs
syn::Ident::new("repr"), .iter()
vec![ .filter_map(|attr| match *attr {
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(syn::Ident::new("i8"))), 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 { ...@@ -91,4 +91,28 @@ typedef union {
}; };
} G; } 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 { ...@@ -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" { 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" } // extern "C"
...@@ -58,6 +58,14 @@ enum G { ...@@ -58,6 +58,14 @@ enum G {
Baz Baz
} }
/// cbindgen:prefix-with-name
#[repr(C, u8)]
enum H {
Foo(i16),
Bar { x: u8, y: i16 },
Baz
}
#[no_mangle] #[no_mangle]
pub extern "C" fn root( pub extern "C" fn root(
o: *mut Opaque, o: *mut Opaque,
...@@ -67,5 +75,6 @@ pub extern "C" fn root( ...@@ -67,5 +75,6 @@ pub extern "C" fn root(
d: D, d: D,
e: E, e: E,
f: F, 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