<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod additional_cpp_generator;
mod bridge_converter;
mod byvalue_checker;
mod parse;
mod preprocessor_parse_callbacks;
mod rust_pretty_printer;
mod types;

#[cfg(test)]
mod integration_tests;

use proc_macro2::TokenStream as TokenStream2;
use std::path::PathBuf;

use indoc::indoc;
use quote::ToTokens;
use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::{parse_quote, ItemMod, Macro};

use additional_cpp_generator::{AdditionalCpp, AdditionalCppGenerator};
use itertools::join;
use log::{debug, info, warn};
use preprocessor_parse_callbacks::{PreprocessorDefinitions, PreprocessorParseCallbacks};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Mutex;
use types::TypeName;

pub use parse::{parse_file, ParseError};

const BINDGEN_BLOCKLIST: &[&str] = &["std.*", ".*mbstate_t.*"];
pub struct CppFilePair {
    pub header: Vec<u8>,
    pub implementation: Vec<u8>,
    pub header_name: String,
}

pub struct GeneratedCpp(pub Vec<CppFilePair>);

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Bindgen(()),
    CxxGen(cxx_gen::Error),
    Parsing(syn::Error),
    NoAutoCxxInc,
    CouldNotCanoncalizeIncludeDir(PathBuf),
    Conversion(bridge_converter::ConvertError),
}

pub type Result<T, E = Error> = std::result::Result<T, E>;

pub enum CppInclusion {
    Define(String),
    Header(String),
}

/// Core of the autocxx engine.
/// TODO - consider whether this 'engine' crate should actually be a
/// directory of source symlinked from all the other sub-crates, so that
/// we avoid exposing an external interface from this code.
pub struct IncludeCpp {
    inclusions: Vec<CppInclusion>,
    allowlist: Vec<String>, // not TypeName as it may be functions or whatever.
    pod_types: Vec<TypeName>,
    preconfigured_inc_dirs: Option<std::ffi::OsString>,
    parse_only: bool,
    preprocessor_definitions: Rc<Mutex<PreprocessorDefinitions>>,
}

impl Parse for IncludeCpp {
    fn parse(input: ParseStream) -> ParseResult<Self> {
        Self::new_from_parse_stream(input)
    }
}

fn dump_generated_code(gen: cxx_gen::GeneratedCode) -> Result<cxx_gen::GeneratedCode> {
    info!(
        "CXX:\n{}",
        String::from_utf8(gen.implementation.clone()).unwrap()
    );
    info!(
        "header:\n{}",
        String::from_utf8(gen.header.clone()).unwrap()
    );
    Ok(gen)
}

/// Prelude of C++ for squirting into bindgen. This configures
/// bindgen to output simpler types to replace some STL types
/// that bindgen just can't cope with. Although we then replace
/// those types with cxx types (e.g. UniquePtr), this intermediate
/// step is still necessary because bindgen can't otherwise
/// give us the templated types (e.g. when faced with the STL
/// unique_ptr, bindgen would normally give us std_unique_ptr
/// as opposed to std_unique_ptr<T>.)
static PRELUDE: &str = indoc! {"
    /**
    *

    */
    template<typename T> class UniquePtr {
        T* ptr;
    };

    /**
    *

    */
    class CxxString {
        char* str_data;
    };
    \n"};

impl IncludeCpp {
    fn new_from_parse_stream(input: ParseStream) -> syn::Result<Self> {
        // Takes as inputs:
        // 1. List of headers to include
        // 2. List of #defines to include
        // 3. Allowlist

        let mut inclusions = Vec::new();
        let mut allowlist = Vec::new();
        let mut pod_types = Vec::new();
        let mut parse_only = false;

        while !input.is_empty() {
            let ident: syn::Ident = input.parse()?;
            if ident == "Header" {
                let args;
                syn::parenthesized!(args in input);
                let hdr: syn::LitStr = args.parse()?;
                inclusions.push(CppInclusion::Header(hdr.value()));
            } else if ident == "Allow" || ident == "AllowPOD" {
                let args;
                syn::parenthesized!(args in input);
                let allow: syn::LitStr = args.parse()?;
                allowlist.push(allow.value());
                if ident == "AllowPOD" {
                    pod_types.push(TypeName::new(&allow.value()));
                }
            } else if ident == "ParseOnly" {
                parse_only = true;
            } else {
                return Err(syn::Error::new(
                    ident.span(),
                    "expected Header, Allow or AllowPOD",
                ));
            }
            if input.is_empty() {
                break;
            }
            input.parse::<syn::Token![,]>()?;
        }

        Ok(IncludeCpp {
            inclusions,
            allowlist,
            pod_types,
            preconfigured_inc_dirs: None,
            parse_only,
            preprocessor_definitions: Rc::new(Mutex::new(PreprocessorDefinitions::new())),
        })
    }

    pub fn new_from_syn(mac: Macro) -> Result<Self> {
        mac.parse_body::<IncludeCpp>().map_err(Error::Parsing)
    }

    pub fn set_include_dirs<P: AsRef<std::ffi::OsStr>>(&mut self, include_dirs: P) {
        self.preconfigured_inc_dirs = Some(include_dirs.as_ref().into());
    }

    fn build_header(&self) -> String {
        join(
            self.inclusions.iter().map(|incl| match incl {
                CppInclusion::Define(symbol) => format!("#define {}\n", symbol),
                CppInclusion::Header(path) => format!("#include \"{}\"\n", path),
            }),
            "",
        )
    }

    fn determine_incdirs(&self) -> Result<Vec<PathBuf>> {
        let inc_dirs = match &self.preconfigured_inc_dirs {
            Some(d) => d.clone(),
            None => std::env::var_os("AUTOCXX_INC").ok_or(Error::NoAutoCxxInc)?,
        };
        let inc_dirs = std::env::split_paths(&inc_dirs);
        // TODO consider if we can or should look up the include path automatically
        // instead of requiring callers always to set AUTOCXX_INC.

        // On Windows, the canonical path begins with a UNC prefix that cannot be passed to
        // the MSVC compiler, so dunce::canonicalize() is used instead of std::fs::canonicalize()
        // See:
        // * https://github.com/dtolnay/cxx/pull/41
        // * https://github.com/alexcrichton/cc-rs/issues/169
        inc_dirs
            .map(|p| dunce::canonicalize(&p).map_err(|_| Error::CouldNotCanoncalizeIncludeDir(p)))
            .collect()
    }

    fn make_bindgen_builder(&self) -> Result<bindgen::Builder> {
        let inc_dirs = self.determine_incdirs()?;

        debug!("Inc dir: {:?}", inc_dirs);

        // TODO support different C++ versions
        let mut builder = bindgen::builder()
            .clang_args(&["-x", "c++", "-std=c++14"])
            .derive_copy(false)
            .derive_debug(false)
            .parse_callbacks(Box::new(PreprocessorParseCallbacks::new(
                self.preprocessor_definitions.clone(),
            )))
            .default_enum_style(bindgen::EnumVariation::Rust {
                non_exhaustive: false,
            })
            .layout_tests(false); // TODO revisit later
        for item in BINDGEN_BLOCKLIST.iter() {
            builder = builder.blacklist_item(*item);
        }

        for inc_dir in inc_dirs {
            // TODO work with OsStrs here to avoid the .display()
            builder = builder.clang_arg(format!("-I{}", inc_dir.display()));
        }

        // 3. Passes allowlist and other options to the bindgen::Builder equivalent
        //    to --output-style=cxx --allowlist=<as passed in>
        for a in &self.allowlist {
            // TODO - allowlist type/functions/separately
            builder = builder
                .whitelist_type(a)
                .whitelist_function(a)
                .whitelist_var(a);
        }

        Ok(builder)
    }

    fn inject_header_into_bindgen(
        &self,
        mut builder: bindgen::Builder,
        additional_cpp: Option<AdditionalCpp>,
    ) -> bindgen::Builder {
        let full_header = self.build_header();
        let more_decls = if let Some(additional_cpp) = additional_cpp {
            for a in additional_cpp.extra_allowlist {
                builder = builder.whitelist_function(a);
            }
            format!(
                "#include <memory>\n\n// Extra autocxx insertions:\n\n{}\n\n",
                additional_cpp.declarations
            )
        } else {
            String::new()
        };
        let full_header = format!("{}{}\n\n{}", PRELUDE, more_decls, full_header,);
        info!("Full header: {}", full_header);
        builder = builder.header_contents("example.hpp", &full_header);
        builder
    }

    pub fn generate_rs(&self) -> Result<TokenStream2> {
        let results = self.do_generation()?;
        Ok(match results {
            Some((itemmod, _)) => itemmod.to_token_stream(),
            None => TokenStream2::new(),
        })
    }

    fn get_preprocessor_defs_mod(&self) -> Option<ItemMod> {
        let another_ref = self.preprocessor_definitions.clone();
        let m = another_ref.try_lock().unwrap().to_mod();
        m
    }

    fn parse_bindings(&self, bindings: bindgen::Bindings) -> Result<ItemMod> {
        // This bindings object is actually a TokenStream internally and we're wasting
        // effort converting to and from string. We could enhance the bindgen API
        // in future.
        let bindings = bindings.to_string();
        // Manually add the mod ffi {} so that we can ask syn to parse
        // into a single construct.
        let bindings = format!("mod bindgen {{ {} }}", bindings);
        info!("Bindings: {}", bindings);
        syn::parse_str::<ItemMod>(&bindings).map_err(Error::Parsing)
    }

    fn generate_include_list(&self) -> Vec<String> {
        let mut include_list = Vec::new();
        for incl in &self.inclusions {
            match incl {
                CppInclusion::Header(ref hdr) => {
                    include_list.push(hdr.clone());
                }
                CppInclusion::Define(_) => warn!("Currently no way to define! within cxx"),
            }
        }
        include_list
    }

    fn do_generation(&self) -> Result<Option<(ItemMod, AdditionalCppGenerator)>> {
        // If we are in parse only mode, do nothing. This is used for
        // doc tests to ensure the parsing is valid, but we can't expect
        // valid C++ header files or linkers to allow a complete build.
        if self.parse_only {
            return Ok(None);
        }

        // 4. (also respects environment variables to pick up more headers,
        //     include paths and #defines)
        // Then:
        // 1. Builds an overall C++ header with all those #defines and #includes
        // 2. Passes it to bindgen::Builder::header
        let builder = self.make_bindgen_builder()?;
        let bindings = self
            .inject_header_into_bindgen(builder, None)
            .generate()
            .map_err(Error::Bindgen)?;
        let bindings = self.parse_bindings(bindings)?;

        let mut converter = bridge_converter::BridgeConverter::new(
            self.generate_include_list(),
            self.pod_types.clone(), // TODO take self by value to avoid clone.
        );

        let mut conversion = converter
            .convert(bindings, None, &HashMap::new())
            .map_err(Error::Conversion)?;
        let mut additional_cpp_generator = AdditionalCppGenerator::new(self.build_header());
        additional_cpp_generator.add_needs(conversion.additional_cpp_needs);
        let additional_cpp_items = additional_cpp_generator.generate();
        if let Some(additional_cpp_items) = additional_cpp_items {
            // When processing the bindings the first time, we discovered we wanted to add
            // more C++ (because you can never have too much C++.) Examples are field
            // accessor methods, or make_unique wrappers.
            // So, err, let's start all over again. Fun!
            let mut builder = self.make_bindgen_builder()?;
            info!(
                "Extra blocklist: {:?}",
                additional_cpp_items.extra_blocklist
            );
            for x in &additional_cpp_items.extra_blocklist {
                builder = builder.blacklist_item(x);
            }
            // TODO this clone is tedious
            let renames = additional_cpp_items.renames.clone();
            let bindings = self
                .inject_header_into_bindgen(builder, Some(additional_cpp_items))
                .generate()
                .map_err(Error::Bindgen)?;
            let bindings = self.parse_bindings(bindings)?;
            conversion = converter
                .convert(bindings, Some("autocxxgen.h"), &renames)
                .map_err(Error::Conversion)?;
        }

        let mut items = conversion.items;
        if let Some(itemmod) = self.get_preprocessor_defs_mod() {
            items.push(syn::Item::Mod(itemmod));
        }
        let mut new_bindings: ItemMod = parse_quote! {
            mod ffi {
            }
        };
        new_bindings.content.as_mut().unwrap().1.append(&mut items);
        info!(
            "New bindings:\n{}",
            rust_pretty_printer::pretty_print(&new_bindings.to_token_stream())
        );
        Ok(Some((new_bindings, additional_cpp_generator)))
    }

    /// Generate C++-side bindings for these APIs.
    pub fn generate_h_and_cxx(self) -> Result<GeneratedCpp> {
        let generation = self.do_generation()?;
        let mut files = Vec::new();
        match generation {
            None => {}
            Some((itemmod, additional_cpp_generator)) => {
                let rs = itemmod.into_token_stream();
                let opt = cxx_gen::Opt::default();
                let cxx_generated = cxx_gen::generate_header_and_cc(rs, &opt)
                    .map_err(Error::CxxGen)
                    .and_then(dump_generated_code)?;
                files.push(CppFilePair {
                    header: cxx_generated.header,
                    header_name: "cxxgen.h".to_string(),
                    implementation: cxx_generated.implementation,
                });

                match additional_cpp_generator.generate() {
                    None => {}
                    Some(additional_cpp) => {
                        // TODO should probably replace pragma once below with traditional include guards.
                        let declarations = format!("#pragma once\n{}", additional_cpp.declarations);
                        files.push(CppFilePair {
                            header: declarations.as_bytes().to_vec(),
                            header_name: "autocxxgen.h".to_string(),
                            implementation: additional_cpp.definitions.as_bytes().to_vec(),
                        });
                    }
                }
            }
        };
        Ok(GeneratedCpp(files))
    }

    /// Get the configured include directories.
    pub fn include_dirs(&self) -> Result<Vec<PathBuf>> {
        self.determine_incdirs()
    }
}

#[cfg(test)]
mod tests {
    use crate::TypeName;

    #[test]
    fn test_typename() {
        let s = proc_macro2::Span::call_site();
        let id = syn::Ident::new("Bob", s);
        let tn = TypeName::from_ident(&id);
        assert_eq!(tn.to_ident(), id);
    }
}
<commit_msg>Adding __gnu to blocklist<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod additional_cpp_generator;
mod bridge_converter;
mod byvalue_checker;
mod parse;
mod preprocessor_parse_callbacks;
mod rust_pretty_printer;
mod types;

#[cfg(test)]
mod integration_tests;

use proc_macro2::TokenStream as TokenStream2;
use std::path::PathBuf;

use indoc::indoc;
use quote::ToTokens;
use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::{parse_quote, ItemMod, Macro};

use additional_cpp_generator::{AdditionalCpp, AdditionalCppGenerator};
use itertools::join;
use log::{debug, info, warn};
use preprocessor_parse_callbacks::{PreprocessorDefinitions, PreprocessorParseCallbacks};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Mutex;
use types::TypeName;

pub use parse::{parse_file, ParseError};

const BINDGEN_BLOCKLIST: &[&str] = &["std.*", "__gnu.*", ".*mbstate_t.*"];
pub struct CppFilePair {
    pub header: Vec<u8>,
    pub implementation: Vec<u8>,
    pub header_name: String,
}

pub struct GeneratedCpp(pub Vec<CppFilePair>);

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Bindgen(()),
    CxxGen(cxx_gen::Error),
    Parsing(syn::Error),
    NoAutoCxxInc,
    CouldNotCanoncalizeIncludeDir(PathBuf),
    Conversion(bridge_converter::ConvertError),
}

pub type Result<T, E = Error> = std::result::Result<T, E>;

pub enum CppInclusion {
    Define(String),
    Header(String),
}

/// Core of the autocxx engine.
/// TODO - consider whether this 'engine' crate should actually be a
/// directory of source symlinked from all the other sub-crates, so that
/// we avoid exposing an external interface from this code.
pub struct IncludeCpp {
    inclusions: Vec<CppInclusion>,
    allowlist: Vec<String>, // not TypeName as it may be functions or whatever.
    pod_types: Vec<TypeName>,
    preconfigured_inc_dirs: Option<std::ffi::OsString>,
    parse_only: bool,
    preprocessor_definitions: Rc<Mutex<PreprocessorDefinitions>>,
}

impl Parse for IncludeCpp {
    fn parse(input: ParseStream) -> ParseResult<Self> {
        Self::new_from_parse_stream(input)
    }
}

fn dump_generated_code(gen: cxx_gen::GeneratedCode) -> Result<cxx_gen::GeneratedCode> {
    info!(
        "CXX:\n{}",
        String::from_utf8(gen.implementation.clone()).unwrap()
    );
    info!(
        "header:\n{}",
        String::from_utf8(gen.header.clone()).unwrap()
    );
    Ok(gen)
}

/// Prelude of C++ for squirting into bindgen. This configures
/// bindgen to output simpler types to replace some STL types
/// that bindgen just can't cope with. Although we then replace
/// those types with cxx types (e.g. UniquePtr), this intermediate
/// step is still necessary because bindgen can't otherwise
/// give us the templated types (e.g. when faced with the STL
/// unique_ptr, bindgen would normally give us std_unique_ptr
/// as opposed to std_unique_ptr<T>.)
static PRELUDE: &str = indoc! {"
    /**
    *

    */
    template<typename T> class UniquePtr {
        T* ptr;
    };

    /**
    *

    */
    class CxxString {
        char* str_data;
    };
    \n"};

impl IncludeCpp {
    fn new_from_parse_stream(input: ParseStream) -> syn::Result<Self> {
        // Takes as inputs:
        // 1. List of headers to include
        // 2. List of #defines to include
        // 3. Allowlist

        let mut inclusions = Vec::new();
        let mut allowlist = Vec::new();
        let mut pod_types = Vec::new();
        let mut parse_only = false;

        while !input.is_empty() {
            let ident: syn::Ident = input.parse()?;
            if ident == "Header" {
                let args;
                syn::parenthesized!(args in input);
                let hdr: syn::LitStr = args.parse()?;
                inclusions.push(CppInclusion::Header(hdr.value()));
            } else if ident == "Allow" || ident == "AllowPOD" {
                let args;
                syn::parenthesized!(args in input);
                let allow: syn::LitStr = args.parse()?;
                allowlist.push(allow.value());
                if ident == "AllowPOD" {
                    pod_types.push(TypeName::new(&allow.value()));
                }
            } else if ident == "ParseOnly" {
                parse_only = true;
            } else {
                return Err(syn::Error::new(
                    ident.span(),
                    "expected Header, Allow or AllowPOD",
                ));
            }
            if input.is_empty() {
                break;
            }
            input.parse::<syn::Token![,]>()?;
        }

        Ok(IncludeCpp {
            inclusions,
            allowlist,
            pod_types,
            preconfigured_inc_dirs: None,
            parse_only,
            preprocessor_definitions: Rc::new(Mutex::new(PreprocessorDefinitions::new())),
        })
    }

    pub fn new_from_syn(mac: Macro) -> Result<Self> {
        mac.parse_body::<IncludeCpp>().map_err(Error::Parsing)
    }

    pub fn set_include_dirs<P: AsRef<std::ffi::OsStr>>(&mut self, include_dirs: P) {
        self.preconfigured_inc_dirs = Some(include_dirs.as_ref().into());
    }

    fn build_header(&self) -> String {
        join(
            self.inclusions.iter().map(|incl| match incl {
                CppInclusion::Define(symbol) => format!("#define {}\n", symbol),
                CppInclusion::Header(path) => format!("#include \"{}\"\n", path),
            }),
            "",
        )
    }

    fn determine_incdirs(&self) -> Result<Vec<PathBuf>> {
        let inc_dirs = match &self.preconfigured_inc_dirs {
            Some(d) => d.clone(),
            None => std::env::var_os("AUTOCXX_INC").ok_or(Error::NoAutoCxxInc)?,
        };
        let inc_dirs = std::env::split_paths(&inc_dirs);
        // TODO consider if we can or should look up the include path automatically
        // instead of requiring callers always to set AUTOCXX_INC.

        // On Windows, the canonical path begins with a UNC prefix that cannot be passed to
        // the MSVC compiler, so dunce::canonicalize() is used instead of std::fs::canonicalize()
        // See:
        // * https://github.com/dtolnay/cxx/pull/41
        // * https://github.com/alexcrichton/cc-rs/issues/169
        inc_dirs
            .map(|p| dunce::canonicalize(&p).map_err(|_| Error::CouldNotCanoncalizeIncludeDir(p)))
            .collect()
    }

    fn make_bindgen_builder(&self) -> Result<bindgen::Builder> {
        let inc_dirs = self.determine_incdirs()?;

        debug!("Inc dir: {:?}", inc_dirs);

        // TODO support different C++ versions
        let mut builder = bindgen::builder()
            .clang_args(&["-x", "c++", "-std=c++14"])
            .derive_copy(false)
            .derive_debug(false)
            .parse_callbacks(Box::new(PreprocessorParseCallbacks::new(
                self.preprocessor_definitions.clone(),
            )))
            .default_enum_style(bindgen::EnumVariation::Rust {
                non_exhaustive: false,
            })
            .layout_tests(false); // TODO revisit later
        for item in BINDGEN_BLOCKLIST.iter() {
            builder = builder.blacklist_item(*item);
        }

        for inc_dir in inc_dirs {
            // TODO work with OsStrs here to avoid the .display()
            builder = builder.clang_arg(format!("-I{}", inc_dir.display()));
        }

        // 3. Passes allowlist and other options to the bindgen::Builder equivalent
        //    to --output-style=cxx --allowlist=<as passed in>
        for a in &self.allowlist {
            // TODO - allowlist type/functions/separately
            builder = builder
                .whitelist_type(a)
                .whitelist_function(a)
                .whitelist_var(a);
        }

        Ok(builder)
    }

    fn inject_header_into_bindgen(
        &self,
        mut builder: bindgen::Builder,
        additional_cpp: Option<AdditionalCpp>,
    ) -> bindgen::Builder {
        let full_header = self.build_header();
        let more_decls = if let Some(additional_cpp) = additional_cpp {
            for a in additional_cpp.extra_allowlist {
                builder = builder.whitelist_function(a);
            }
            format!(
                "#include <memory>\n\n// Extra autocxx insertions:\n\n{}\n\n",
                additional_cpp.declarations
            )
        } else {
            String::new()
        };
        let full_header = format!("{}{}\n\n{}", PRELUDE, more_decls, full_header,);
        info!("Full header: {}", full_header);
        builder = builder.header_contents("example.hpp", &full_header);
        builder
    }

    pub fn generate_rs(&self) -> Result<TokenStream2> {
        let results = self.do_generation()?;
        Ok(match results {
            Some((itemmod, _)) => itemmod.to_token_stream(),
            None => TokenStream2::new(),
        })
    }

    fn get_preprocessor_defs_mod(&self) -> Option<ItemMod> {
        let another_ref = self.preprocessor_definitions.clone();
        let m = another_ref.try_lock().unwrap().to_mod();
        m
    }

    fn parse_bindings(&self, bindings: bindgen::Bindings) -> Result<ItemMod> {
        // This bindings object is actually a TokenStream internally and we're wasting
        // effort converting to and from string. We could enhance the bindgen API
        // in future.
        let bindings = bindings.to_string();
        // Manually add the mod ffi {} so that we can ask syn to parse
        // into a single construct.
        let bindings = format!("mod bindgen {{ {} }}", bindings);
        info!("Bindings: {}", bindings);
        syn::parse_str::<ItemMod>(&bindings).map_err(Error::Parsing)
    }

    fn generate_include_list(&self) -> Vec<String> {
        let mut include_list = Vec::new();
        for incl in &self.inclusions {
            match incl {
                CppInclusion::Header(ref hdr) => {
                    include_list.push(hdr.clone());
                }
                CppInclusion::Define(_) => warn!("Currently no way to define! within cxx"),
            }
        }
        include_list
    }

    fn do_generation(&self) -> Result<Option<(ItemMod, AdditionalCppGenerator)>> {
        // If we are in parse only mode, do nothing. This is used for
        // doc tests to ensure the parsing is valid, but we can't expect
        // valid C++ header files or linkers to allow a complete build.
        if self.parse_only {
            return Ok(None);
        }

        // 4. (also respects environment variables to pick up more headers,
        //     include paths and #defines)
        // Then:
        // 1. Builds an overall C++ header with all those #defines and #includes
        // 2. Passes it to bindgen::Builder::header
        let builder = self.make_bindgen_builder()?;
        let bindings = self
            .inject_header_into_bindgen(builder, None)
            .generate()
            .map_err(Error::Bindgen)?;
        let bindings = self.parse_bindings(bindings)?;

        let mut converter = bridge_converter::BridgeConverter::new(
            self.generate_include_list(),
            self.pod_types.clone(), // TODO take self by value to avoid clone.
        );

        let mut conversion = converter
            .convert(bindings, None, &HashMap::new())
            .map_err(Error::Conversion)?;
        let mut additional_cpp_generator = AdditionalCppGenerator::new(self.build_header());
        additional_cpp_generator.add_needs(conversion.additional_cpp_needs);
        let additional_cpp_items = additional_cpp_generator.generate();
        if let Some(additional_cpp_items) = additional_cpp_items {
            // When processing the bindings the first time, we discovered we wanted to add
            // more C++ (because you can never have too much C++.) Examples are field
            // accessor methods, or make_unique wrappers.
            // So, err, let's start all over again. Fun!
            let mut builder = self.make_bindgen_builder()?;
            info!(
                "Extra blocklist: {:?}",
                additional_cpp_items.extra_blocklist
            );
            for x in &additional_cpp_items.extra_blocklist {
                builder = builder.blacklist_item(x);
            }
            // TODO this clone is tedious
            let renames = additional_cpp_items.renames.clone();
            let bindings = self
                .inject_header_into_bindgen(builder, Some(additional_cpp_items))
                .generate()
                .map_err(Error::Bindgen)?;
            let bindings = self.parse_bindings(bindings)?;
            conversion = converter
                .convert(bindings, Some("autocxxgen.h"), &renames)
                .map_err(Error::Conversion)?;
        }

        let mut items = conversion.items;
        if let Some(itemmod) = self.get_preprocessor_defs_mod() {
            items.push(syn::Item::Mod(itemmod));
        }
        let mut new_bindings: ItemMod = parse_quote! {
            mod ffi {
            }
        };
        new_bindings.content.as_mut().unwrap().1.append(&mut items);
        info!(
            "New bindings:\n{}",
            rust_pretty_printer::pretty_print(&new_bindings.to_token_stream())
        );
        Ok(Some((new_bindings, additional_cpp_generator)))
    }

    /// Generate C++-side bindings for these APIs.
    pub fn generate_h_and_cxx(self) -> Result<GeneratedCpp> {
        let generation = self.do_generation()?;
        let mut files = Vec::new();
        match generation {
            None => {}
            Some((itemmod, additional_cpp_generator)) => {
                let rs = itemmod.into_token_stream();
                let opt = cxx_gen::Opt::default();
                let cxx_generated = cxx_gen::generate_header_and_cc(rs, &opt)
                    .map_err(Error::CxxGen)
                    .and_then(dump_generated_code)?;
                files.push(CppFilePair {
                    header: cxx_generated.header,
                    header_name: "cxxgen.h".to_string(),
                    implementation: cxx_generated.implementation,
                });

                match additional_cpp_generator.generate() {
                    None => {}
                    Some(additional_cpp) => {
                        // TODO should probably replace pragma once below with traditional include guards.
                        let declarations = format!("#pragma once\n{}", additional_cpp.declarations);
                        files.push(CppFilePair {
                            header: declarations.as_bytes().to_vec(),
                            header_name: "autocxxgen.h".to_string(),
                            implementation: additional_cpp.definitions.as_bytes().to_vec(),
                        });
                    }
                }
            }
        };
        Ok(GeneratedCpp(files))
    }

    /// Get the configured include directories.
    pub fn include_dirs(&self) -> Result<Vec<PathBuf>> {
        self.determine_incdirs()
    }
}

#[cfg(test)]
mod tests {
    use crate::TypeName;

    #[test]
    fn test_typename() {
        let s = proc_macro2::Span::call_site();
        let id = syn::Ident::new("Bob", s);
        let tn = TypeName::from_ident(&id);
        assert_eq!(tn.to_ident(), id);
    }
}
<|endoftext|>


<commit_before>extern crate kafka;

use kafka::client::KafkaClient;

/// This program demonstrates the low level api for fetching messages.
/// Please look at examles/consume.rs for an easier to use API.
fn main() {
    let broker = "localhost:9092";
    let topic = "my-topic";
    let partition = 0;
    let offset = 0;

    println!("About to fetch messages at {} from: {} (partition {}, offset {}) ",
        broker, topic, partition, offset);

    let mut client = KafkaClient::new(vec!(broker.to_owned()));
    if let Err(e) = client.load_metadata_all() {
        println!("Failed to load meta data from {}: {}", broker, e);
        return;
    }

    // ~ make sure to print out a warning message when the target
    // topic does not yet exist
    if !client.topic_partitions.contains_key(topic) {
        println!("No such topic at {}: {}", broker, topic);
        return;
    }

    match client.fetch_messages(topic.to_owned(), partition, offset) {
        Err(e) => {
            println!("Failed to fetch messages: {}", e);
        }
        Ok(msgs) => {
            for msg in msgs {
                println!("{:?}", msg);
            }
            println!("No more messages.");
        }
    }
}
<commit_msg>#! Fix interpreting fetch example<commit_after>extern crate kafka;

use kafka::client::KafkaClient;

/// This program demonstrates the low level api for fetching messages.
/// Please look at examles/consume.rs for an easier to use API.
fn main() {
    let broker = "localhost:9092";
    let topic = "my-topic";
    let partition = 0;
    let offset = 0;

    println!("About to fetch messages at {} from: {} (partition {}, offset {}) ",
        broker, topic, partition, offset);

    let mut client = KafkaClient::new(vec!(broker.to_owned()));
    if let Err(e) = client.load_metadata_all() {
        println!("Failed to load meta data from {}: {}", broker, e);
        return;
    }

    // ~ make sure to print out a warning message when the target
    // topic does not yet exist
    if !client.topic_partitions.contains_key(topic) {
        println!("No such topic at {}: {}", broker, topic);
        return;
    }

    match client.fetch_messages(topic, partition, offset) {
        Err(e) => {
            println!("Failed to fetch messages: {}", e);
        }
        Ok(msgs) => {
            for msg in msgs {
                println!("{:?}", msg);
            }
            println!("No more messages.");
        }
    }
}
<|endoftext|>


<commit_before>extern crate mpi;

use mpi::traits::*;

use mpi::topology::GroupRelation;

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let g1 = world.group();
    let g2 = world.group();

    assert_eq!(GroupRelation::Identical, g1.compare(&g2));
}
<commit_msg>Expand Group examples/tests.<commit_after>extern crate mpi;

use mpi::traits::*;
use mpi::topology::{GroupRelation, Rank};

fn main() {
    let universe = mpi::initialize().unwrap();
    let world = universe.world();

    let g = world.group();
    // Group accessors and Communicator accessors agree
    assert_eq!(world.size(), g.size());
    assert_eq!(world.rank(), g.rank().unwrap());

    // g == g
    assert_eq!(GroupRelation::Identical, g.compare(&g));

    let h = world.group();
    // h == g
    assert_eq!(GroupRelation::Identical, g.compare(&h));

    let i = g.union(&h);
    // g union h == g union g == g
    assert_eq!(GroupRelation::Identical, g.compare(&i));

    let empty = g.difference(&h);
    // g difference h == g difference h = empty Group
    assert_eq!(0, empty.size());

    // g intersection empty == empty Group
    assert_eq!(0, g.intersection(&empty).size());

    let first_half: Vec<Rank> = (0..g.size() / 2).collect();

    // f and s are first and second half of g
    let f = g.include(&first_half[..]);
    let s = g.exclude(&first_half[..]);
    // f != s
    assert_eq!(GroupRelation::Unequal, f.compare(&s));

    // g intersection f == f
    let f_ = g.intersection(&f);
    assert_eq!(GroupRelation::Identical, f.compare(&f_));
    // g intersection s == s
    let s_ = g.intersection(&s);
    assert_eq!(GroupRelation::Identical, s.compare(&s_));

    // g difference s == f
    let f__ = g.difference(&s);
    assert_eq!(GroupRelation::Identical, f.compare(&f__));
    // g difference f == s
    let s__ = g.difference(&f);
    assert_eq!(GroupRelation::Identical, s.compare(&s__));

    // f union s == g
    let fs = f.union(&s);
    assert_eq!(GroupRelation::Identical, g.compare(&fs));

    // f intersection s == empty Group
    let fs = f.intersection(&s);
    assert_eq!(GroupRelation::Identical, empty.compare(&fs));

    // rank is either in f or in s
    assert!((f.rank().is_some() && s.rank().is_none())
            ^ (f.rank().is_none() && s.rank().is_some()));

    // inverting rank mappings
    let rev: Vec<Rank> = (0..g.size()).rev().collect();
    let r = g.include(&rev[..]);
    assert_eq!(Some(rev[g.rank().unwrap() as usize]), r.translate_rank(g.rank().unwrap(), &g));
}
<|endoftext|>


<commit_before>//! Array type node attribute.

use std::fmt;
use std::marker::PhantomData;
use std::io;
use std::io::Read;
use byteorder::{ReadBytesExt, LittleEndian};
#[cfg(feature = "flate2")]
use flate2::read::ZlibDecoder;
#[cfg(feature = "libflate")]
use libflate::zlib;

use parser::binary::{BinaryParser, CountReader};
use parser::binary::error::{Result, Error, Warning};

/// Read array type attribute from the given parser.
pub fn read_array_attribute<R: Read>(
    parser: &mut BinaryParser<R>,
    type_code: u8
) -> Result<(ArrayAttribute<R>, u64)> {
    let header = try!(ArrayAttributeHeader::read_from_parser(parser));
    let current_pos = parser.source.count();
    let BinaryParser { ref mut source, ref mut warnings, .. } = *parser;
    let reader = try!(ArrayDecoder::new(source, &header));

    let value = match type_code {
        b'b' => ArrayAttribute::Bool(ArrayAttributeReader::new(&header, reader, warnings)),
        b'i' => ArrayAttribute::I32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'l' => ArrayAttribute::I64(ArrayAttributeReader::new(&header, reader, warnings)),
        b'f' => ArrayAttribute::F32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'd' => ArrayAttribute::F64(ArrayAttributeReader::new(&header, reader, warnings)),
        _ => unreachable!(),
    };
    Ok((value, current_pos + header.bytelen_elements as u64))
}

/// Header of an array attribute.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct ArrayAttributeHeader {
    /// Number of elements.
    num_elements: u32,
    /// Array encoding, i.e. compression method.
    encoding: u32,
    /// Length of the array (excluding this header) in bytes.
    bytelen_elements: u32,
}

impl ArrayAttributeHeader {
    fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> io::Result<Self> {
        let num_elements = try!(parser.source.read_u32());
        let encoding = try!(parser.source.read_u32());
        let bytelen_elements = try!(parser.source.read_u32());

        Ok(ArrayAttributeHeader {
            num_elements: num_elements,
            encoding: encoding,
            bytelen_elements: bytelen_elements,
        })
    }
}

/// Array type attribute.
#[derive(Debug)]
pub enum ArrayAttribute<'a, R: 'a> {
    /// Array of `bool`.
    Bool(ArrayAttributeReader<'a, R, bool>),
    /// Array of `i32`.
    I32(ArrayAttributeReader<'a, R, i32>),
    /// Array of `i64`.
    I64(ArrayAttributeReader<'a, R, i64>),
    /// Array of `f32`.
    F32(ArrayAttributeReader<'a, R, f32>),
    /// Array of `f64`.
    F64(ArrayAttributeReader<'a, R, f64>),
}

/// Reader of array attribute elements.
#[derive(Debug)]
pub struct ArrayAttributeReader<'a, R: 'a, T> {
    num_elements: u64,
    rest_elements: u64,
    reader: ArrayDecoder<'a, CountReader<R>>,
    warnings: &'a mut Vec<Warning>,
    _value_type: PhantomData<T>,
}

impl<'a, R: 'a + Read, T> ArrayAttributeReader<'a, R, T> {
    fn new<'b>(
        header: &'b ArrayAttributeHeader,
        reader: ArrayDecoder<'a, CountReader<R>>,
        warnings: &'a mut Vec<Warning>
    ) -> Self {
        ArrayAttributeReader {
            num_elements: header.num_elements as u64,
            rest_elements: header.num_elements as u64,
            reader: reader,
            warnings: warnings,
            _value_type: PhantomData,
        }
    }

    /// Returns number of elements.
    pub fn num_elements(&self) -> u64 {
        self.num_elements
    }

    /// Returns number of rest elements.
    pub fn rest_elements(&self) -> u64 {
        self.num_elements
    }
}

impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, bool> {
    type Item = io::Result<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest_elements == 0 {
            return None;
        }
        let raw = match self.reader.read_u8() {
            Ok(val) => val,
            Err(err) => return Some(Err(err)),
        };
        let val = (raw & 1) == 1;
        Some(Ok(val))
    }
}

macro_rules! impl_attr_array_iter {
    ($ty:ty, $f:ident) => {
        impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, $ty> {
            type Item = io::Result<$ty>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.rest_elements == 0 {
                    return None;
                }
                Some(self.reader.$f::<LittleEndian>())
            }
        }
    }
}

impl_attr_array_iter!(i32, read_i32);
impl_attr_array_iter!(i64, read_i64);
impl_attr_array_iter!(f32, read_f32);
impl_attr_array_iter!(f64, read_f64);

/// Attribute array decoder.
enum ArrayDecoder<'a, R: 'a> {
    /// Non-compressed stream.
    ///
    /// `encoding` == 0.
    Raw(io::Take<&'a mut R>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "flate2")]
    Zlib(ZlibDecoder<io::Take<&'a mut R>>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "libflate")]
    Zlib(zlib::Decoder<io::Take<&'a mut R>>),
}

impl<'a, R: 'a + Read> ArrayDecoder<'a, R> {
    fn new(reader: &'a mut R, header: &ArrayAttributeHeader) -> Result<Self> {
        match header.encoding {
            0 => Ok(ArrayDecoder::Raw(reader.take(header.bytelen_elements as u64))),
            #[cfg(feature = "flate2")]
            1 => Ok(ArrayDecoder::Zlib(ZlibDecoder::new(reader.take(header.bytelen_elements as u64)))),
            #[cfg(feature = "libflate")]
            1 => Ok(ArrayDecoder::Zlib(try!(zlib::Decoder::new(reader.take(header.bytelen_elements as u64))))),
            _ => Err(Error::UnknownArrayAttributeEncoding(header.encoding)),
        }
    }
}

impl<'a, R: 'a + Read> Read for ArrayDecoder<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            ArrayDecoder::Raw(ref mut reader) => reader.read(buf),
            #[cfg(feature = "flate2")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
            #[cfg(feature = "libflate")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
        }
    }
}

impl<'a, R: 'a> fmt::Debug for ArrayDecoder<'a, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "ArrayDecoder::{}",
               match *self {
                   ArrayDecoder::Raw(_) => "Raw",
                   #[cfg(feature = "flate2")]
                   ArrayDecoder::Zlib(_) => "Zlib",
                   #[cfg(feature = "libflate")]
                   ArrayDecoder::Zlib(_) => "Zlib",
               })
    }
}
<commit_msg>Decrement rest elements count of array attribute corretly<commit_after>//! Array type node attribute.

use std::fmt;
use std::marker::PhantomData;
use std::io;
use std::io::Read;
use byteorder::{ReadBytesExt, LittleEndian};
#[cfg(feature = "flate2")]
use flate2::read::ZlibDecoder;
#[cfg(feature = "libflate")]
use libflate::zlib;

use parser::binary::{BinaryParser, CountReader};
use parser::binary::error::{Result, Error, Warning};

/// Read array type attribute from the given parser.
pub fn read_array_attribute<R: Read>(
    parser: &mut BinaryParser<R>,
    type_code: u8
) -> Result<(ArrayAttribute<R>, u64)> {
    let header = try!(ArrayAttributeHeader::read_from_parser(parser));
    let current_pos = parser.source.count();
    let BinaryParser { ref mut source, ref mut warnings, .. } = *parser;
    let reader = try!(ArrayDecoder::new(source, &header));

    let value = match type_code {
        b'b' => ArrayAttribute::Bool(ArrayAttributeReader::new(&header, reader, warnings)),
        b'i' => ArrayAttribute::I32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'l' => ArrayAttribute::I64(ArrayAttributeReader::new(&header, reader, warnings)),
        b'f' => ArrayAttribute::F32(ArrayAttributeReader::new(&header, reader, warnings)),
        b'd' => ArrayAttribute::F64(ArrayAttributeReader::new(&header, reader, warnings)),
        _ => unreachable!(),
    };
    Ok((value, current_pos + header.bytelen_elements as u64))
}

/// Header of an array attribute.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct ArrayAttributeHeader {
    /// Number of elements.
    num_elements: u32,
    /// Array encoding, i.e. compression method.
    encoding: u32,
    /// Length of the array (excluding this header) in bytes.
    bytelen_elements: u32,
}

impl ArrayAttributeHeader {
    fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> io::Result<Self> {
        let num_elements = try!(parser.source.read_u32());
        let encoding = try!(parser.source.read_u32());
        let bytelen_elements = try!(parser.source.read_u32());

        Ok(ArrayAttributeHeader {
            num_elements: num_elements,
            encoding: encoding,
            bytelen_elements: bytelen_elements,
        })
    }
}

/// Array type attribute.
#[derive(Debug)]
pub enum ArrayAttribute<'a, R: 'a> {
    /// Array of `bool`.
    Bool(ArrayAttributeReader<'a, R, bool>),
    /// Array of `i32`.
    I32(ArrayAttributeReader<'a, R, i32>),
    /// Array of `i64`.
    I64(ArrayAttributeReader<'a, R, i64>),
    /// Array of `f32`.
    F32(ArrayAttributeReader<'a, R, f32>),
    /// Array of `f64`.
    F64(ArrayAttributeReader<'a, R, f64>),
}

/// Reader of array attribute elements.
#[derive(Debug)]
pub struct ArrayAttributeReader<'a, R: 'a, T> {
    num_elements: u64,
    rest_elements: u64,
    reader: ArrayDecoder<'a, CountReader<R>>,
    warnings: &'a mut Vec<Warning>,
    _value_type: PhantomData<T>,
}

impl<'a, R: 'a + Read, T> ArrayAttributeReader<'a, R, T> {
    fn new<'b>(
        header: &'b ArrayAttributeHeader,
        reader: ArrayDecoder<'a, CountReader<R>>,
        warnings: &'a mut Vec<Warning>
    ) -> Self {
        ArrayAttributeReader {
            num_elements: header.num_elements as u64,
            rest_elements: header.num_elements as u64,
            reader: reader,
            warnings: warnings,
            _value_type: PhantomData,
        }
    }

    /// Returns number of elements.
    pub fn num_elements(&self) -> u64 {
        self.num_elements
    }

    /// Returns number of rest elements.
    pub fn rest_elements(&self) -> u64 {
        self.num_elements
    }
}

impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, bool> {
    type Item = io::Result<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest_elements == 0 {
            return None;
        }
        self.rest_elements -= 1;
        let raw = match self.reader.read_u8() {
            Ok(val) => val,
            Err(err) => return Some(Err(err)),
        };
        let val = (raw & 1) == 1;
        Some(Ok(val))
    }
}

macro_rules! impl_attr_array_iter {
    ($ty:ty, $f:ident) => {
        impl<'a, R: 'a + Read> Iterator for ArrayAttributeReader<'a, R, $ty> {
            type Item = io::Result<$ty>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.rest_elements == 0 {
                    return None;
                }
                self.rest_elements -= 1;
                Some(self.reader.$f::<LittleEndian>())
            }
        }
    }
}

impl_attr_array_iter!(i32, read_i32);
impl_attr_array_iter!(i64, read_i64);
impl_attr_array_iter!(f32, read_f32);
impl_attr_array_iter!(f64, read_f64);

/// Attribute array decoder.
enum ArrayDecoder<'a, R: 'a> {
    /// Non-compressed stream.
    ///
    /// `encoding` == 0.
    Raw(io::Take<&'a mut R>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "flate2")]
    Zlib(ZlibDecoder<io::Take<&'a mut R>>),
    /// Zlib-compressed stream.
    ///
    /// `encoding` == 1.
    #[cfg(feature = "libflate")]
    Zlib(zlib::Decoder<io::Take<&'a mut R>>),
}

impl<'a, R: 'a + Read> ArrayDecoder<'a, R> {
    fn new(reader: &'a mut R, header: &ArrayAttributeHeader) -> Result<Self> {
        match header.encoding {
            0 => Ok(ArrayDecoder::Raw(reader.take(header.bytelen_elements as u64))),
            #[cfg(feature = "flate2")]
            1 => Ok(ArrayDecoder::Zlib(ZlibDecoder::new(reader.take(header.bytelen_elements as u64)))),
            #[cfg(feature = "libflate")]
            1 => Ok(ArrayDecoder::Zlib(try!(zlib::Decoder::new(reader.take(header.bytelen_elements as u64))))),
            _ => Err(Error::UnknownArrayAttributeEncoding(header.encoding)),
        }
    }
}

impl<'a, R: 'a + Read> Read for ArrayDecoder<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            ArrayDecoder::Raw(ref mut reader) => reader.read(buf),
            #[cfg(feature = "flate2")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
            #[cfg(feature = "libflate")]
            ArrayDecoder::Zlib(ref mut reader) => reader.read(buf),
        }
    }
}

impl<'a, R: 'a> fmt::Debug for ArrayDecoder<'a, R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "ArrayDecoder::{}",
               match *self {
                   ArrayDecoder::Raw(_) => "Raw",
                   #[cfg(feature = "flate2")]
                   ArrayDecoder::Zlib(_) => "Zlib",
                   #[cfg(feature = "libflate")]
                   ArrayDecoder::Zlib(_) => "Zlib",
               })
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::thread::Builder;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();

    // Right now the algorithm in cargo::core::resolve is pretty recursive and
    // runs the risk of blowing the stack. Platforms tend to have different
    // stack limits by default (I just witnessed 512K on OSX and 2MB on Linux)
    // so to get a consistent experience just spawn ourselves with a large stack
    // size.
    let stack_size = env::var("CARGO_STACK_SIZE").ok()
                         .and_then(|s| s.parse().ok())
                         .unwrap_or(8 * 1024 * 1024); // 8MB
    Builder::new().stack_size(stack_size).spawn(|| {
        execute_main_without_stdin(execute, true, USAGE)
    }).unwrap().join().unwrap();
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(rustc);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Don't use an 8MB stack any more<commit_after>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(rustc);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use fuzzy::{matches, Score};

/// A Choice wraps a String and it's calculated Score
pub struct Choice(String, Score);

impl Choice {
    /// Creates a new Choice if the needle matches the haystack.
    ///
    /// # Examples
    ///
    /// ```
    /// use rff::choice::Choice;
    /// assert!(Choice::new("amo", String::from("app/models/order")).is_some());
    /// ```
    pub fn new(needle: &str, haystack: String) -> Option<Choice> {
        if matches(&needle, &haystack) {
            let score = Score::calculate(&needle, &haystack);
            Some(Choice(haystack, score))
        } else {
            None
        }
    }
}

impl PartialEq for Choice {
    fn eq(&self, other: &Choice) -> bool {
        self.1.eq(&other.1)
    }
}

impl PartialOrd for Choice {
    fn partial_cmp(&self, other: &Choice) -> Option<Ordering> {
        self.1.partial_cmp(&other.1)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[bench]
    fn create_choice(b: &mut Bencher) {
        b.iter(|| Choice::new("app/models", String::from("app/models/order")))
    }

    #[test]
    fn partial_cmp() {
        let a = Choice::new("amor", String::from("app/models/order")).unwrap();
        let b = Choice::new("amor", String::from("app/models/zrder")).unwrap();

        assert!(a > b);
    }
}
<commit_msg>Implement Display for Choice<commit_after>use std::cmp::Ordering;
use std::fmt;
use fuzzy::{matches, Score};

/// A Choice wraps a String and it's calculated Score
pub struct Choice(String, Score);

impl Choice {
    /// Creates a new Choice if the needle matches the haystack.
    ///
    /// # Examples
    ///
    /// ```
    /// use rff::choice::Choice;
    /// assert!(Choice::new("amo", String::from("app/models/order")).is_some());
    /// ```
    pub fn new(needle: &str, haystack: String) -> Option<Choice> {
        if matches(&needle, &haystack) {
            let score = Score::calculate(&needle, &haystack);
            Some(Choice(haystack, score))
        } else {
            None
        }
    }
}

impl PartialEq for Choice {
    fn eq(&self, other: &Choice) -> bool {
        self.1.eq(&other.1)
    }
}

impl PartialOrd for Choice {
    fn partial_cmp(&self, other: &Choice) -> Option<Ordering> {
        self.1.partial_cmp(&other.1)
    }
}

impl fmt::Display for Choice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[bench]
    fn create_choice(b: &mut Bencher) {
        b.iter(|| Choice::new("app/models", String::from("app/models/order")))
    }

    #[test]
    fn partial_cmp() {
        let a = Choice::new("amor", String::from("app/models/order")).unwrap();
        let b = Choice::new("amor", String::from("app/models/zrder")).unwrap();

        assert!(a > b);
    }

    #[test]
    fn display() {
        let choice = Choice::new("amor", String::from("app/models/order")).unwrap();
        assert_eq!(format!("{}", choice), "app/models/order");
    }
}
<|endoftext|>


<commit_before>#![feature(allocator_api)]
#![feature(const_fn)]
#![feature(integer_atomics)]
#![forbid(private_in_public)]
#![forbid(bare_trait_objects)]
#![deny(unused_assignments)]
#![no_std]

extern crate spin;

use core::alloc::{AllocErr, AllocInit, AllocRef, GlobalAlloc, Layout, MemoryBlock};
use core::ptr::NonNull;

pub const HEAP_START: u64 = 0x4000_0000; // At 1 GiB
pub const HEAP_SIZE: u64 = 0x640_0000; // 100 MiB heap

use spin::Mutex;

/// Align downwards. Returns the greatest x with alignment `align`
/// so that x <= addr. The alignment must be a power of 2.
pub fn align_down(addr: u64, align: u64) -> u64 {
    if align.is_power_of_two() {
        addr & !(align - 1)
    } else if align == 0 {
        addr
    } else {
        panic!("`align` must be a power of 2");
    }
}

/// Align upwards. Returns the smallest x with alignment `align`
/// so that x >= addr. The alignment must be a power of 2.
pub fn align_up(addr: u64, align: u64) -> u64 {
    align_down(addr + align - 1, align)
}

use core::sync::atomic::{AtomicU64, Ordering};

/// A simple allocator that allocates memory linearly and ignores freed memory.
#[derive(Debug)]
pub struct BumpAllocator {
    heap_start: u64,
    heap_end: u64,
    next: AtomicU64,
}

impl BumpAllocator {
    pub const fn new(heap_start: u64, heap_end: u64) -> Self {
        Self {
            heap_start,
            heap_end,
            next: AtomicU64::new(heap_start),
        }
    }
}

unsafe impl<'a> AllocRef for &'a BumpAllocator {
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
        assert!(init == AllocInit::Uninitialized);
        loop {
            // load current state of the `next` field
            let current_next = self.next.load(Ordering::Relaxed);
            let alloc_start = align_up(current_next, layout.align() as u64);
            let alloc_end = alloc_start.saturating_add(layout.size() as u64);

            if alloc_end <= self.heap_end {
                // update the `next` pointer if it still has the value `current_next`
                let next_now =
                    self.next
                        .compare_and_swap(current_next, alloc_end, Ordering::Relaxed);
                if next_now == current_next {
                    // next address was successfully updated, allocation succeeded
                    return Ok(MemoryBlock {
                        ptr: NonNull::new(alloc_start as *mut _).expect("Tried to alloc null ptr"),
                        size: (alloc_end - alloc_start) as usize,
                    });
                }
            } else {
                return Err(AllocErr);
            }
        }
    }

    unsafe fn dealloc(&mut self, _ptr: NonNull<u8>, _layout: Layout) {
        // do nothing, leak memory
    }
}

pub struct GlobAlloc {
    alloc: Mutex<BumpAllocator>,
}
impl GlobAlloc {
    pub const fn new(alloc: BumpAllocator) -> Self {
        Self {
            alloc: Mutex::new(alloc),
        }
    }
}
unsafe impl GlobalAlloc for GlobAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let alloc = self.alloc.lock();
        (&*alloc)
            .alloc(layout, AllocInit::Uninitialized)
            .expect("Could not allocate")
            .ptr
            .as_mut()
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        let alloc = self.alloc.lock();
        (&*alloc).dealloc(
            NonNull::new(ptr as *mut _).expect("Cannot deallocate null pointer"),
            layout,
        );
    }
}
<commit_msg>Fix possible allocator bugs (ZST and Atomics)<commit_after>#![feature(allocator_api)]
#![feature(const_fn)]
#![feature(integer_atomics)]
#![forbid(private_in_public)]
#![forbid(bare_trait_objects)]
#![deny(unused_assignments)]
#![no_std]

extern crate spin;

use core::alloc::{AllocErr, AllocInit, AllocRef, GlobalAlloc, Layout, MemoryBlock};
use core::ptr::NonNull;

pub const HEAP_START: u64 = 0x4000_0000; // At 1 GiB
pub const HEAP_SIZE: u64 = 0x640_0000; // 100 MiB heap

use spin::Mutex;

/// Align downwards. Returns the greatest x with alignment `align`
/// so that x <= addr. The alignment must be a power of 2.
pub fn align_down(addr: u64, align: u64) -> u64 {
    if align.is_power_of_two() {
        addr & !(align - 1)
    } else if align == 0 {
        addr
    } else {
        panic!("`align` must be a power of 2");
    }
}

/// Align upwards. Returns the smallest x with alignment `align`
/// so that x >= addr. The alignment must be a power of 2.
pub fn align_up(addr: u64, align: u64) -> u64 {
    align_down(addr + align - 1, align)
}

use core::sync::atomic::{AtomicU64, Ordering};

/// A simple allocator that allocates memory linearly and ignores freed memory.
#[derive(Debug)]
pub struct BumpAllocator {
    heap_start: u64,
    heap_end: u64,
    next: AtomicU64,
}

impl BumpAllocator {
    pub const fn new(heap_start: u64, heap_end: u64) -> Self {
        Self {
            heap_start,
            heap_end,
            next: AtomicU64::new(heap_start),
        }
    }
}

unsafe impl<'a> AllocRef for &'a BumpAllocator {
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
        assert!(init == AllocInit::Uninitialized);
        assert!(layout.size() > 0);
        loop {
            // load current state of the `next` field
            let current_next = self.next.load(Ordering::SeqCst);
            let alloc_start = align_up(current_next, layout.align() as u64);
            let alloc_end = alloc_start.saturating_add(layout.size() as u64);

            if alloc_end < self.heap_end {
                // update the `next` pointer if it still has the value `current_next`
                let next_now =
                    self.next
                        .compare_and_swap(current_next, alloc_end, Ordering::SeqCst);
                if next_now == current_next {
                    // next address was successfully updated, allocation succeeded
                    return Ok(MemoryBlock {
                        ptr: NonNull::new(alloc_start as *mut _).expect("Tried to alloc null ptr"),
                        size: (alloc_end - alloc_start) as usize,
                    });
                }
            } else {
                return Err(AllocErr);
            }
        }
    }

    unsafe fn dealloc(&mut self, _ptr: NonNull<u8>, _layout: Layout) {
        // do nothing, leak memory
    }
}

pub struct GlobAlloc {
    alloc: Mutex<BumpAllocator>,
}
impl GlobAlloc {
    pub const fn new(alloc: BumpAllocator) -> Self {
        Self {
            alloc: Mutex::new(alloc),
        }
    }
}
unsafe impl GlobalAlloc for GlobAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let alloc = self.alloc.lock();
        (&*alloc)
            .alloc(layout, AllocInit::Uninitialized)
            .expect("Could not allocate")
            .ptr
            .as_mut()
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        let alloc = self.alloc.lock();
        (&*alloc).dealloc(
            NonNull::new(ptr as *mut _).expect("Cannot deallocate null pointer"),
            layout,
        );
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use super::{git2, GitStatuses, GitError, GitReference, GitBranch};

pub struct GitRepo {
    repo: git2::Repository,
    path: PathBuf,
}

//unsafe impl Send for GitRepo {}

impl GitRepo {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, GitError> {
        let path_ref = path.as_ref();
        let repo = git2::Repository::open(path_ref)
            .map_err(|_| GitError::OpenRepo)?;

        Ok(GitRepo {
               repo: repo,
               path: path_ref.to_owned(),
           })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn statuses(&self) -> Result<GitStatuses, GitError> {
        // self.repo.graph_ahead_behind

        let mut opts = git2::StatusOptions::new();

        opts.include_ignored(false)
            .include_untracked(true)
            .recurse_untracked_dirs(true)
            .include_unreadable_as_untracked(true)
            .disable_pathspec_match(true)
            .exclude_submodules(true);

        let statuses = self.repo
            .statuses(Some(&mut opts))
            .map_err(|_| GitError::Status)?;

        Ok(GitStatuses::new(statuses))
    }

    pub fn reset(&self) -> Result<GitReference, GitError> {
        let head = self.repo.head().map_err(|_| GitError::Reset)?;
        let obj = head.peel(git2::ObjectType::Any)
            .map_err(|_| GitError::Reset)?;

        let mut builder = git2::build::CheckoutBuilder::new();
        let mut options = builder
            .remove_untracked(true)
            .progress(|path, a, b| {
                          if path == None {
                              return;
                          }

                          println!("{:?} {:?} {:?}", path, a, b)
                      });

        self.repo
            .reset(&obj, git2::ResetType::Hard, Some(options))
            .map_err(|_| GitError::Reset)?;

        Ok(GitReference::new(head))
    }

    pub fn checkout(&self, branch_name: &str) -> Result<(), GitError> {
        let branch_type = match branch_name.find("origin/") {
            Some(_) => git2::BranchType::Remote,
            None => git2::BranchType::Local,
        };

        let branch = self.repo
            .find_branch(branch_name, branch_type)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        println!("  {} {}",
                 match branch_type {
                     git2::BranchType::Local => " [Local]",
                     git2::BranchType::Remote => "[Remote]",
                 },
                 branch_name);

        Ok(())
    }
}<commit_msg>Implemented Send + Sync for GitRepo<commit_after>use std::path::{Path, PathBuf};
use super::{git2, GitStatuses, GitError, GitReference, GitBranch};

pub struct GitRepo {
    repo: git2::Repository,
    path: PathBuf,
}

unsafe impl Send for GitRepo {}
unsafe impl Sync for GitRepo {}

impl GitRepo {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, GitError> {
        let path_ref = path.as_ref();
        let repo = git2::Repository::open(path_ref)
            .map_err(|_| GitError::OpenRepo)?;

        Ok(GitRepo {
               repo: repo,
               path: path_ref.to_owned(),
           })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn statuses(&self) -> Result<GitStatuses, GitError> {
        // self.repo.graph_ahead_behind

        let mut opts = git2::StatusOptions::new();

        opts.include_ignored(false)
            .include_untracked(true)
            .recurse_untracked_dirs(true)
            .include_unreadable_as_untracked(true)
            .disable_pathspec_match(true)
            .exclude_submodules(true);

        let statuses = self.repo
            .statuses(Some(&mut opts))
            .map_err(|_| GitError::Status)?;

        Ok(GitStatuses::new(statuses))
    }

    pub fn reset(&self) -> Result<GitReference, GitError> {
        let head = self.repo.head().map_err(|_| GitError::Reset)?;
        let obj = head.peel(git2::ObjectType::Any)
            .map_err(|_| GitError::Reset)?;

        let mut builder = git2::build::CheckoutBuilder::new();
        let mut options = builder
            .remove_untracked(true)
            .progress(|path, a, b| {
                          if path == None {
                              return;
                          }

                          println!("{:?} {:?} {:?}", path, a, b)
                      });

        self.repo
            .reset(&obj, git2::ResetType::Hard, Some(options))
            .map_err(|_| GitError::Reset)?;

        Ok(GitReference::new(head))
    }

    pub fn checkout(&self, branch_name: &str) -> Result<(), GitError> {
        let branch_type = match branch_name.find("origin/") {
            Some(_) => git2::BranchType::Remote,
            None => git2::BranchType::Local,
        };

        let branch = self.repo
            .find_branch(branch_name, branch_type)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        println!("  {} {}",
                 match branch_type {
                     git2::BranchType::Local => " [Local]",
                     git2::BranchType::Remote => "[Remote]",
                 },
                 branch_name);

        Ok(())
    }
}<|endoftext|>


<commit_before>//! Check that we correctly lint procedural macros.

#![crate_type = "proc-macro"]

#[allow(dead_code)]
fn f() {
    let _x = 3.14;
}
<commit_msg>Mark rust source file as non-executable.<commit_after>//! Check that we correctly lint procedural macros.

#![crate_type = "proc-macro"]

#[allow(dead_code)]
fn f() {
    let _x = 3.14;
}
<|endoftext|>