//! Generate Rust bindings for C and C++ libraries.
//!
//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
//! functions and use types defined in the header.
//!
//! See the [`Builder`](./struct.Builder.html) struct for usage.
//!
//! See the [Users Guide](https://rust-lang.github.io/rust-bindgen/) for
//! additional documentation.
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(unused_extern_crates)]
// To avoid rather annoying warnings when matching with CXCursor_xxx as a
// constant.
#![allow(non_upper_case_globals)]
// `quote!` nests quite deeply.
#![recursion_limit = "128"]

#[macro_use]
extern crate bitflags;
extern crate cexpr;
#[macro_use]
#[allow(unused_extern_crates)]
extern crate cfg_if;
extern crate clang_sys;
extern crate lazycell;
extern crate rustc_hash;
#[macro_use]
extern crate lazy_static;
extern crate peeking_take_while;
#[macro_use]
extern crate quote;
extern crate proc_macro2;
extern crate regex;
extern crate shlex;
#[cfg(feature = "which-rustfmt")]
extern crate which;

#[cfg(feature = "logging")]
#[macro_use]
extern crate log;

#[cfg(not(feature = "logging"))]
#[macro_use]
mod log_stubs;

#[macro_use]
mod extra_assertions;

// A macro to declare an internal module for which we *must* provide
// documentation for. If we are building with the "testing_only_docs" feature,
// then the module is declared public, and our `#![deny(missing_docs)]` pragma
// applies to it. This feature is used in CI, so we won't let anything slip by
// undocumented. Normal builds, however, will leave the module private, so that
// we don't expose internals to library consumers.
macro_rules! doc_mod {
    ($m:ident, $doc_mod_name:ident) => {
        cfg_if! {
            if #[cfg(feature = "testing_only_docs")] {
                pub mod $doc_mod_name {
                    //! Autogenerated documentation module.
                    pub use super::$m::*;
                }
            } else {
            }
        }
    };
}

mod clang;
mod codegen;
mod features;
mod ir;
mod parse;
mod regex_set;
mod time;

pub mod callbacks;

doc_mod!(clang, clang_docs);
doc_mod!(features, features_docs);
doc_mod!(ir, ir_docs);
doc_mod!(parse, parse_docs);
doc_mod!(regex_set, regex_set_docs);

pub use codegen::{AliasVariation, EnumVariation};
use features::RustFeatures;
pub use features::{RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS};
use ir::context::{BindgenContext, ItemId};
use ir::item::Item;
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

use std::borrow::Cow;
use std::fs::{File, OpenOptions};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{env, iter};

// Some convenient typedefs for a fast hash map and hash set.
type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>;
type HashSet<K> = ::rustc_hash::FxHashSet<K>;
pub(crate) use std::collections::hash_map::Entry;

fn args_are_cpp(clang_args: &[String]) -> bool {
    return clang_args
        .windows(2)
        .any(|w| w[0] == "-xc++" || w[1] == "-xc++" || w == &["-x", "c++"]);
}

bitflags! {
    /// A type used to indicate which kind of items we have to generate.
    pub struct CodegenConfig: u32 {
        /// Whether to generate functions.
        const FUNCTIONS = 1 << 0;
        /// Whether to generate types.
        const TYPES = 1 << 1;
        /// Whether to generate constants.
        const VARS = 1 << 2;
        /// Whether to generate methods.
        const METHODS = 1 << 3;
        /// Whether to generate constructors
        const CONSTRUCTORS = 1 << 4;
        /// Whether to generate destructors.
        const DESTRUCTORS = 1 << 5;
    }
}

impl CodegenConfig {
    /// Returns true if functions should be generated.
    pub fn functions(self) -> bool {
        self.contains(CodegenConfig::FUNCTIONS)
    }

    /// Returns true if types should be generated.
    pub fn types(self) -> bool {
        self.contains(CodegenConfig::TYPES)
    }

    /// Returns true if constants should be generated.
    pub fn vars(self) -> bool {
        self.contains(CodegenConfig::VARS)
    }

    /// Returns true if methds should be generated.
    pub fn methods(self) -> bool {
        self.contains(CodegenConfig::METHODS)
    }

    /// Returns true if constructors should be generated.
    pub fn constructors(self) -> bool {
        self.contains(CodegenConfig::CONSTRUCTORS)
    }

    /// Returns true if destructors should be generated.
    pub fn destructors(self) -> bool {
        self.contains(CodegenConfig::DESTRUCTORS)
    }
}

impl Default for CodegenConfig {
    fn default() -> Self {
        CodegenConfig::all()
    }
}

/// Configure and generate Rust bindings for a C/C++ header.
///
/// This is the main entry point to the library.
///
/// ```ignore
/// use bindgen::builder;
///
/// // Configure and generate bindings.
/// let bindings = builder().header("path/to/input/header")
///     .whitelisted_type("SomeCoolClass")
///     .whitelisted_function("do_some_cool_thing")
///     .generate()?;
///
/// // Write the generated bindings to an output file.
/// bindings.write_to_file("path/to/output.rs")?;
/// ```
///
/// # Enums
///
/// Bindgen can map C/C++ enums into Rust in different ways. The way bindgen maps enums depends on
/// the pattern passed to several methods:
///
/// 1. [`constified_enum_module()`](#method.constified_enum_module)
/// 2. [`bitfield_enum()`](#method.bitfield_enum)
/// 3. [`rustified_enum()`](#method.rustified_enum)
///
/// For each C enum, bindgen tries to match the pattern in the following order:
///
/// 1. Constified enum module
/// 2. Bitfield enum
/// 3. Rustified enum
///
/// If none of the above patterns match, then bindgen will generate a set of Rust constants.
#[derive(Debug, Default)]
pub struct Builder {
    options: BindgenOptions,
    input_headers: Vec<String>,
    // Tuples of unsaved file contents of the form (name, contents).
    input_header_contents: Vec<(String, String)>,
}

/// Construct a new [`Builder`](./struct.Builder.html).
pub fn builder() -> Builder {
    Default::default()
}

impl Builder {
    /// Generates the command line flags use for creating `Builder`.
    pub fn command_line_flags(&self) -> Vec<String> {
        let mut output_vector: Vec<String> = Vec::new();

        if let Some(header) = self.input_headers.last().cloned() {
            // Positional argument 'header'
            output_vector.push(header);
        }

        output_vector.push("--rust-target".into());
        output_vector.push(self.options.rust_target.into());

        if self.options.default_enum_style != Default::default() {
            output_vector.push("--default-enum-style=".into());
            output_vector.push(
                match self.options.default_enum_style {
                    codegen::EnumVariation::Rust {
                        non_exhaustive: false,
                    } => "rust",
                    codegen::EnumVariation::Rust {
                        non_exhaustive: true,
                    } => "rust_non_exhaustive",
                    codegen::EnumVariation::Bitfield => "bitfield",
                    codegen::EnumVariation::Consts => "consts",
                    codegen::EnumVariation::ModuleConsts => "moduleconsts",
                }
                .into(),
            )
        }

        self.options
            .bitfield_enums
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--bitfield-enum".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .rustified_enums
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--rustified-enum".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .rustified_non_exhaustive_enums
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--rustified-enum-non-exhaustive".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .constified_enum_modules
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--constified-enum-module".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .constified_enums
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--constified-enum".into());
                output_vector.push(item.to_owned());
            })
            .count();

        if self.options.default_alias_style != Default::default() {
            output_vector.push("--default-alias-style=".into());
            output_vector
                .push(self.options.default_alias_style.as_str().into());
        }

        self.options
            .type_alias
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--type-alias".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .new_type_alias
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--new-type-alias".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .new_type_alias_deref
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--new-type-alias-deref".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .blacklisted_types
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--blacklist-type".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .blacklisted_functions
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--blacklist-function".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .blacklisted_items
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--blacklist-item".into());
                output_vector.push(item.to_owned());
            })
            .count();

        if !self.options.layout_tests {
            output_vector.push("--no-layout-tests".into());
        }

        if self.options.impl_debug {
            output_vector.push("--impl-debug".into());
        }

        if self.options.impl_partialeq {
            output_vector.push("--impl-partialeq".into());
        }

        if !self.options.derive_copy {
            output_vector.push("--no-derive-copy".into());
        }

        if !self.options.derive_debug {
            output_vector.push("--no-derive-debug".into());
        }

        if !self.options.derive_default {
            output_vector.push("--no-derive-default".into());
        } else {
            output_vector.push("--with-derive-default".into());
        }

        if self.options.derive_hash {
            output_vector.push("--with-derive-hash".into());
        }

        if self.options.derive_partialord {
            output_vector.push("--with-derive-partialord".into());
        }

        if self.options.derive_ord {
            output_vector.push("--with-derive-ord".into());
        }

        if self.options.derive_partialeq {
            output_vector.push("--with-derive-partialeq".into());
        }

        if self.options.derive_eq {
            output_vector.push("--with-derive-eq".into());
        }

        if self.options.time_phases {
            output_vector.push("--time-phases".into());
        }

        if !self.options.generate_comments {
            output_vector.push("--no-doc-comments".into());
        }

        if !self.options.whitelist_recursively {
            output_vector.push("--no-recursive-whitelist".into());
        }

        if self.options.objc_extern_crate {
            output_vector.push("--objc-extern-crate".into());
        }

        if self.options.generate_block {
            output_vector.push("--generate-block".into());
        }

        if self.options.block_extern_crate {
            output_vector.push("--block-extern-crate".into());
        }

        if self.options.builtins {
            output_vector.push("--builtins".into());
        }

        if let Some(ref prefix) = self.options.ctypes_prefix {
            output_vector.push("--ctypes-prefix".into());
            output_vector.push(prefix.clone());
        }

        if self.options.emit_ast {
            output_vector.push("--emit-clang-ast".into());
        }

        if self.options.emit_ir {
            output_vector.push("--emit-ir".into());
        }
        if let Some(ref graph) = self.options.emit_ir_graphviz {
            output_vector.push("--emit-ir-graphviz".into());
            output_vector.push(graph.clone())
        }
        if self.options.enable_cxx_namespaces {
            output_vector.push("--enable-cxx-namespaces".into());
        }
        if self.options.enable_function_attribute_detection {
            output_vector.push("--enable-function-attribute-detection".into());
        }
        if self.options.disable_name_namespacing {
            output_vector.push("--disable-name-namespacing".into());
        }
        if self.options.disable_nested_struct_naming {
            output_vector.push("--disable-nested-struct-naming".into());
        }

        if !self.options.codegen_config.functions() {
            output_vector.push("--ignore-functions".into());
        }

        output_vector.push("--generate".into());

        //Temporary placeholder for below 4 options
        let mut options: Vec<String> = Vec::new();
        if self.options.codegen_config.functions() {
            options.push("functions".into());
        }
        if self.options.codegen_config.types() {
            options.push("types".into());
        }
        if self.options.codegen_config.vars() {
            options.push("vars".into());
        }
        if self.options.codegen_config.methods() {
            options.push("methods".into());
        }
        if self.options.codegen_config.constructors() {
            options.push("constructors".into());
        }
        if self.options.codegen_config.destructors() {
            options.push("destructors".into());
        }

        output_vector.push(options.join(","));

        if !self.options.codegen_config.methods() {
            output_vector.push("--ignore-methods".into());
        }

        if !self.options.convert_floats {
            output_vector.push("--no-convert-floats".into());
        }

        if !self.options.prepend_enum_name {
            output_vector.push("--no-prepend-enum-name".into());
        }

        if self.options.array_pointers_in_arguments {
            output_vector.push("--use-array-pointers-in-arguments".into());
        }

        self.options
            .opaque_types
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--opaque-type".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .raw_lines
            .iter()
            .map(|item| {
                output_vector.push("--raw-line".into());
                output_vector.push(item.to_owned());
            })
            .count();

        if self.options.use_core {
            output_vector.push("--use-core".into());
        }

        if self.options.conservative_inline_namespaces {
            output_vector.push("--conservative-inline-namespaces".into());
        }

        self.options
            .whitelisted_functions
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--whitelist-function".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .whitelisted_types
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--whitelist-type".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .whitelisted_vars
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--whitelist-var".into());
                output_vector.push(item.to_owned());
            })
            .count();

        output_vector.push("--".into());

        if !self.options.clang_args.is_empty() {
            output_vector.extend(self.options.clang_args.iter().cloned());
        }

        if self.input_headers.len() > 1 {
            output_vector.extend(
                self.input_headers[..self.input_headers.len() - 1]
                    .iter()
                    .cloned(),
            );
        }

        if !self.options.record_matches {
            output_vector.push("--no-record-matches".into());
        }

        if !self.options.rustfmt_bindings {
            output_vector.push("--no-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());
        }

        self.options
            .no_partialeq_types
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--no-partialeq".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .no_copy_types
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--no-copy".into());
                output_vector.push(item.to_owned());
            })
            .count();

        self.options
            .no_hash_types
            .get_items()
            .iter()
            .map(|item| {
                output_vector.push("--no-hash".into());
                output_vector.push(item.to_owned());
            })
            .count();

        output_vector
    }

    /// Add an input C/C++ header to generate bindings for.
    ///
    /// This can be used to generate bindings to a single header:
    ///
    /// ```ignore
    /// let bindings = bindgen::Builder::default()
    ///     .header("input.h")
    ///     .generate()
    ///     .unwrap();
    /// ```
    ///
    /// Or you can invoke it multiple times to generate bindings to multiple
    /// headers:
    ///
    /// ```ignore
    /// let bindings = bindgen::Builder::default()
    ///     .header("first.h")
    ///     .header("second.h")
    ///     .header("third.h")
    ///     .generate()
    ///     .unwrap();
    /// ```
    pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
        self.input_headers.push(header.into());
        self
    }

    /// Add `contents` as an input C/C++ header named `name`.
    ///
    /// The file `name` will be added to the clang arguments.
    pub fn header_contents(mut self, name: &str, contents: &str) -> Builder {
        self.input_header_contents
            .push((name.into(), contents.into()));
        self
    }

    /// Specify the rust target
    ///
    /// The default is the latest stable Rust version
    pub fn rust_target(mut self, rust_target: RustTarget) -> Self {
        self.options.set_rust_target(rust_target);
        self
    }

    /// Disable support for native Rust unions, if supported.
    pub fn disable_untagged_union(mut self) -> Self {
        self.options.rust_features.untagged_union = false;
        self
    }

    /// Set the output graphviz file.
    pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder {
        let path = path.into();
        self.options.emit_ir_graphviz = Some(path);
        self
    }

    /// Whether the generated bindings should contain documentation comments or
    /// not.
    ///
    /// This ideally will always be true, but it may need to be false until we
    /// implement some processing on comments to work around issues as described
    /// in:
    ///
    /// https://github.com/rust-lang/rust-bindgen/issues/426
    pub fn generate_comments(mut self, doit: bool) -> Self {
        self.options.generate_comments = doit;
        self
    }

    /// Whether to whitelist recursively or not. Defaults to true.
    ///
    /// Given that we have explicitly whitelisted the "initiate_dance_party"
    /// function in this C header:
    ///
    /// ```c
    /// typedef struct MoonBoots {
    ///     int bouncy_level;
    /// } MoonBoots;
    ///
    /// void initiate_dance_party(MoonBoots* boots);
    /// ```
    ///
    /// We would normally generate bindings to both the `initiate_dance_party`
    /// function and the `MoonBoots` struct that it transitively references. By
    /// configuring with `whitelist_recursively(false)`, `bindgen` will not emit
    /// bindings for anything except the explicitly whitelisted items, and there
    /// would be no emitted struct definition for `MoonBoots`. However, the
    /// `initiate_dance_party` function would still reference `MoonBoots`!
    ///
    /// **Disabling this feature will almost certainly cause `bindgen` to emit
    /// bindings that will not compile!** If you disable this feature, then it
    /// is *your* responsibility to provide definitions for every type that is
    /// referenced from an explicitly whitelisted item. One way to provide the
    /// definitions is by using the [`Builder::raw_line`](#method.raw_line)
    /// method, another would be to define them in Rust and then `include!(...)`
    /// the bindings immediately afterwards.
    pub fn whitelist_recursively(mut self, doit: bool) -> Self {
        self.options.whitelist_recursively = doit;
        self
    }

    /// Generate `#[macro_use] extern crate objc;` instead of `use objc;`
    /// in the prologue of the files generated from objective-c files
    pub fn objc_extern_crate(mut self, doit: bool) -> Self {
        self.options.objc_extern_crate = doit;
        self
    }

    /// Generate proper block signatures instead of void pointers.
    pub fn generate_block(mut self, doit: bool) -> Self {
        self.options.generate_block = doit;
        self
    }

    /// Generate `#[macro_use] extern crate block;` instead of `use block;`
    /// in the prologue of the files generated from apple block files
    pub fn block_extern_crate(mut self, doit: bool) -> Self {
        self.options.block_extern_crate = doit;
        self
    }

    /// Whether to use the clang-provided name mangling. This is true by default
    /// and probably needed for C++ features.
    ///
    /// However, some old libclang versions seem to return incorrect results in
    /// some cases for non-mangled functions, see [1], so we allow disabling it.
    ///
    /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528
    pub fn trust_clang_mangling(mut self, doit: bool) -> Self {
        self.options.enable_mangling = doit;
        self
    }

    /// Hide the given type from the generated bindings. Regular expressions are
    /// supported.
    #[deprecated(note = "Use blacklist_type instead")]
    pub fn hide_type<T: AsRef<str>>(self, arg: T) -> Builder {
        self.blacklist_type(arg)
    }

    /// Hide the given type from the generated bindings. Regular expressions are
    /// supported.
    pub fn blacklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.blacklisted_types.insert(arg);
        self
    }

    /// Hide the given function from the generated bindings. Regular expressions
    /// are supported.
    pub fn blacklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.blacklisted_functions.insert(arg);
        self
    }

    /// Hide the given item from the generated bindings, regardless of
    /// whether it's a type, function, module, etc. Regular
    /// expressions are supported.
    pub fn blacklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.blacklisted_items.insert(arg);
        self
    }

    /// Treat the given type as opaque in the generated bindings. Regular
    /// expressions are supported.
    pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.opaque_types.insert(arg);
        self
    }

    /// Whitelist the given type so that it (and all types that it transitively
    /// refers to) appears in the generated bindings. Regular expressions are
    /// supported.
    #[deprecated(note = "use whitelist_type instead")]
    pub fn whitelisted_type<T: AsRef<str>>(self, arg: T) -> Builder {
        self.whitelist_type(arg)
    }

    /// Whitelist the given type so that it (and all types that it transitively
    /// refers to) appears in the generated bindings. Regular expressions are
    /// supported.
    pub fn whitelist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_types.insert(arg);
        self
    }

    /// Whitelist the given function so that it (and all types that it
    /// transitively refers to) appears in the generated bindings. Regular
    /// expressions are supported.
    pub fn whitelist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_functions.insert(arg);
        self
    }

    /// Whitelist the given function.
    ///
    /// Deprecated: use whitelist_function instead.
    #[deprecated(note = "use whitelist_function instead")]
    pub fn whitelisted_function<T: AsRef<str>>(self, arg: T) -> Builder {
        self.whitelist_function(arg)
    }

    /// Whitelist the given variable so that it (and all types that it
    /// transitively refers to) appears in the generated bindings. Regular
    /// expressions are supported.
    pub fn whitelist_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_vars.insert(arg);
        self
    }

    /// Whitelist the given variable.
    ///
    /// Deprecated: use whitelist_var instead.
    #[deprecated(note = "use whitelist_var instead")]
    pub fn whitelisted_var<T: AsRef<str>>(self, arg: T) -> Builder {
        self.whitelist_var(arg)
    }

    /// Set the default style of code to generate for enums
    pub fn default_enum_style(
        mut self,
        arg: codegen::EnumVariation,
    ) -> Builder {
        self.options.default_enum_style = arg;
        self
    }

    /// Mark the given enum (or set of enums, if using a pattern) as being
    /// bitfield-like. Regular expressions are supported.
    ///
    /// This makes bindgen generate a type that isn't a rust `enum`. Regular
    /// expressions are supported.
    pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.bitfield_enums.insert(arg);
        self
    }

    /// Mark the given enum (or set of enums, if using a pattern) as a Rust
    /// enum.
    ///
    /// This makes bindgen generate enums instead of constants. Regular
    /// expressions are supported.
    ///
    /// **Use this with caution,** you probably want to use the non_exhaustive
    /// flavor of rust enums instead of this one. Take a look at
    /// https://github.com/rust-lang/rust/issues/36927 for more information.
    pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.rustified_enums.insert(arg);
        self
    }

    /// Mark the given enum (or set of enums, if using a pattern) as a Rust
    /// enum with the #[non_exhaustive] attribute.
    ///
    /// This makes bindgen generate enums instead of constants. Regular
    /// expressions are supported.
    pub fn rustified_non_exhaustive_enum<T: AsRef<str>>(
        mut self,
        arg: T,
    ) -> Builder {
        self.options.rustified_non_exhaustive_enums.insert(arg);
        self
    }

    /// Mark the given enum (or set of enums, if using a pattern) as a set of
    /// constants that are not to be put into a module.
    pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.constified_enums.insert(arg);
        self
    }

    /// Mark the given enum (or set of enums, if using a pattern) as a set of
    /// constants that should be put into a module.
    ///
    /// This makes bindgen generate modules containing constants instead of
    /// just constants. Regular expressions are supported.
    pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.constified_enum_modules.insert(arg);
        self
    }

    /// Set the default style of code to generate for typedefs
    pub fn default_alias_style(
        mut self,
        arg: codegen::AliasVariation,
    ) -> Builder {
        self.options.default_alias_style = arg;
        self
    }

    /// Mark the given typedef alias (or set of aliases, if using a pattern) to
    /// use regular Rust type aliasing.
    ///
    /// This is the default behavior and should be used if `default_alias_style`
    /// was set to NewType or NewTypeDeref and you want to override it for a
    /// set of typedefs.
    pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.type_alias.insert(arg);
        self
    }

    /// Mark the given typedef alias (or set of aliases, if using a pattern) to
    /// be generated as a new type by having the aliased type be wrapped in a
    /// #[repr(transparent)] struct.
    ///
    /// Used to enforce stricter type checking.
    pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.new_type_alias.insert(arg);
        self
    }

    /// Mark the given typedef alias (or set of aliases, if using a pattern) to
    /// be generated as a new type by having the aliased type be wrapped in a
    /// #[repr(transparent)] struct and also have an automatically generated
    /// impl's of `Deref` and `DerefMut` to their aliased type.
    pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder {
        self.options.new_type_alias_deref.insert(arg);
        self
    }

    /// Add a string to prepend to the generated bindings. The string is passed
    /// through without any modification.
    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
        self.options.raw_lines.push(arg.into());
        self
    }

    /// Add a given line to the beginning of module `mod`.
    pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self
    where
        T: Into<String>,
        U: Into<String>,
    {
        self.options
            .module_lines
            .entry(mod_.into())
            .or_insert_with(Vec::new)
            .push(line.into());
        self
    }

    /// Add a given set of lines to the beginning of module `mod`.
    pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self
    where
        T: Into<String>,
        I: IntoIterator,
        I::Item: Into<String>,
    {
        self.options
            .module_lines
            .entry(mod_.into())
            .or_insert_with(Vec::new)
            .extend(lines.into_iter().map(Into::into));
        self
    }

    /// Add an argument to be passed straight through to clang.
    pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.clang_args.push(arg.into());
        self
    }

    /// Add arguments to be passed straight through to clang.
    pub fn clang_args<I>(mut self, iter: I) -> Builder
    where
        I: IntoIterator,
        I::Item: AsRef<str>,
    {
        for arg in iter {
            self = self.clang_arg(arg.as_ref())
        }
        self
    }

    /// Emit bindings for builtin definitions (for example `__builtin_va_list`)
    /// in the generated Rust.
    pub fn emit_builtins(mut self) -> Builder {
        self.options.builtins = true;
        self
    }

    /// Avoid converting floats to `f32`/`f64` by default.
    pub fn no_convert_floats(mut self) -> Self {
        self.options.convert_floats = false;
        self
    }

    /// Set whether layout tests should be generated.
    pub fn layout_tests(mut self, doit: bool) -> Self {
        self.options.layout_tests = doit;
        self
    }

    /// Set whether `Debug` should be implemented, if it can not be derived automatically.
    pub fn impl_debug(mut self, doit: bool) -> Self {
        self.options.impl_debug = doit;
        self
    }

    /// Set whether `PartialEq` should be implemented, if it can not be derived automatically.
    pub fn impl_partialeq(mut self, doit: bool) -> Self {
        self.options.impl_partialeq = doit;
        self
    }

    /// Set whether `Copy` should be derived by default.
    pub fn derive_copy(mut self, doit: bool) -> Self {
        self.options.derive_copy = doit;
        self
    }

    /// Set whether `Debug` should be derived by default.
    pub fn derive_debug(mut self, doit: bool) -> Self {
        self.options.derive_debug = doit;
        self
    }

    /// Set whether `Default` should be derived by default.
    pub fn derive_default(mut self, doit: bool) -> Self {
        self.options.derive_default = doit;
        self
    }

    /// Set whether `Hash` should be derived by default.
    pub fn derive_hash(mut self, doit: bool) -> Self {
        self.options.derive_hash = doit;
        self
    }

    /// Set whether `PartialOrd` should be derived by default.
    /// If we don't compute partialord, we also cannot compute
    /// ord. Set the derive_ord to `false` when doit is `false`.
    pub fn derive_partialord(mut self, doit: bool) -> Self {
        self.options.derive_partialord = doit;
        if !doit {
            self.options.derive_ord = false;
        }
        self
    }

    /// Set whether `Ord` should be derived by default.
    /// We can't compute `Ord` without computing `PartialOrd`,
    /// so we set the same option to derive_partialord.
    pub fn derive_ord(mut self, doit: bool) -> Self {
        self.options.derive_ord = doit;
        self.options.derive_partialord = doit;
        self
    }

    /// Set whether `PartialEq` should be derived by default.
    ///
    /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving
    /// `Eq` is also disabled when `doit` is `false`.
    pub fn derive_partialeq(mut self, doit: bool) -> Self {
        self.options.derive_partialeq = doit;
        if !doit {
            self.options.derive_eq = false;
        }
        self
    }

    /// Set whether `Eq` should be derived by default.
    ///
    /// We can't derive `Eq` without also deriving `PartialEq`, so we also
    /// enable deriving `PartialEq` when `doit` is `true`.
    pub fn derive_eq(mut self, doit: bool) -> Self {
        self.options.derive_eq = doit;
        if doit {
            self.options.derive_partialeq = doit;
        }
        self
    }

    /// Set whether or not to time bindgen phases, and print information to
    /// stderr.
    pub fn time_phases(mut self, doit: bool) -> Self {
        self.options.time_phases = doit;
        self
    }

    /// Emit Clang AST.
    pub fn emit_clang_ast(mut self) -> Builder {
        self.options.emit_ast = true;
        self
    }

    /// Emit IR.
    pub fn emit_ir(mut self) -> Builder {
        self.options.emit_ir = true;
        self
    }

    /// Enable C++ namespaces.
    pub fn enable_cxx_namespaces(mut self) -> Builder {
        self.options.enable_cxx_namespaces = true;
        self
    }

    /// Enable detecting must_use attributes on C functions.
    ///
    /// This is quite slow in some cases (see #1465), so it's disabled by
    /// default.
    ///
    /// Note that for this to do something meaningful for now at least, the rust
    /// target version has to have support for `#[must_use]`.
    pub fn enable_function_attribute_detection(mut self) -> Self {
        self.options.enable_function_attribute_detection = true;
        self
    }

    /// Disable name auto-namespacing.
    ///
    /// By default, bindgen mangles names like `foo::bar::Baz` to look like
    /// `foo_bar_Baz` instead of just `Baz`.
    ///
    /// This method disables that behavior.
    ///
    /// Note that this intentionally does not change the names used for
    /// whitelisting and blacklisting, which should still be mangled with the
    /// namespaces.
    ///
    /// Note, also, that this option may cause bindgen to generate duplicate
    /// names.
    pub fn disable_name_namespacing(mut self) -> Builder {
        self.options.disable_name_namespacing = true;
        self
    }

    /// Disable nested struct naming.
    ///
    /// The following structs have different names for C and C++. In case of C
    /// they are visible as `foo` and `bar`. In case of C++ they are visible as
    /// `foo` and `foo::bar`.
    ///
    /// ```c
    /// struct foo {
    ///     struct bar {
    ///     } b;
    /// };
    /// ```
    ///
    /// Bindgen wants to avoid duplicate names by default so it follows C++ naming
    /// and it generates `foo`/`foo_bar` instead of just `foo`/`bar`.
    ///
    /// This method disables this behavior and it is indented to be used only
    /// for headers that were written for C.
    pub fn disable_nested_struct_naming(mut self) -> Builder {
        self.options.disable_nested_struct_naming = true;
        self
    }

    /// Treat inline namespaces conservatively.
    ///
    /// This is tricky, because in C++ is technically legal to override an item
    /// defined in an inline namespace:
    ///
    /// ```cpp
    /// inline namespace foo {
    ///     using Bar = int;
    /// }
    /// using Bar = long;
    /// ```
    ///
    /// Even though referencing `Bar` is a compiler error.
    ///
    /// We want to support this (arguably esoteric) use case, but we don't want
    /// to make the rest of bindgen users pay an usability penalty for that.
    ///
    /// To support this, we need to keep all the inline namespaces around, but
    /// then bindgen usage is a bit more difficult, because you cannot
    /// reference, e.g., `std::string` (you'd need to use the proper inline
    /// namespace).
    ///
    /// We could complicate a lot of the logic to detect name collisions, and if
    /// not detected generate a `pub use inline_ns::*` or something like that.
    ///
    /// That's probably something we can do if we see this option is needed in a
    /// lot of cases, to improve it's usability, but my guess is that this is
    /// not going to be too useful.
    pub fn conservative_inline_namespaces(mut self) -> Builder {
        self.options.conservative_inline_namespaces = true;
        self
    }

    /// Whether inline functions should be generated or not.
    ///
    /// Note that they will usually not work. However you can use
    /// `-fkeep-inline-functions` or `-fno-inline-functions` if you are
    /// responsible of compiling the library to make them callable.
    pub fn generate_inline_functions(mut self, doit: bool) -> Self {
        self.options.generate_inline_functions = doit;
        self
    }

    /// Ignore functions.
    pub fn ignore_functions(mut self) -> Builder {
        self.options.codegen_config.remove(CodegenConfig::FUNCTIONS);
        self
    }

    /// Ignore methods.
    pub fn ignore_methods(mut self) -> Builder {
        self.options.codegen_config.remove(CodegenConfig::METHODS);
        self
    }

    /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings.
    #[deprecated(note = "please use `rust_target` instead")]
    pub fn unstable_rust(self, doit: bool) -> Self {
        let rust_target = if doit {
            RustTarget::Nightly
        } else {
            LATEST_STABLE_RUST
        };
        self.rust_target(rust_target)
    }

    /// Use core instead of libstd in the generated bindings.
    pub fn use_core(mut self) -> Builder {
        self.options.use_core = true;
        self
    }

    /// Use the given prefix for the raw types instead of `::std::os::raw`.
    pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
        self.options.ctypes_prefix = Some(prefix.into());
        self
    }

    /// Allows configuring types in different situations, see the
    /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation.
    pub fn parse_callbacks(
        mut self,
        cb: Box<dyn callbacks::ParseCallbacks>,
    ) -> Self {
        self.options.parse_callbacks = Some(cb);
        self
    }

    /// Choose what to generate using a
    /// [`CodegenConfig`](./struct.CodegenConfig.html).
    pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
        self.options.codegen_config = config;
        self
    }

    /// Whether to detect include paths using clang_sys.
    pub fn detect_include_paths(mut self, doit: bool) -> Self {
        self.options.detect_include_paths = doit;
        self
    }

    /// Prepend the enum name to constant or bitfield variants.
    pub fn prepend_enum_name(mut self, doit: bool) -> Self {
        self.options.prepend_enum_name = doit;
        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 whether we should record matched items in our regex sets.
    pub fn record_matches(mut self, doit: bool) -> Self {
        self.options.record_matches = 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
    }

    /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled.
    pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self {
        self.options.rustfmt_path = Some(path.into());
        self
    }

    /// Generate the Rust bindings using the options built up thus far.
    pub fn generate(mut self) -> Result<Bindings, ()> {
        // Add any extra arguments from the environment to the clang command line.
        if let Some(extra_clang_args) =
            env::var("BINDGEN_EXTRA_CLANG_ARGS").ok()
        {
            // Try to parse it with shell quoting. If we fail, make it one single big argument.
            if let Some(strings) = shlex::split(&extra_clang_args) {
                self.options.clang_args.extend(strings);
            } else {
                self.options.clang_args.push(extra_clang_args);
            };
        }

        // Transform input headers to arguments on the clang command line.
        self.options.input_header = self.input_headers.pop();
        self.options
            .clang_args
            .extend(self.input_headers.drain(..).flat_map(|header| {
                iter::once("-include".into()).chain(iter::once(header))
            }));

        self.options.input_unsaved_files.extend(
            self.input_header_contents
                .drain(..)
                .map(|(name, contents)| {
                    clang::UnsavedFile::new(&name, &contents)
                }),
        );

        Bindings::generate(self.options)
    }

    /// Preprocess and dump the input header files to disk.
    ///
    /// This is useful when debugging bindgen, using C-Reduce, or when filing
    /// issues. The resulting file will be named something like `__bindgen.i` or
    /// `__bindgen.ii`
    pub fn dump_preprocessed_input(&self) -> io::Result<()> {
        fn check_is_cpp(name_file: &str) -> bool {
            name_file.ends_with(".hpp") ||
                name_file.ends_with(".hxx") ||
                name_file.ends_with(".hh") ||
                name_file.ends_with(".h++")
        }

        let clang =
            clang_sys::support::Clang::find(None, &[]).ok_or_else(|| {
                io::Error::new(
                    io::ErrorKind::Other,
                    "Cannot find clang executable",
                )
            })?;

        // The contents of a wrapper file that includes all the input header
        // files.
        let mut wrapper_contents = String::new();

        // Whether we are working with C or C++ inputs.
        let mut is_cpp = args_are_cpp(&self.options.clang_args);

        // For each input header, add `#include "$header"`.
        for header in &self.input_headers {
            is_cpp |= check_is_cpp(header);

            wrapper_contents.push_str("#include \"");
            wrapper_contents.push_str(header);
            wrapper_contents.push_str("\"\n");
        }

        // For each input header content, add a prefix line of `#line 0 "$name"`
        // followed by the contents.
        for &(ref name, ref contents) in &self.input_header_contents {
            is_cpp |= check_is_cpp(name);

            wrapper_contents.push_str("#line 0 \"");
            wrapper_contents.push_str(name);
            wrapper_contents.push_str("\"\n");
            wrapper_contents.push_str(contents);
        }

        let wrapper_path = PathBuf::from(if is_cpp {
            "__bindgen.cpp"
        } else {
            "__bindgen.c"
        });

        {
            let mut wrapper_file = File::create(&wrapper_path)?;
            wrapper_file.write(wrapper_contents.as_bytes())?;
        }

        let mut cmd = Command::new(&clang.path);
        cmd.arg("-save-temps")
            .arg("-E")
            .arg("-C")
            .arg("-c")
            .arg(&wrapper_path)
            .stdout(Stdio::piped());

        for a in &self.options.clang_args {
            cmd.arg(a);
        }

        let mut child = cmd.spawn()?;

        let mut preprocessed = child.stdout.take().unwrap();
        let mut file = File::create(if is_cpp {
            "__bindgen.ii"
        } else {
            "__bindgen.i"
        })?;
        io::copy(&mut preprocessed, &mut file)?;

        if child.wait()?.success() {
            Ok(())
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "clang exited with non-zero status",
            ))
        }
    }

    /// Don't derive `PartialEq` for a given type. Regular
    /// expressions are supported.
    pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.no_partialeq_types.insert(arg.into());
        self
    }

    /// Don't derive `Copy` for a given type. Regular
    /// expressions are supported.
    pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self {
        self.options.no_copy_types.insert(arg.into());
        self
    }

    /// Don't derive `Hash` for a given type. Regular
    /// expressions are supported.
    pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.no_hash_types.insert(arg.into());
        self
    }

    /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut)
    pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self {
        self.options.array_pointers_in_arguments = doit;
        self
    }
}

/// Configuration options for generated bindings.
#[derive(Debug)]
struct BindgenOptions {
    /// The set of types that have been blacklisted and should not appear
    /// anywhere in the generated code.
    blacklisted_types: RegexSet,

    /// The set of functions that have been blacklisted and should not appear
    /// in the generated code.
    blacklisted_functions: RegexSet,

    /// The set of items, regardless of item-type, that have been
    /// blacklisted and should not appear in the generated code.
    blacklisted_items: RegexSet,

    /// The set of types that should be treated as opaque structures in the
    /// generated code.
    opaque_types: RegexSet,

    /// The explicit rustfmt path.
    rustfmt_path: Option<PathBuf>,

    /// The set of types that we should have bindings for in the generated
    /// code.
    ///
    /// This includes all types transitively reachable from any type in this
    /// set. One might think of whitelisted types/vars/functions as GC roots,
    /// and the generated Rust code as including everything that gets marked.
    whitelisted_types: RegexSet,

    /// Whitelisted functions. See docs for `whitelisted_types` for more.
    whitelisted_functions: RegexSet,

    /// Whitelisted variables. See docs for `whitelisted_types` for more.
    whitelisted_vars: RegexSet,

    /// The default style of code to generate for enums
    default_enum_style: codegen::EnumVariation,

    /// The enum patterns to mark an enum as bitfield.
    bitfield_enums: RegexSet,

    /// The enum patterns to mark an enum as a Rust enum.
    rustified_enums: RegexSet,

    /// The enum patterns to mark an enum as a non-exhaustive Rust enum.
    rustified_non_exhaustive_enums: RegexSet,

    /// The enum patterns to mark an enum as a module of constants.
    constified_enum_modules: RegexSet,

    /// The enum patterns to mark an enum as a set of constants.
    constified_enums: RegexSet,

    /// The default style of code to generate for typedefs.
    default_alias_style: codegen::AliasVariation,

    /// Typedef patterns that will use regular type aliasing.
    type_alias: RegexSet,

    /// Typedef patterns that will be aliased by creating a new struct.
    new_type_alias: RegexSet,

    /// Typedef patterns that will be wrapped in a new struct and have
    /// Deref and Deref to their aliased type.
    new_type_alias_deref: RegexSet,

    /// Whether we should generate builtins or not.
    builtins: bool,

    /// True if we should dump the Clang AST for debugging purposes.
    emit_ast: bool,

    /// True if we should dump our internal IR for debugging purposes.
    emit_ir: bool,

    /// Output graphviz dot file.
    emit_ir_graphviz: Option<String>,

    /// True if we should emulate C++ namespaces with Rust modules in the
    /// generated bindings.
    enable_cxx_namespaces: bool,

    /// True if we should try to find unexposed attributes in functions, in
    /// order to be able to generate #[must_use] attributes in Rust.
    enable_function_attribute_detection: bool,

    /// True if we should avoid mangling names with namespaces.
    disable_name_namespacing: bool,

    /// True if we should avoid generating nested struct names.
    disable_nested_struct_naming: bool,

    /// True if we should generate layout tests for generated structures.
    layout_tests: bool,

    /// True if we should implement the Debug trait for C/C++ structures and types
    /// that do not support automatically deriving Debug.
    impl_debug: bool,

    /// True if we should implement the PartialEq trait for C/C++ structures and types
    /// that do not support automatically deriving PartialEq.
    impl_partialeq: bool,

    /// True if we should derive Copy trait implementations for C/C++ structures
    /// and types.
    derive_copy: bool,

    /// True if we should derive Debug trait implementations for C/C++ structures
    /// and types.
    derive_debug: bool,

    /// True if we should derive Default trait implementations for C/C++ structures
    /// and types.
    derive_default: bool,

    /// True if we should derive Hash trait implementations for C/C++ structures
    /// and types.
    derive_hash: bool,

    /// True if we should derive PartialOrd trait implementations for C/C++ structures
    /// and types.
    derive_partialord: bool,

    /// True if we should derive Ord trait implementations for C/C++ structures
    /// and types.
    derive_ord: bool,

    /// True if we should derive PartialEq trait implementations for C/C++ structures
    /// and types.
    derive_partialeq: bool,

    /// True if we should derive Eq trait implementations for C/C++ structures
    /// and types.
    derive_eq: bool,

    /// True if we should avoid using libstd to use libcore instead.
    use_core: bool,

    /// An optional prefix for the "raw" types, like `c_int`, `c_void`...
    ctypes_prefix: Option<String>,

    /// Whether to time the bindgen phases.
    time_phases: bool,

    /// True if we should generate constant names that are **directly** under
    /// namespaces.
    namespaced_constants: bool,

    /// True if we should use MSVC name mangling rules.
    msvc_mangling: bool,

    /// Whether we should convert float types to f32/f64 types.
    convert_floats: bool,

    /// The set of raw lines to prepend to the top-level module of generated
    /// Rust code.
    raw_lines: Vec<String>,

    /// The set of raw lines to prepend to each of the modules.
    ///
    /// This only makes sense if the `enable_cxx_namespaces` option is set.
    module_lines: HashMap<String, Vec<String>>,

    /// The set of arguments to pass straight through to Clang.
    clang_args: Vec<String>,

    /// The input header file.
    input_header: Option<String>,

    /// Unsaved files for input.
    input_unsaved_files: Vec<clang::UnsavedFile>,

    /// A user-provided visitor to allow customizing different kinds of
    /// situations.
    parse_callbacks: Option<Box<dyn callbacks::ParseCallbacks>>,

    /// Which kind of items should we generate? By default, we'll generate all
    /// of them.
    codegen_config: CodegenConfig,

    /// Whether to treat inline namespaces conservatively.
    ///
    /// See the builder method description for more details.
    conservative_inline_namespaces: bool,

    /// Whether to keep documentation comments in the generated output. See the
    /// documentation for more details.
    generate_comments: bool,

    /// Whether to generate inline functions. Defaults to false.
    generate_inline_functions: bool,

    /// Whether to whitelist types recursively. Defaults to true.
    whitelist_recursively: bool,

    /// Instead of emitting 'use objc;' to files generated from objective c files,
    /// generate '#[macro_use] extern crate objc;'
    objc_extern_crate: bool,

    /// Instead of emitting 'use block;' to files generated from objective c files,
    /// generate '#[macro_use] extern crate block;'
    generate_block: bool,

    /// Instead of emitting 'use block;' to files generated from objective c files,
    /// generate '#[macro_use] extern crate block;'
    block_extern_crate: bool,

    /// Whether to use the clang-provided name mangling. This is true and
    /// probably needed for C++ features.
    ///
    /// However, some old libclang versions seem to return incorrect results in
    /// some cases for non-mangled functions, see [1], so we allow disabling it.
    ///
    /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528
    enable_mangling: bool,

    /// Whether to detect include paths using clang_sys.
    detect_include_paths: bool,

    /// Whether to prepend the enum name to bitfield or constant variants.
    prepend_enum_name: bool,

    /// Version of the Rust compiler to target
    rust_target: RustTarget,

    /// Features to enable, derived from `rust_target`
    rust_features: RustFeatures,

    /// Whether we should record which items in the regex sets ever matched.
    ///
    /// This may be a bit slower, but will enable reporting of unused whitelist
    /// items via the `error!` log.
    record_matches: bool,

    /// Whether rustfmt should format the generated bindings.
    rustfmt_bindings: bool,

    /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt
    /// options are used.
    rustfmt_configuration_file: Option<PathBuf>,

    /// The set of types that we should not derive `PartialEq` for.
    no_partialeq_types: RegexSet,

    /// The set of types that we should not derive `Copy` for.
    no_copy_types: RegexSet,

    /// The set of types that we should not derive `Hash` for.
    no_hash_types: RegexSet,

    /// Decide if C arrays should be regular pointers in rust or array pointers
    array_pointers_in_arguments: bool,
}

/// TODO(emilio): This is sort of a lie (see the error message that results from
/// removing this), but since we don't share references across panic boundaries
/// it's ok.
impl ::std::panic::UnwindSafe for BindgenOptions {}

impl BindgenOptions {
    fn build(&mut self) {
        let mut regex_sets = [
            &mut self.whitelisted_vars,
            &mut self.whitelisted_types,
            &mut self.whitelisted_functions,
            &mut self.blacklisted_types,
            &mut self.blacklisted_functions,
            &mut self.blacklisted_items,
            &mut self.opaque_types,
            &mut self.bitfield_enums,
            &mut self.constified_enums,
            &mut self.constified_enum_modules,
            &mut self.rustified_enums,
            &mut self.rustified_non_exhaustive_enums,
            &mut self.type_alias,
            &mut self.new_type_alias,
            &mut self.new_type_alias_deref,
            &mut self.no_partialeq_types,
            &mut self.no_copy_types,
            &mut self.no_hash_types,
        ];
        let record_matches = self.record_matches;
        for regex_set in &mut regex_sets {
            regex_set.build(record_matches);
        }
    }

    /// Update rust target version
    pub fn set_rust_target(&mut self, rust_target: RustTarget) {
        self.rust_target = rust_target;

        // Keep rust_features synced with rust_target
        self.rust_features = rust_target.into();
    }

    /// Get features supported by target Rust version
    pub fn rust_features(&self) -> RustFeatures {
        self.rust_features
    }
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        let rust_target = RustTarget::default();

        BindgenOptions {
            rust_target,
            rust_features: rust_target.into(),
            blacklisted_types: Default::default(),
            blacklisted_functions: Default::default(),
            blacklisted_items: Default::default(),
            opaque_types: Default::default(),
            rustfmt_path: Default::default(),
            whitelisted_types: Default::default(),
            whitelisted_functions: Default::default(),
            whitelisted_vars: Default::default(),
            default_enum_style: Default::default(),
            bitfield_enums: Default::default(),
            rustified_enums: Default::default(),
            rustified_non_exhaustive_enums: Default::default(),
            constified_enums: Default::default(),
            constified_enum_modules: Default::default(),
            default_alias_style: Default::default(),
            type_alias: Default::default(),
            new_type_alias: Default::default(),
            new_type_alias_deref: Default::default(),
            builtins: false,
            emit_ast: false,
            emit_ir: false,
            emit_ir_graphviz: None,
            layout_tests: true,
            impl_debug: false,
            impl_partialeq: false,
            derive_copy: true,
            derive_debug: true,
            derive_default: false,
            derive_hash: false,
            derive_partialord: false,
            derive_ord: false,
            derive_partialeq: false,
            derive_eq: false,
            enable_cxx_namespaces: false,
            enable_function_attribute_detection: false,
            disable_name_namespacing: false,
            disable_nested_struct_naming: false,
            use_core: false,
            ctypes_prefix: None,
            namespaced_constants: true,
            msvc_mangling: false,
            convert_floats: true,
            raw_lines: vec![],
            module_lines: HashMap::default(),
            clang_args: vec![],
            input_header: None,
            input_unsaved_files: vec![],
            parse_callbacks: None,
            codegen_config: CodegenConfig::all(),
            conservative_inline_namespaces: false,
            generate_comments: true,
            generate_inline_functions: false,
            whitelist_recursively: true,
            generate_block: false,
            objc_extern_crate: false,
            block_extern_crate: false,
            enable_mangling: true,
            detect_include_paths: true,
            prepend_enum_name: true,
            time_phases: false,
            record_matches: true,
            rustfmt_bindings: true,
            rustfmt_configuration_file: None,
            no_partialeq_types: Default::default(),
            no_copy_types: Default::default(),
            no_hash_types: Default::default(),
            array_pointers_in_arguments: false,
        }
    }
}

#[cfg(feature = "runtime")]
fn ensure_libclang_is_loaded() {
    if clang_sys::is_loaded() {
        return;
    }

    // XXX (issue #350): Ensure that our dynamically loaded `libclang`
    // doesn't get dropped prematurely, nor is loaded multiple times
    // across different threads.

    lazy_static! {
        static ref LIBCLANG: std::sync::Arc<clang_sys::SharedLibrary> = {
            clang_sys::load().expect("Unable to find libclang");
            clang_sys::get_library().expect(
                "We just loaded libclang and it had better still be \
                 here!",
            )
        };
    }

    clang_sys::set_library(Some(LIBCLANG.clone()));
}

#[cfg(not(feature = "runtime"))]
fn ensure_libclang_is_loaded() {}

/// Generated Rust bindings.
#[derive(Debug)]
pub struct Bindings {
    options: BindgenOptions,
    module: proc_macro2::TokenStream,
}

impl Bindings {
    /// Generate bindings for the given options.
    pub(crate) fn generate(
        mut options: BindgenOptions,
    ) -> Result<Bindings, ()> {
        ensure_libclang_is_loaded();

        #[cfg(feature = "runtime")]
        debug!(
            "Generating bindings, libclang at {}",
            clang_sys::get_library().unwrap().path().display()
        );
        #[cfg(not(feature = "runtime"))]
        debug!("Generating bindings, libclang linked");

        options.build();

        fn detect_include_paths(options: &mut BindgenOptions) {
            if !options.detect_include_paths {
                return;
            }

            // Filter out include paths and similar stuff, so we don't incorrectly
            // promote them to `-isystem`.
            let clang_args_for_clang_sys = {
                let mut last_was_include_prefix = false;
                options
                    .clang_args
                    .iter()
                    .filter(|arg| {
                        if last_was_include_prefix {
                            last_was_include_prefix = false;
                            return false;
                        }

                        let arg = &**arg;

                        // https://clang.llvm.org/docs/ClangCommandLineReference.html
                        // -isystem and -isystem-after are harmless.
                        if arg == "-I" || arg == "--include-directory" {
                            last_was_include_prefix = true;
                            return false;
                        }

                        if arg.starts_with("-I") ||
                            arg.starts_with("--include-directory=")
                        {
                            return false;
                        }

                        true
                    })
                    .cloned()
                    .collect::<Vec<_>>()
            };

            debug!(
                "Trying to find clang with flags: {:?}",
                clang_args_for_clang_sys
            );

            let clang = match clang_sys::support::Clang::find(
                None,
                &clang_args_for_clang_sys,
            ) {
                None => return,
                Some(clang) => clang,
            };

            debug!("Found clang: {:?}", clang);

            // Whether we are working with C or C++ inputs.
            let is_cpp = args_are_cpp(&options.clang_args);
            let search_paths = if is_cpp {
                clang.cpp_search_paths
            } else {
                clang.c_search_paths
            };

            if let Some(search_paths) = search_paths {
                for path in search_paths.into_iter() {
                    if let Ok(path) = path.into_os_string().into_string() {
                        options.clang_args.push("-isystem".to_owned());
                        options.clang_args.push(path);
                    }
                }
            }
        }

        detect_include_paths(&mut options);

        #[cfg(unix)]
        fn can_read(perms: &std::fs::Permissions) -> bool {
            use std::os::unix::fs::PermissionsExt;
            perms.mode() & 0o444 > 0
        }

        #[cfg(not(unix))]
        fn can_read(_: &std::fs::Permissions) -> bool {
            true
        }

        if let Some(h) = options.input_header.as_ref() {
            if let Ok(md) = std::fs::metadata(h) {
                if md.is_dir() {
                    eprintln!("error: '{}' is a folder", h);
                    return Err(());
                }
                if !can_read(&md.permissions()) {
                    eprintln!(
                        "error: insufficient permissions to read '{}'",
                        h
                    );
                    return Err(());
                }
                options.clang_args.push(h.clone())
            } else {
                eprintln!("error: header '{}' does not exist.", h);
                return Err(());
            }
        }

        for f in options.input_unsaved_files.iter() {
            options.clang_args.push(f.name.to_str().unwrap().to_owned())
        }

        debug!("Fixed-up options: {:?}", options);

        let time_phases = options.time_phases;
        let mut context = BindgenContext::new(options);

        {
            let _t = time::Timer::new("parse").with_output(time_phases);
            parse(&mut context)?;
        }

        let (items, options) = codegen::codegen(context);

        Ok(Bindings {
            options: options,
            module: quote! {
                #( #items )*
            },
        })
    }

    /// Convert these bindings into source text (with raw lines prepended).
    pub fn to_string(&self) -> String {
        let mut bytes = vec![];
        self.write(Box::new(&mut bytes) as Box<dyn Write>)
            .expect("writing to a vec cannot fail");
        String::from_utf8(bytes)
            .expect("we should only write bindings that are valid utf-8")
    }

    /// Write these bindings as source text to a file.
    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(path.as_ref())?;
        self.write(Box::new(file))?;
        Ok(())
    }

    /// Write these bindings as source text to the given `Write`able.
    pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> {
        writer.write(
            "/* automatically generated by rust-bindgen */\n\n".as_bytes(),
        )?;

        for line in self.options.raw_lines.iter() {
            writer.write(line.as_bytes())?;
            writer.write("\n".as_bytes())?;
        }

        if !self.options.raw_lines.is_empty() {
            writer.write("\n".as_bytes())?;
        }

        let bindings = self.module.to_string();

        match self.rustfmt_generated_string(&bindings) {
            Ok(rustfmt_bindings) => {
                writer.write(rustfmt_bindings.as_bytes())?;
            }
            Err(err) => {
                eprintln!(
                    "Failed to run rustfmt: {} (non-fatal, continuing)",
                    err
                );
                writer.write(bindings.as_bytes())?;
            }
        }
        Ok(())
    }

    /// Gets the rustfmt path to rustfmt the generated bindings.
    fn rustfmt_path<'a>(&'a self) -> io::Result<Cow<'a, PathBuf>> {
        debug_assert!(self.options.rustfmt_bindings);
        if let Some(ref p) = self.options.rustfmt_path {
            return Ok(Cow::Borrowed(p));
        }
        if let Ok(rustfmt) = env::var("RUSTFMT") {
            return Ok(Cow::Owned(rustfmt.into()));
        }
        #[cfg(feature = "which-rustfmt")]
        match which::which("rustfmt") {
            Ok(p) => Ok(Cow::Owned(p)),
            Err(e) => {
                Err(io::Error::new(io::ErrorKind::Other, format!("{}", e)))
            }
        }
        #[cfg(not(feature = "which-rustfmt"))]
        // No rustfmt binary was specified, so assume that the binary is called
        // "rustfmt" and that it is in the user's PATH.
        Ok(Cow::Owned("rustfmt".into()))
    }

    /// Checks if rustfmt_bindings is set and runs rustfmt on the string
    fn rustfmt_generated_string<'a>(
        &self,
        source: &'a str,
    ) -> io::Result<Cow<'a, str>> {
        let _t = time::Timer::new("rustfmt_generated_string")
            .with_output(self.options.time_phases);

        if !self.options.rustfmt_bindings {
            return Ok(Cow::Borrowed(source));
        }

        let rustfmt = self.rustfmt_path()?;
        let mut cmd = Command::new(&*rustfmt);

        cmd.stdin(Stdio::piped()).stdout(Stdio::piped());

        if let Some(path) = self
            .options
            .rustfmt_configuration_file
            .as_ref()
            .and_then(|f| f.to_str())
        {
            cmd.args(&["--config-path", path]);
        }

        let mut child = cmd.spawn()?;
        let mut child_stdin = child.stdin.take().unwrap();
        let mut child_stdout = child.stdout.take().unwrap();

        let source = source.to_owned();

        // Write to stdin in a new thread, so that we can read from stdout on this
        // thread. This keeps the child from blocking on writing to its stdout which
        // might block us from writing to its stdin.
        let stdin_handle = ::std::thread::spawn(move || {
            let _ = child_stdin.write_all(source.as_bytes());
            source
        });

        let mut output = vec![];
        io::copy(&mut child_stdout, &mut output)?;

        let status = child.wait()?;
        let source = stdin_handle.join().expect(
            "The thread writing to rustfmt's stdin doesn't do \
             anything that could panic",
        );

        match String::from_utf8(output) {
            Ok(bindings) => match status.code() {
                Some(0) => Ok(Cow::Owned(bindings)),
                Some(2) => Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Rustfmt parsing errors.".to_string(),
                )),
                Some(3) => {
                    warn!("Rustfmt could not format some lines.");
                    Ok(Cow::Owned(bindings))
                }
                _ => Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Internal rustfmt error".to_string(),
                )),
            },
            _ => Ok(Cow::Owned(source)),
        }
    }
}

/// Determines whether the given cursor is in any of the files matched by the
/// options.
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
    ctx.options().builtins || !cursor.is_builtin()
}

/// Parse one `Item` from the Clang cursor.
fn parse_one(
    ctx: &mut BindgenContext,
    cursor: clang::Cursor,
    parent: Option<ItemId>,
) -> clang_sys::CXChildVisitResult {
    if !filter_builtins(ctx, &cursor) {
        return CXChildVisit_Continue;
    }

    use clang_sys::CXChildVisit_Continue;
    match Item::parse(cursor, parent, ctx) {
        Ok(..) => {}
        Err(ParseError::Continue) => {}
        Err(ParseError::Recurse) => {
            cursor.visit(|child| parse_one(ctx, child, parent));
        }
    }
    CXChildVisit_Continue
}

/// Parse the Clang AST into our `Item` internal representation.
fn parse(context: &mut BindgenContext) -> Result<(), ()> {
    use clang_sys::*;

    let mut any_error = false;
    for d in context.translation_unit().diags().iter() {
        let msg = d.format();
        let is_err = d.severity() >= CXDiagnostic_Error;
        eprintln!("{}, err: {}", msg, is_err);
        any_error |= is_err;
    }

    if any_error {
        return Err(());
    }

    let cursor = context.translation_unit().cursor();

    if context.options().emit_ast {
        fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult {
            if !cur.is_builtin() {
                clang::ast_dump(&cur, 0)
            } else {
                CXChildVisit_Continue
            }
        }
        cursor.visit(|cur| dump_if_not_builtin(&cur));
    }

    let root = context.root_module();
    context.with_module(root, |context| {
        cursor.visit(|cursor| parse_one(context, cursor, None))
    });

    assert!(
        context.current_module() == context.root_module(),
        "How did this happen?"
    );
    Ok(())
}

/// Extracted Clang version data
#[derive(Debug)]
pub struct ClangVersion {
    /// Major and minor semver, if parsing was successful
    pub parsed: Option<(u32, u32)>,
    /// full version string
    pub full: String,
}

/// Get the major and the minor semver numbers of Clang's version
pub fn clang_version() -> ClangVersion {
    ensure_libclang_is_loaded();

    let raw_v: String = clang::extract_clang_version();
    let split_v: Option<Vec<&str>> = raw_v
        .split_whitespace()
        .nth(2)
        .map(|v| v.split('.').collect());
    match split_v {
        Some(v) => {
            if v.len() >= 2 {
                let maybe_major = v[0].parse::<u32>();
                let maybe_minor = v[1].parse::<u32>();
                match (maybe_major, maybe_minor) {
                    (Ok(major), Ok(minor)) => {
                        return ClangVersion {
                            parsed: Some((major, minor)),
                            full: raw_v.clone(),
                        }
                    }
                    _ => {}
                }
            }
        }
        None => {}
    };
    ClangVersion {
        parsed: None,
        full: raw_v.clone(),
    }
}

/// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed
/// line
///
/// When running in side a `build.rs` script, this can be used to make cargo invalidate the
/// generated bindings whenever any of the files included from the header change:
/// ```
/// use bindgen::builder;
/// let bindings = builder()
///     .header("path/to/input/header")
///     .parse_callbacks(Box::new(bindgen::CargoCallbacks))
///     .generate();
/// ```
#[derive(Debug)]
pub struct CargoCallbacks;

impl callbacks::ParseCallbacks for CargoCallbacks {
    fn include_file(&self, filename: &str) {
        println!("cargo:rerun-if-changed={}", filename);
    }
}

/// Test command_line_flag function.
#[test]
fn commandline_flag_unit_test_function() {
    //Test 1
    let bindings = ::builder();
    let command_line_flags = bindings.command_line_flags();

    let test_cases = vec![
        "--rust-target",
        "--no-derive-default",
        "--generate",
        "functions,types,vars,methods,constructors,destructors",
    ]
    .iter()
    .map(|&x| x.into())
    .collect::<Vec<String>>();

    assert!(test_cases
        .iter()
        .all(|ref x| command_line_flags.contains(x),));

    //Test 2
    let bindings = ::builder()
        .header("input_header")
        .whitelist_type("Distinct_Type")
        .whitelist_function("safe_function");

    let command_line_flags = bindings.command_line_flags();
    let test_cases = vec![
        "--rust-target",
        "input_header",
        "--no-derive-default",
        "--generate",
        "functions,types,vars,methods,constructors,destructors",
        "--whitelist-type",
        "Distinct_Type",
        "--whitelist-function",
        "safe_function",
    ]
    .iter()
    .map(|&x| x.into())
    .collect::<Vec<String>>();
    println!("{:?}", command_line_flags);

    assert!(test_cases
        .iter()
        .all(|ref x| command_line_flags.contains(x),));
}
