Skip to content

Commit

Permalink
Unions: Remove feature-gate for stable rustc
Browse files Browse the repository at this point in the history
Unions: derive Copy/Clone for struct within unions
  • Loading branch information
Luke Jones committed Jul 22, 2017
1 parent 5c71144 commit e9a7910
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 143 deletions.
4 changes: 0 additions & 4 deletions Cargo.toml
Expand Up @@ -29,7 +29,3 @@ git2 = { version = "0.6", default-features = false }

[profile.release]
codegen-units = 4

[features]
default = []
use_unions = []
4 changes: 1 addition & 3 deletions README.md
Expand Up @@ -279,11 +279,9 @@ It'll generate a `docs.md` if everything went fine. That's where all this crate'

And now your crate should be completely documented as expected!

## Nightly Rust Only Features

### Unions

By default union generation is disabled except for some special cases due to unions not yet being a stable feature. However if you are using *nightly* rust, then you can enable union generation using `cargo run --release --features "use_unions"`.
`gir` now has the ability to generate c-like unions using newly stabilised `union` in rustc 1.19. As such this means `gir` requires a minimum version rustc of 1.19

Keep in mind that to access union members, you are required to use `unsafe` blocks, for example;

Expand Down
129 changes: 37 additions & 92 deletions src/codegen/sys/lib_.rs
Expand Up @@ -318,58 +318,31 @@ fn generate_unions(w: &mut Write, env: &Env, items: &[&Union]) -> Result<()> {

for item in items {
if let Some(ref c_type) = item.c_type {
#[cfg(feature = "use_unions")]
{
let (lines, commented) = generate_fields(env, &item.name, &item.fields);

let comment = if commented { "//" } else { "" };
if lines.is_empty() {
try!(writeln!(
w,
"{comment}#[repr(C)]\n{comment}pub union {name}(c_void);\n",
comment = comment,
name = c_type
));
} else {
try!(writeln!(
w,
"{comment}#[repr(C)]\n{comment}pub union {name} {{",
comment = comment,
name = c_type
));

for line in lines {
try!(writeln!(w, "{}{}", comment, line));
}
try!(writeln!(w, "{}}}\n", comment));
}
}
#[cfg(not(feature = "use_unions"))]
{
// TODO: GLib/GObject special cases until we have proper union support in Rust
if env.config.library_name == "GLib" && c_type == "GMutex" {
// Two c_uint or a pointer => 64 bits on all platforms currently
// supported by GLib but the alignment is different on 32 bit
// platforms (32 bit vs. 64 bits on 64 bit platforms)
try!(writeln!(
w,
"#[cfg(target_pointer_width = \"32\")]\n#[repr(C)]\npub struct {0}([u32; 2]);\n\
#[cfg(target_pointer_width = \"64\")]\n#[repr(C)]\npub struct {0}(*mut c_void);",
c_type
));
} else {
try!(writeln!(w, "pub type {} = c_void; // union", c_type));
let (lines, commented) = generate_fields(env, &item.name, &item.fields);

let comment = if commented { "//" } else { "" };
if lines.is_empty() {
try!(writeln!(
w,
"{comment}#[repr(C)]\n{comment}pub union {name}(c_void);\n",
comment = comment,
name = c_type
));
} else {
try!(writeln!(
w,
"{comment}#[repr(C)]\n{comment}pub union {name} {{",
comment = comment,
name = c_type
));

for line in lines {
try!(writeln!(w, "{}{}", comment, line));
}
try!(writeln!(w, "{}}}\n", comment));
}
}
}
#[cfg(not(feature = "use_unions"))]
{
if !items.is_empty() {
try!(writeln!(w, ""));
}
}

Ok(())
}

Expand Down Expand Up @@ -457,12 +430,11 @@ fn generate_records(w: &mut Write, env: &Env, records: &[&Record]) -> Result<()>
));
try!(writeln!(w, ""));
}
try!(writeln!(
w,
"{}#[repr(C)]\n{0}pub struct {} {{",
comment,
record.c_type
));
try!(writeln!(w, "{}#[repr(C)]", comment));
if record.derive_copy {
try!(writeln!(w, "{}#[derive(Copy,Clone)]", comment));
}
try!(writeln!(w, "{0}pub struct {} {{", record.c_type));
for line in lines {
try!(writeln!(w, "{}{}", comment, line));
}
Expand Down Expand Up @@ -508,43 +480,16 @@ fn generate_fields(env: &Env, struct_name: &str, fields: &[Field]) -> (Vec<Strin
}
};

// TODO: Special case for padding unions like used in GStreamer, see e.g.
// the padding in GstControlBinding
#[cfg(not(feature = "use_unions"))]
if !is_gweakref && !truncated && !is_ptr && is_bits &&
!is_union_special_case(&field.c_type)
{
if is_union && !truncated {
if let Some(union_) = env.library.type_(field.typ).maybe_ref_as::<Union>() {
for union_field in &union_.fields {
if union_field.name.contains("reserved") ||
union_field.name.contains("padding")
{
if let Some(ref c_type) = union_field.c_type {
let name = mangle_keywords(&*union_field.name);
let c_type = ffi_type(env, union_field.typ, c_type);
if c_type.is_err() {
commented = true;
}
lines.push(format!("\tpub {}: {},", name, c_type.into_string()));
continue 'fields;
}
}
}
}
}
}

if !cfg!(feature = "use_unions") || (is_bits && !truncated) {
if !is_gweakref && !truncated && !is_ptr && (is_union || is_bits) &&
!is_union_special_case(&field.c_type)
{
warn!(
"Field `{}::{}` not expressible in Rust, truncated",
struct_name,
field.name
);
lines.push("\t_truncated_record_marker: c_void,".to_owned());
truncated = true;
}
warn!(
"Field `{}::{}` not expressible in Rust, truncated",
struct_name,
field.name
);
lines.push("\t_truncated_record_marker: u8,".to_owned());
truncated = true;
}

if truncated {
Expand All @@ -565,7 +510,7 @@ fn generate_fields(env: &Env, struct_name: &str, fields: &[Field]) -> (Vec<Strin
continue 'fields;
}

if is_gweakref && !cfg!(feature = "use_unions") {
if is_gweakref {
// union containing a single pointer
lines.push("\tpub priv_: gpointer,".to_owned());
} else if let Some(ref c_type) = field.c_type {
Expand All @@ -574,7 +519,7 @@ fn generate_fields(env: &Env, struct_name: &str, fields: &[Field]) -> (Vec<Strin
if c_type.is_err() {
commented = true;
}
if !cfg!(feature = "use_unions") && is_gvalue && field.name == "data" {
if is_gvalue && field.name == "data" {
c_type = Ok("[u64; 2]".to_owned());
}
lines.push(format!("\tpub {}: {},", name, c_type.into_string()));
Expand Down
7 changes: 1 addition & 6 deletions src/codegen/sys/statics.rs
Expand Up @@ -3,13 +3,8 @@ use std::io::{Result, Write};
use super::super::general::write_vec;

pub fn begin(w: &mut Write) -> Result<()> {
#[cfg(feature = "use_unions")]
let u = "#![feature(untagged_unions)]";
#[cfg(not(feature = "use_unions"))]
let u = "";

let v = vec![
u,
"",
"#![allow(non_camel_case_types, non_upper_case_globals)]",
"",
"extern crate libc;",
Expand Down
2 changes: 2 additions & 0 deletions src/library.rs
Expand Up @@ -286,6 +286,7 @@ pub struct Record {
pub deprecated_version: Option<Version>,
pub doc: Option<String>,
pub doc_deprecated: Option<String>,
pub derive_copy: bool,
}

#[derive(Default, Debug)]
Expand Down Expand Up @@ -568,6 +569,7 @@ impl Type {
deprecated_version: r.deprecated_version,
doc: r.doc,
doc_deprecated: r.doc_deprecated,
derive_copy: r.derive_copy,
});
library.add_type(ns_id, &format!("#{:?}", field_tids), typ)
}
Expand Down
46 changes: 8 additions & 38 deletions src/parser.rs
Expand Up @@ -293,20 +293,9 @@ impl Library {
let u_doc = u.doc.clone();
let ctype = u.c_type.clone();

let type_id = {
#[cfg(not(feature = "use_unions"))]
{
Type::union(self, u, INTERNAL_NAMESPACE)
}
#[cfg(feature = "use_unions")]
{
Type::union(self, u, ns_id)
}
};

fields.push(Field {
name: field_name,
typ: type_id,
typ: Type::union(self, u, ns_id),
doc: u_doc,
c_type: ctype,
..Field::default()
Expand Down Expand Up @@ -350,7 +339,7 @@ impl Library {
attrs: &Attributes,
) -> Result<()> {

if let Some(typ) = try!(self.read_record(parser, ns_id, attrs, None, None)) {
if let Some(typ) = try!(self.read_record(parser, ns_id, attrs, None, None, false)) {
let name = typ.get_name().clone();
self.add_type(ns_id, &name, typ);
}
Expand All @@ -364,6 +353,7 @@ impl Library {
attrs: &Attributes,
parent_name_prefix: Option<&str>,
parent_ctype_prefix: Option<&str>,
derive_copy: bool,
) -> Result<Option<Type>> {
let mut record_name = try!(
attrs
Expand Down Expand Up @@ -452,20 +442,9 @@ impl Library {
let u_doc = u.doc.clone();
let ctype = u.c_type.clone();

let type_id = {
#[cfg(not(feature = "use_unions"))]
{
Type::union(self, u, INTERNAL_NAMESPACE)
}
#[cfg(feature = "use_unions")]
{
Type::union(self, u, ns_id)
}
};

fields.push(Field {
name: field_name,
typ: type_id,
typ: Type::union(self, u, ns_id),
doc: u_doc,
c_type: ctype,
..Field::default()
Expand Down Expand Up @@ -525,6 +504,7 @@ impl Library {
deprecated_version: deprecated_version,
doc: doc,
doc_deprecated: doc_deprecated,
derive_copy: derive_copy,
});

Ok(Some(typ))
Expand Down Expand Up @@ -598,7 +578,8 @@ impl Library {
ns_id,
attrs,
parent_name_prefix,
parent_ctype_prefix
parent_ctype_prefix,
true
)) {
Some(Type::Record(r)) => r,
_ => continue,
Expand Down Expand Up @@ -641,20 +622,9 @@ impl Library {
let r_doc = r.doc.clone();
let ctype = r.c_type.clone();

let type_id = {
#[cfg(not(feature = "use_unions"))]
{
Type::record(self, r, INTERNAL_NAMESPACE)
}
#[cfg(feature = "use_unions")]
{
Type::record(self, r, ns_id)
}
};

fields.push(Field {
name: field_name,
typ: type_id,
typ: Type::record(self, r, ns_id),
doc: r_doc,
c_type: Some(ctype),
..Field::default()
Expand Down

0 comments on commit e9a7910

Please sign in to comment.