diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 4 | ||||
-rw-r--r-- | src/ir/comp.rs | 4 | ||||
-rw-r--r-- | src/ir/context.rs | 8 | ||||
-rw-r--r-- | src/ir/template.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 114 | ||||
-rw-r--r-- | src/options.rs | 37 |
6 files changed, 151 insertions, 18 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 886f3860..6113e5d5 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -175,7 +175,7 @@ impl<'a> CodegenResult<'a> { /// counter internally so the next time we ask for the overload for this /// name, we get the incremented value, and so on. fn overload_number(&mut self, name: &str) -> u32 { - let mut counter = + let counter = self.overload_counters.entry(name.into()).or_insert(0); let number = *counter; *counter += 1; @@ -2030,7 +2030,7 @@ impl MethodCodegen for Method { } let count = { - let mut count = method_names.entry(name.clone()).or_insert(0); + let count = method_names.entry(name.clone()).or_insert(0); *count += 1; *count - 1 }; diff --git a/src/ir/comp.rs b/src/ir/comp.rs index ecdfb5de..98002b68 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -460,7 +460,7 @@ fn raw_fields_to_fields_and_bitfield_units<I>(ctx: &BindgenContext, /// (potentially multiple) bitfield units. fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext, bitfield_unit_count: &mut usize, - mut fields: &mut E, + fields: &mut E, raw_bitfields: I) where E: Extend<Field>, I: IntoIterator<Item=RawField> @@ -478,7 +478,7 @@ fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext, // TODO(emilio): Take into account C++'s wide bitfields, and // packing, sigh. - fn flush_allocation_unit<E>(mut fields: &mut E, + fn flush_allocation_unit<E>(fields: &mut E, bitfield_unit_count: &mut usize, unit_size_in_bits: usize, unit_align_in_bits: usize, diff --git a/src/ir/context.rs b/src/ir/context.rs index a0663d8c..a2493aee 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -466,8 +466,8 @@ impl<'ctx> BindgenContext<'ctx> { assert!(item.id() != self.root_module); assert!(!self.items.contains_key(&item.id())); - if let Some(mut parent) = self.items.get_mut(&item.parent_id()) { - if let Some(mut module) = parent.as_module_mut() { + if let Some(parent) = self.items.get_mut(&item.parent_id()) { + if let Some(module) = parent.as_module_mut() { debug!("add_item_to_module: adding {:?} as child of parent module {:?}", item.id(), item.parent_id()); @@ -607,7 +607,7 @@ impl<'ctx> BindgenContext<'ctx> { to opaque blob"); Item::new_opaque_type(self.next_item_id(), &ty, self) }); - let mut item = self.items.get_mut(&id).unwrap(); + let item = self.items.get_mut(&id).unwrap(); *item.kind_mut().as_type_mut().unwrap().kind_mut() = TypeKind::ResolvedTypeRef(resolved); @@ -699,7 +699,7 @@ impl<'ctx> BindgenContext<'ctx> { debug!("Replacing {:?} with {:?}", id, replacement); let new_parent = { - let mut item = self.items.get_mut(&id).unwrap(); + let item = self.items.get_mut(&id).unwrap(); *item.kind_mut().as_type_mut().unwrap().kind_mut() = TypeKind::ResolvedTypeRef(replacement); item.parent_id() diff --git a/src/ir/template.rs b/src/ir/template.rs index 30189908..f1828327 100644 --- a/src/ir/template.rs +++ b/src/ir/template.rs @@ -322,7 +322,7 @@ impl IsOpaque for TemplateInstantiation { arg_path[1..].join("::") }).collect(); { - let mut last = path.last_mut().unwrap(); + let last = path.last_mut().unwrap(); last.push('<'); last.push_str(&args.join(", ")); last.push('>'); @@ -26,6 +26,7 @@ extern crate peeking_take_while; extern crate regex; #[macro_use] extern crate lazy_static; +extern crate which; #[cfg(feature = "logging")] #[macro_use] @@ -455,6 +456,19 @@ impl Builder { ); } + if !self.options.rustfmt_bindings { + output_vector.push("--rustfmt-bindings".into()); + } + + if let Some(path) = self.options + .rustfmt_configuration_file + .as_ref() + .and_then(|f| f.to_str()) + { + output_vector.push("--rustfmt-configuration-file".into()); + output_vector.push(path.into()); + } + output_vector } @@ -840,6 +854,20 @@ impl Builder { self } + /// Set whether rustfmt should format the generated bindings. + pub fn rustfmt_bindings(mut self, doit: bool) -> Self { + self.options.rustfmt_bindings = doit; + self + } + + /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt + /// options are used. + pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self { + self = self.rustfmt_bindings(true); + self.options.rustfmt_configuration_file = path; + self + } + /// Generate the Rust bindings using the options built up thus far. pub fn generate<'ctx>(mut self) -> Result<Bindings<'ctx>, ()> { self.options.input_header = self.input_headers.pop(); @@ -1099,6 +1127,13 @@ pub struct BindgenOptions { /// Features to enable, derived from `rust_target` rust_features: RustFeatures, + + /// Whether rustfmt should format the generated bindings. + pub rustfmt_bindings: bool, + + /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt + /// options are used. + pub rustfmt_configuration_file: Option<PathBuf>, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -1183,6 +1218,8 @@ impl Default for BindgenOptions { objc_extern_crate: false, enable_mangling: true, prepend_enum_name: true, + rustfmt_bindings: false, + rustfmt_configuration_file: None, } } } @@ -1334,14 +1371,18 @@ impl<'ctx> Bindings<'ctx> { /// Write these bindings as source text to a file. pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { - let file = try!( - OpenOptions::new() - .write(true) - .truncate(true) - .create(true) - .open(path) - ); - self.write(Box::new(file)) + { + let file = try!( + OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(path.as_ref()) + ); + self.write(Box::new(file))?; + } + + self.rustfmt_generated_file(path.as_ref()) } /// Write these bindings as source text to the given `Write`able. @@ -1364,6 +1405,63 @@ impl<'ctx> Bindings<'ctx> { try!(eof(&mut ps.s)); ps.s.out.flush() } + + /// Checks if rustfmt_bindings is set and runs rustfmt on the file + fn rustfmt_generated_file(&self, file: &Path) -> io::Result<()> { + if !self.context.options().rustfmt_bindings { + return Ok(()); + } + + let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") { + rustfmt + } else { + return Err(io::Error::new( + io::ErrorKind::Other, + "Rustfmt activated, but it could not be found in global path.", + )); + }; + + let mut cmd = Command::new(rustfmt); + + if let Some(path) = self.context + .options() + .rustfmt_configuration_file + .as_ref() + .and_then(|f| f.to_str()) + { + cmd.args(&["--config-path", path]); + } + + if let Ok(output) = cmd.arg(file).output() { + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + match output.status.code() { + Some(2) => Err(io::Error::new( + io::ErrorKind::Other, + format!("Rustfmt parsing errors:\n{}", stderr), + )), + Some(3) => { + warn!( + "Rustfmt could not format some lines:\n{}", + stderr + ); + Ok(()) + } + _ => Err(io::Error::new( + io::ErrorKind::Other, + format!("Internal rustfmt error:\n{}", stderr), + )), + } + } else { + Ok(()) + } + } else { + Err(io::Error::new( + io::ErrorKind::Other, + "Error executing rustfmt!", + )) + } + } } /// Determines whether the given cursor is in any of the files matched by the diff --git a/src/options.rs b/src/options.rs index 28faea99..7b5169b7 100644 --- a/src/options.rs +++ b/src/options.rs @@ -4,6 +4,7 @@ use clap::{App, Arg}; use std::fs::File; use std::io::{self, Error, ErrorKind, Write, stderr}; use std::str::FromStr; +use std::path::PathBuf; /// Construct a new [`Builder`](./struct.Builder.html) from command line flags. pub fn builder_from_flags<I>( @@ -231,7 +232,20 @@ where .help("Preprocess and dump the input header files to disk. \ Useful when debugging bindgen, using C-Reduce, or when \ filing issues. The resulting file will be named \ - something like `__bindgen.i` or `__bindgen.ii`.") + something like `__bindgen.i` or `__bindgen.ii`."), + Arg::with_name("rustfmt-bindings") + .long("rustfmt-bindings") + .help("Format the generated bindings with rustfmt. \ + Rustfmt needs to be in the global PATH."), + Arg::with_name("rustfmt-configuration-file") + .long("rustfmt-configuration-file") + .help("The absolute path to the rustfmt configuration file. \ + The configuration file will be used for formatting the bindings. \ + Setting this parameter, will automatically set --rustfmt-bindings.") + .value_name("path") + .takes_value(true) + .multiple(false) + .number_of_values(1), ]) // .args() .get_matches_from(args); @@ -458,6 +472,27 @@ where builder.dump_preprocessed_input()?; } + if matches.is_present("rustfmt-bindings") { + builder = builder.rustfmt_bindings(true); + } + + if let Some(path_str) = matches.value_of("rustfmt-configuration-file") { + let path = PathBuf::from(path_str); + + if !path.is_absolute() { + return Err(Error::new(ErrorKind::Other, + "--rustfmt-configuration--file needs to be an absolute path!")); + } + + if path.to_str().is_none() { + return Err( + Error::new(ErrorKind::Other, + "--rustfmt-configuration-file contains non-valid UTF8 characters.")); + } + + builder = builder.rustfmt_configuration_file(Some(path)); + } + let verbose = matches.is_present("verbose"); Ok((builder, output, verbose)) |