<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![forbid(unsafe_code)]

mod depfile;

use autocxx_engine::{parse_file, HeaderNamer, RebuildDependencyRecorder};
use clap::{crate_authors, crate_version, App, Arg, ArgGroup};
use depfile::Depfile;
use miette::IntoDiagnostic;
use proc_macro2::TokenStream;
use quote::ToTokens;
use std::cell::RefCell;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::rc::Rc;
use std::{cell::Cell, fs::File, path::Path};

pub(crate) static BLANK: &str = "// Blank autocxx placeholder";

static LONG_HELP: &str = "
Command line utility to expand the Rust 'autocxx' include_cpp! directive.

This tool can generate both the C++ and Rust side binding code for
a Rust file containing an include_cpp! directive.

If you're using cargo, don't use this: use autocxx_build instead,
which is much easier to include in build.rs build scripts. You'd likely
use this tool only if you're using some non-Cargo build system. If
that's you, read on.

This tool has three modes: generate the C++; generate a new Rust file where
the include_cpp! directive is *replaced* with bindings, or generate
a Rust file which can be included by the autocxx_macro. You may specify
multiple modes, or of course, invoke the tool multiple times.

In any mode, you'll need to pass the source Rust file name and the C++
include path.

For generation of the Rust side bindings, here's how to choose between
the two modes. If you're copying the entire Rust crate to a different
location during your build process, you may as well use --gen-rs-complete
to generate a whole new replacement .rs file with the autocxx
include_cpp! macro expanded.

But in most build systems, you won't be copying all the crate source
to a new location. In such a case, you should use --gen-rs-include
which will generate a file that will be included by the autocxx_macro
crate.

The second decision you must make is naming of the output files.
If your build system is able to cope with autocxx_gen building
unpredictable filenames, then:
a) set AUTOCXX_RS when using autocxx_macro
b) build all *.cc files produced by this tool.

If your build system requires each build rule to make precise filenames
known in advance, then you will need to:
a) Use `--generate-exact <N> --gen-rs-complete`
b) Teach your build system that the C++ files to compile are named `gen0.h`,
   `gen0.cc`, `gen1.h`, `gen1.cc`, etc (through `N`), corresponding
   to each `include_cpp!` section, plus 'cxxgen.h`. `gen.complete.rs` will also
   be generated and should be compiled _instead of_ the original Rust file.
c) If `N` is bigger than the number of files needed, extra no-op files will
   be emitted. These may still be compiled normally, but won't do anything. If
   `N` is smaller than the number of files needed, generation will fail.

Note that there is currently no way to teach each `include_cpp!` section
which `.include.rs` file to use, so the only way to get fixed output paths is
with `--gen-rs-complete`. There are always multiple `.cc` files (even with just
a single `include_cpp!` section), and we always generate the same number of each
type of file.
";

fn main() -> miette::Result<()> {
    let matches = App::new("autocxx-gen")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generates bindings files from Rust files that contain include_cpp! macros")
        .long_about(LONG_HELP)
        .arg(
            Arg::with_name("INPUT")
                .help("Sets the input .rs file to use")
                .required(true)
                .index(1),
        )
        .arg(
            Arg::with_name("outdir")
                .short("o")
                .long("outdir")
                .value_name("PATH")
                .help("output directory path")
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name("inc")
                .short("I")
                .long("inc")
                .multiple(true)
                .number_of_values(1)
                .value_name("INCLUDE DIRS")
                .help("include path")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cpp-extension")
                .long("cpp-extension")
                .value_name("EXTENSION")
                .default_value("cc")
                .help("C++ filename extension")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("gen-cpp")
                .long("gen-cpp")
                .help("whether to generate C++ implementation and header files")
        )
        .arg(
            Arg::with_name("gen-rs-complete")
                .long("gen-rs-complete")
                .help("whether to generate a Rust file replacing the original file (suffix will be .complete.rs)")
        )
        .arg(
            Arg::with_name("gen-rs-include")
                .long("gen-rs-include")
                .help("whether to generate Rust files for inclusion using autocxx_macro (suffix will be .include.rs)")
        )
        .group(ArgGroup::with_name("mode")
            .required(true)
            .multiple(true)
            .arg("gen-cpp")
            .arg("gen-rs-complete")
            .arg("gen-rs-include")
        )
        .arg(
            Arg::with_name("skip-cxx-gen")
                .long("skip-cxx-gen")
                .help("Skip performing C++ codegen for #[cxx::bridge] blocks. Only applies for --gen-cpp")
                .requires("gen-cpp")
        )
        .arg(
            Arg::with_name("generate-exact")
                .long("generate-exact")
                .value_name("NUM")
                .help("assume and ensure there are exactly NUM bridge blocks in the file. Only applies for --gen-cpp or --gen-rs-include")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("fix-rs-include-name")
                .long("fix-rs-include-name")
                .help("Make the name of the .rs file predictable. You must set AUTOCXX_RS_FILE during Rust build time to educate autocxx_macro about your choice.")
                .requires("gen-rs-include")
        )
        .arg(
            Arg::with_name("auto-allowlist")
                .long("auto-allowlist")
                .help("Dynamically construct allowlist from real uses of APIs.")
        )
        .arg(
            Arg::with_name("suppress-system-headers")
                .long("suppress-system-headers")
                .help("Do not refer to any system headers from generated code. May be useful for minimization.")
        )
        .arg(
            Arg::with_name("cxx-impl-annotations")
                .long("cxx-impl-annotations")
                .value_name("ANNOTATION")
                .help("prefix for symbols to be exported from C++ bindings, e.g. __attribute__ ((visibility (\"default\")))")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cxx-h-path")
                .long("cxx-h-path")
                .value_name("PREFIX")
                .help("prefix for path to cxx.h (from the cxx crate) within #include statements. Must end in /")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cxxgen-h-path")
                .long("cxxgen-h-path")
                .value_name("PREFIX")
                .help("prefix for path to cxxgen.h (which we generate into the output directory) within #include statements. Must end in /")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("depfile")
                .long("depfile")
                .value_name("DEPFILE")
                .help("A .d file to write")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("clang-args")
                .last(true)
                .multiple(true)
                .help("Extra arguments to pass to Clang"),
        )
        .get_matches();

    env_logger::builder().init();
    let mut parsed_file = parse_file(
        matches.value_of("INPUT").unwrap(),
        matches.is_present("auto-allowlist"),
    )?;
    let incs = matches
        .values_of("inc")
        .unwrap_or_default()
        .map(PathBuf::from)
        .collect();
    let extra_clang_args: Vec<_> = matches
        .values_of("clang-args")
        .unwrap_or_default()
        .collect();
    let suppress_system_headers = matches.is_present("suppress-system-headers");
    let desired_number = matches
        .value_of("generate-exact")
        .map(|s| s.parse::<usize>().unwrap());
    let header_counter = Cell::new(0);
    let header_namer = if desired_number.is_some() {
        HeaderNamer(Box::new(|_| {
            let r = format!("gen{}.h", header_counter.get());
            header_counter.set(header_counter.get() + 1);
            r
        }))
    } else {
        Default::default()
    };
    let cpp_codegen_options = autocxx_engine::CppCodegenOptions {
        suppress_system_headers,
        cxx_impl_annotations: get_option_string("cxx-impl-annotations", &matches),
        path_to_cxx_h: get_option_string("cxx-h-path", &matches),
        path_to_cxxgen_h: get_option_string("cxxgen-h-path", &matches),
        skip_cxx_gen: matches.is_present("skip-cxx-gen"),
        header_namer,
    };
    let depfile = match matches.value_of("depfile") {
        None => None,
        Some(depfile_path) => {
            let depfile_path = PathBuf::from(depfile_path);
            Some(Rc::new(RefCell::new(
                Depfile::new(&depfile_path).into_diagnostic()?,
            )))
        }
    };
    let dep_recorder: Option<Box<dyn RebuildDependencyRecorder>> = depfile
        .as_ref()
        .map(|rc| get_dependency_recorder(rc.clone()));
    parsed_file.resolve_all(incs, &extra_clang_args, dep_recorder, &cpp_codegen_options)?;
    let outdir: PathBuf = matches.value_of_os("outdir").unwrap().into();
    if matches.is_present("gen-cpp") {
        let cpp = matches.value_of("cpp-extension").unwrap();
        let mut counter = 0usize;
        for include_cxx in parsed_file.get_cpp_buildables() {
            let generations = include_cxx
                .generate_h_and_cxx(&cpp_codegen_options)
                .expect("Unable to generate header and C++ code");
            for pair in generations.0 {
                let cppname = format!("gen{}.{}", counter, cpp);
                add_output(&depfile, &outdir, &cppname);
                add_output(&depfile, &outdir, &pair.header_name);
                write_to_file(&outdir, cppname, &pair.implementation.unwrap_or_default());
                write_to_file(&outdir, pair.header_name, &pair.header);
                counter += 1;
            }
        }
        write_placeholders(&outdir, counter, desired_number, cpp);
    }
    drop(cpp_codegen_options);
    write_placeholders(&outdir, header_counter.into_inner(), desired_number, "h");
    if matches.is_present("gen-rs-complete") {
        let mut ts = TokenStream::new();
        parsed_file.to_tokens(&mut ts);
        write_to_file(
            &outdir,
            "gen.complete.rs".to_string(),
            ts.to_string().as_bytes(),
        );
    }
    if matches.is_present("gen-rs-include") {
        let autocxxes = parsed_file.get_rs_buildables();
        let mut counter = 0usize;
        for include_cxx in autocxxes {
            let ts = include_cxx.generate_rs();
            let fname = if matches.is_present("fix-rs-include-name") {
                format!("gen{}.include.rs", counter)
            } else {
                include_cxx.get_rs_filename()
            };
            add_output(&depfile, &outdir, &fname);
            write_to_file(&outdir, fname, ts.to_string().as_bytes());
            counter += 1;
        }
        if matches.is_present("fix-rs-include-name") {
            write_placeholders(&outdir, counter, desired_number, "include.rs");
        }
    }
    if let Some(depfile) = depfile {
        depfile.borrow_mut().write().into_diagnostic()?;
    }
    Ok(())
}

fn add_output(depfile: &Option<Rc<RefCell<Depfile>>>, dir: &Path, filename: &str) {
    if let Some(depfile) = depfile {
        let pb = dir.join(filename);
        depfile.borrow_mut().add_output(&pb);
    }
}

fn get_dependency_recorder(depfile: Rc<RefCell<Depfile>>) -> Box<dyn RebuildDependencyRecorder> {
    Box::new(RecordIntoDepfile(depfile))
}

fn get_option_string(option: &str, matches: &clap::ArgMatches) -> Option<String> {
    let cxx_impl_annotations = matches.value_of(option).map(|s| s.to_string());
    cxx_impl_annotations
}

fn write_placeholders(
    outdir: &Path,
    mut counter: usize,
    desired_number: Option<usize>,
    extension: &str,
) {
    if let Some(desired_number) = desired_number {
        if counter > desired_number {
            panic!("More .{} files were generated than expected. Increase the value passed to --generate-exact or reduce the number of include_cpp! sections.", extension);
        }
        while counter < desired_number {
            let fname = format!("gen{}.{}", counter, extension);
            write_to_file(outdir, fname, BLANK.as_bytes());
            counter += 1;
        }
    }
}

fn write_to_file(dir: &Path, filename: String, content: &[u8]) {
    let path = dir.join(filename);
    {
        let f = File::open(&path);
        if let Ok(mut f) = f {
            let mut existing_content = Vec::new();
            let r = f.read_to_end(&mut existing_content);
            if r.is_ok() && existing_content == content {
                return; // don't change timestamp on existing file unnecessarily
            }
        }
    }
    let mut f = File::create(&path).expect("Unable to create file");
    f.write_all(content).expect("Unable to write file");
}

struct RecordIntoDepfile(Rc<RefCell<Depfile>>);

impl RebuildDependencyRecorder for RecordIntoDepfile {
    fn record_header_file_dependency(&self, filename: &str) {
        self.0.borrow_mut().add_dependency(&PathBuf::from(filename))
    }
}

impl std::fmt::Debug for RecordIntoDepfile {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "<depfile>")
    }
}
<commit_msg>Depfile handling made consistent with writing files.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![forbid(unsafe_code)]

mod depfile;

use autocxx_engine::{parse_file, HeaderNamer, RebuildDependencyRecorder};
use clap::{crate_authors, crate_version, App, Arg, ArgGroup};
use depfile::Depfile;
use miette::IntoDiagnostic;
use proc_macro2::TokenStream;
use quote::ToTokens;
use std::cell::RefCell;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::rc::Rc;
use std::{cell::Cell, fs::File, path::Path};

pub(crate) static BLANK: &str = "// Blank autocxx placeholder";

static LONG_HELP: &str = "
Command line utility to expand the Rust 'autocxx' include_cpp! directive.

This tool can generate both the C++ and Rust side binding code for
a Rust file containing an include_cpp! directive.

If you're using cargo, don't use this: use autocxx_build instead,
which is much easier to include in build.rs build scripts. You'd likely
use this tool only if you're using some non-Cargo build system. If
that's you, read on.

This tool has three modes: generate the C++; generate a new Rust file where
the include_cpp! directive is *replaced* with bindings, or generate
a Rust file which can be included by the autocxx_macro. You may specify
multiple modes, or of course, invoke the tool multiple times.

In any mode, you'll need to pass the source Rust file name and the C++
include path.

For generation of the Rust side bindings, here's how to choose between
the two modes. If you're copying the entire Rust crate to a different
location during your build process, you may as well use --gen-rs-complete
to generate a whole new replacement .rs file with the autocxx
include_cpp! macro expanded.

But in most build systems, you won't be copying all the crate source
to a new location. In such a case, you should use --gen-rs-include
which will generate a file that will be included by the autocxx_macro
crate.

The second decision you must make is naming of the output files.
If your build system is able to cope with autocxx_gen building
unpredictable filenames, then:
a) set AUTOCXX_RS when using autocxx_macro
b) build all *.cc files produced by this tool.

If your build system requires each build rule to make precise filenames
known in advance, then you will need to:
a) Use `--generate-exact <N> --gen-rs-complete`
b) Teach your build system that the C++ files to compile are named `gen0.h`,
   `gen0.cc`, `gen1.h`, `gen1.cc`, etc (through `N`), corresponding
   to each `include_cpp!` section, plus 'cxxgen.h`. `gen.complete.rs` will also
   be generated and should be compiled _instead of_ the original Rust file.
c) If `N` is bigger than the number of files needed, extra no-op files will
   be emitted. These may still be compiled normally, but won't do anything. If
   `N` is smaller than the number of files needed, generation will fail.

Note that there is currently no way to teach each `include_cpp!` section
which `.include.rs` file to use, so the only way to get fixed output paths is
with `--gen-rs-complete`. There are always multiple `.cc` files (even with just
a single `include_cpp!` section), and we always generate the same number of each
type of file.
";

fn main() -> miette::Result<()> {
    let matches = App::new("autocxx-gen")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generates bindings files from Rust files that contain include_cpp! macros")
        .long_about(LONG_HELP)
        .arg(
            Arg::with_name("INPUT")
                .help("Sets the input .rs file to use")
                .required(true)
                .index(1),
        )
        .arg(
            Arg::with_name("outdir")
                .short("o")
                .long("outdir")
                .value_name("PATH")
                .help("output directory path")
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name("inc")
                .short("I")
                .long("inc")
                .multiple(true)
                .number_of_values(1)
                .value_name("INCLUDE DIRS")
                .help("include path")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cpp-extension")
                .long("cpp-extension")
                .value_name("EXTENSION")
                .default_value("cc")
                .help("C++ filename extension")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("gen-cpp")
                .long("gen-cpp")
                .help("whether to generate C++ implementation and header files")
        )
        .arg(
            Arg::with_name("gen-rs-complete")
                .long("gen-rs-complete")
                .help("whether to generate a Rust file replacing the original file (suffix will be .complete.rs)")
        )
        .arg(
            Arg::with_name("gen-rs-include")
                .long("gen-rs-include")
                .help("whether to generate Rust files for inclusion using autocxx_macro (suffix will be .include.rs)")
        )
        .group(ArgGroup::with_name("mode")
            .required(true)
            .multiple(true)
            .arg("gen-cpp")
            .arg("gen-rs-complete")
            .arg("gen-rs-include")
        )
        .arg(
            Arg::with_name("skip-cxx-gen")
                .long("skip-cxx-gen")
                .help("Skip performing C++ codegen for #[cxx::bridge] blocks. Only applies for --gen-cpp")
                .requires("gen-cpp")
        )
        .arg(
            Arg::with_name("generate-exact")
                .long("generate-exact")
                .value_name("NUM")
                .help("assume and ensure there are exactly NUM bridge blocks in the file. Only applies for --gen-cpp or --gen-rs-include")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("fix-rs-include-name")
                .long("fix-rs-include-name")
                .help("Make the name of the .rs file predictable. You must set AUTOCXX_RS_FILE during Rust build time to educate autocxx_macro about your choice.")
                .requires("gen-rs-include")
        )
        .arg(
            Arg::with_name("auto-allowlist")
                .long("auto-allowlist")
                .help("Dynamically construct allowlist from real uses of APIs.")
        )
        .arg(
            Arg::with_name("suppress-system-headers")
                .long("suppress-system-headers")
                .help("Do not refer to any system headers from generated code. May be useful for minimization.")
        )
        .arg(
            Arg::with_name("cxx-impl-annotations")
                .long("cxx-impl-annotations")
                .value_name("ANNOTATION")
                .help("prefix for symbols to be exported from C++ bindings, e.g. __attribute__ ((visibility (\"default\")))")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cxx-h-path")
                .long("cxx-h-path")
                .value_name("PREFIX")
                .help("prefix for path to cxx.h (from the cxx crate) within #include statements. Must end in /")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("cxxgen-h-path")
                .long("cxxgen-h-path")
                .value_name("PREFIX")
                .help("prefix for path to cxxgen.h (which we generate into the output directory) within #include statements. Must end in /")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("depfile")
                .long("depfile")
                .value_name("DEPFILE")
                .help("A .d file to write")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("clang-args")
                .last(true)
                .multiple(true)
                .help("Extra arguments to pass to Clang"),
        )
        .get_matches();

    env_logger::builder().init();
    let mut parsed_file = parse_file(
        matches.value_of("INPUT").unwrap(),
        matches.is_present("auto-allowlist"),
    )?;
    let incs = matches
        .values_of("inc")
        .unwrap_or_default()
        .map(PathBuf::from)
        .collect();
    let extra_clang_args: Vec<_> = matches
        .values_of("clang-args")
        .unwrap_or_default()
        .collect();
    let suppress_system_headers = matches.is_present("suppress-system-headers");
    let desired_number = matches
        .value_of("generate-exact")
        .map(|s| s.parse::<usize>().unwrap());
    let header_counter = Cell::new(0);
    let header_namer = if desired_number.is_some() {
        HeaderNamer(Box::new(|_| {
            let r = format!("gen{}.h", header_counter.get());
            header_counter.set(header_counter.get() + 1);
            r
        }))
    } else {
        Default::default()
    };
    let cpp_codegen_options = autocxx_engine::CppCodegenOptions {
        suppress_system_headers,
        cxx_impl_annotations: get_option_string("cxx-impl-annotations", &matches),
        path_to_cxx_h: get_option_string("cxx-h-path", &matches),
        path_to_cxxgen_h: get_option_string("cxxgen-h-path", &matches),
        skip_cxx_gen: matches.is_present("skip-cxx-gen"),
        header_namer,
    };
    let depfile = match matches.value_of("depfile") {
        None => None,
        Some(depfile_path) => {
            let depfile_path = PathBuf::from(depfile_path);
            Some(Rc::new(RefCell::new(
                Depfile::new(&depfile_path).into_diagnostic()?,
            )))
        }
    };
    let dep_recorder: Option<Box<dyn RebuildDependencyRecorder>> = depfile
        .as_ref()
        .map(|rc| get_dependency_recorder(rc.clone()));
    parsed_file.resolve_all(incs, &extra_clang_args, dep_recorder, &cpp_codegen_options)?;
    let outdir: PathBuf = matches.value_of_os("outdir").unwrap().into();
    if matches.is_present("gen-cpp") {
        let cpp = matches.value_of("cpp-extension").unwrap();
        let mut counter = 0usize;
        for include_cxx in parsed_file.get_cpp_buildables() {
            let generations = include_cxx
                .generate_h_and_cxx(&cpp_codegen_options)
                .expect("Unable to generate header and C++ code");
            for pair in generations.0 {
                let cppname = format!("gen{}.{}", counter, cpp);
                write_to_file(
                    &depfile,
                    &outdir,
                    cppname,
                    &pair.implementation.unwrap_or_default(),
                );
                write_to_file(&depfile, &outdir, pair.header_name, &pair.header);
                counter += 1;
            }
        }
        write_placeholders(&depfile, &outdir, counter, desired_number, cpp);
    }
    drop(cpp_codegen_options);
    write_placeholders(
        &depfile,
        &outdir,
        header_counter.into_inner(),
        desired_number,
        "h",
    );
    if matches.is_present("gen-rs-complete") {
        let mut ts = TokenStream::new();
        parsed_file.to_tokens(&mut ts);
        write_to_file(
            &depfile,
            &outdir,
            "gen.complete.rs".to_string(),
            ts.to_string().as_bytes(),
        );
    }
    if matches.is_present("gen-rs-include") {
        let autocxxes = parsed_file.get_rs_buildables();
        let mut counter = 0usize;
        for include_cxx in autocxxes {
            let ts = include_cxx.generate_rs();
            let fname = if matches.is_present("fix-rs-include-name") {
                format!("gen{}.include.rs", counter)
            } else {
                include_cxx.get_rs_filename()
            };
            write_to_file(&depfile, &outdir, fname, ts.to_string().as_bytes());
            counter += 1;
        }
        if matches.is_present("fix-rs-include-name") {
            write_placeholders(&depfile, &outdir, counter, desired_number, "include.rs");
        }
    }
    if let Some(depfile) = depfile {
        depfile.borrow_mut().write().into_diagnostic()?;
    }
    Ok(())
}

fn get_dependency_recorder(depfile: Rc<RefCell<Depfile>>) -> Box<dyn RebuildDependencyRecorder> {
    Box::new(RecordIntoDepfile(depfile))
}

fn get_option_string(option: &str, matches: &clap::ArgMatches) -> Option<String> {
    let cxx_impl_annotations = matches.value_of(option).map(|s| s.to_string());
    cxx_impl_annotations
}

fn write_placeholders(
    depfile: &Option<Rc<RefCell<Depfile>>>,
    outdir: &Path,
    mut counter: usize,
    desired_number: Option<usize>,
    extension: &str,
) {
    if let Some(desired_number) = desired_number {
        if counter > desired_number {
            panic!("More .{} files were generated than expected. Increase the value passed to --generate-exact or reduce the number of include_cpp! sections.", extension);
        }
        while counter < desired_number {
            let fname = format!("gen{}.{}", counter, extension);
            write_to_file(depfile, outdir, fname, BLANK.as_bytes());
            counter += 1;
        }
    }
}

fn write_to_file(
    depfile: &Option<Rc<RefCell<Depfile>>>,
    dir: &Path,
    filename: String,
    content: &[u8],
) {
    let path = dir.join(filename);
    if let Some(depfile) = depfile {
        depfile.borrow_mut().add_output(&path);
    }
    {
        let f = File::open(&path);
        if let Ok(mut f) = f {
            let mut existing_content = Vec::new();
            let r = f.read_to_end(&mut existing_content);
            if r.is_ok() && existing_content == content {
                return; // don't change timestamp on existing file unnecessarily
            }
        }
    }
    let mut f = File::create(&path).expect("Unable to create file");
    f.write_all(content).expect("Unable to write file");
}

struct RecordIntoDepfile(Rc<RefCell<Depfile>>);

impl RebuildDependencyRecorder for RecordIntoDepfile {
    fn record_header_file_dependency(&self, filename: &str) {
        self.0.borrow_mut().add_dependency(&PathBuf::from(filename))
    }
}

impl std::fmt::Debug for RecordIntoDepfile {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "<depfile>")
    }
}
<|endoftext|>


<commit_before>
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use regex::Regex;

pub fn add(a: i32, b: i32) -> i32 {
    a+b
}

#[macro_use]
extern crate lazy_static;
pub fn get_number<P: AsRef<Path>>(filename: P) -> io::Result<i32> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let lines = read_lines(filename)?;
    for line in lines {
        if let Some(n) = RE.captures(&line.unwrap()) {
            if let Some(n) = n.get(1) {
                return Ok(n.as_str().parse().unwrap());
            }
        }
    }
    Ok(0)
}

fn read_lines<P: AsRef<Path>>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

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

    #[test]
    fn it_works() {
        assert_eq!(add(2,2) , 4);
    }

    #[test]
    fn get_test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }
}
<commit_msg>delete old code<commit_after>use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use regex::Regex;

#[macro_use]
extern crate lazy_static;
pub fn get_number<P: AsRef<Path>>(filename: P) -> io::Result<i32> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let lines = read_lines(filename)?;
    for line in lines {
        if let Some(n) = RE.captures(&line.unwrap()) {
            if let Some(n) = n.get(1) {
                return Ok(n.as_str().parse().unwrap());
            }
        }
    }
    Ok(0)
}

fn read_lines<P: AsRef<Path>>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

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

    #[test]
    fn get_test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }
}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::iter::range_step_inclusive;
use platform::vga::{Color, COLS, ROWS};
use platform::vga;

pub struct StdioWriter
{
	pub xpos: u32,
	pub ypos: u32,
	pub fg: Color,
	pub bg: Color
}

impl Copy for StdioWriter {}
impl Clone for StdioWriter { fn clone(&self) -> Self { *self } }

impl StdioWriter
{
	pub fn new() -> StdioWriter
	{
		StdioWriter
		{
			xpos: 0,
			ypos: 0,
			fg: Color::White,
			bg: Color::Black
		}
	}

	pub fn clear_screen(&mut self)
	{
		for y in (0u32 .. ROWS)
		{
			for x in (0u32 .. COLS)
			{
				vga::putc(x, y, 0);
				vga::setfg(x, y, self.fg);
				vga::setbg(x, y, self.bg);
			}
		}
		self.go_to(0, 0);
	}

	pub fn go_to(&mut self, x: u32, y: u32)
	{
		self.move_coords(x, y);
		self.set_cursor();
	}

	pub fn backspace(&mut self)
	{
		self.go_left();
		self.raw_print_char(' ' as u8);
		self.set_cursor();
	}

	pub fn tab(&mut self)
	{
		let x = self.xpos;
		for _ in (0 .. 4 - (x % 4))
		{
			self.raw_print_char(' ' as u8);
			self.go_right();
		}
		self.set_cursor();
	}

	pub fn crlf(&mut self)
	{
		self.xpos = 0;
		self.ypos = if self.ypos == ROWS - 1 { 0 } else { self.ypos + 1 };
		self.set_cursor();
	}

	fn go_right(&mut self)
	{
		if self.xpos == COLS - 1
		{
			self.xpos = 0;
			self.ypos = (self.ypos + ROWS + 1) % ROWS;
		}
		else
		{
			self.xpos += 1;
		}
	}

	fn go_left(&mut self)
	{
		if self.xpos == 0
		{
			self.xpos = COLS - 1;
			self.ypos = (self.ypos + ROWS - 1) % ROWS;
		}
		else
		{
			self.xpos -= 1;
		}
	}

	fn move_coords(&mut self, x: u32, y: u32)
	{
		let mut newx = x;
		let mut newy = y;
		if newx >= COLS { newx = 0; newy += 1; }
		if newy >= ROWS { newy = 0; }
		self.xpos = newx;
		self.ypos = newy;
	}

	fn set_cursor(&self)
	{
		vga::move_cursor(self.xpos, self.ypos);
	}

	pub fn print_dec(&mut self, v: u32)
	{
		if v == 0
		{
			self.print_char('0');
			return;
		}

		let mut fac = 1;
		let mut nv = v;
		while fac <= v { fac *= 10; }
		fac /= 10;
		while fac > 0
		{
			let n = nv / fac;
			let c = n as u8 + '0' as u8;
			self.raw_print_char(c);
			self.go_right();
			nv -= n * fac;
			fac /= 10;
		}
		self.set_cursor();
	}

	pub fn print_bin(&mut self, v: u32, sz: u32)
	{
		self.print_screen("0b");

		for i in range_step_inclusive(sz as i32 - 1, 0, -1)
		{
			let c = match (v >> (i as u32)) & 0x1
			{
				0 => '0',
				_ => '1',
			} as u8;
			self.raw_print_char(c);
			self.go_right();
		}
		self.set_cursor();
	}

	pub fn print_hex(&mut self, v: u32, sz: u32)
	{
		self.print_screen("0x");

		for i in range_step_inclusive(sz as i32 - 4, 0i32, -4)
		{
			let c = match (v >> (i as u32)) & 0xF
			{
				c if c <= 9 => c + '0' as u32,
				c => c - 10 + 'A' as u32,
			} as u8;
			self.raw_print_char(c);
			self.go_right();
		}
		self.set_cursor();
	}

	pub fn print_char(&mut self, value: char)
	{
		self.raw_print_char(value as u8);
		self.go_right();
		self.set_cursor();
	}

	fn raw_print_char(&self, value: u8)
	{
		vga::putc(self.xpos, self.ypos, value);
		vga::setfg(self.xpos, self.ypos, self.fg);
		vga::setbg(self.xpos, self.ypos, self.bg);
	}

	pub fn print_screen(&mut self, value: &str)
	{
		for c in value.bytes()
		{
			self.raw_print_char(c);
			self.go_right();
		}
		self.set_cursor();
	}
}

impl ::core::fmt::Write for StdioWriter
{
	fn write_str(&mut self, s: &str) -> ::core::fmt::Result
	{
		for b in s.bytes()
		{
			self.raw_print_char(b);
			self.go_right();
		}
		self.set_cursor();
		Ok(())
	}
}
<commit_msg>Stop using range_step_inclusive<commit_after>use core::prelude::*;
use platform::vga::{Color, COLS, ROWS};
use platform::vga;

pub struct StdioWriter
{
	pub xpos: u32,
	pub ypos: u32,
	pub fg: Color,
	pub bg: Color
}

impl Copy for StdioWriter {}
impl Clone for StdioWriter { fn clone(&self) -> Self { *self } }

impl StdioWriter
{
	pub fn new() -> StdioWriter
	{
		StdioWriter
		{
			xpos: 0,
			ypos: 0,
			fg: Color::White,
			bg: Color::Black
		}
	}

	pub fn clear_screen(&mut self)
	{
		for y in (0u32 .. ROWS)
		{
			for x in (0u32 .. COLS)
			{
				vga::putc(x, y, 0);
				vga::setfg(x, y, self.fg);
				vga::setbg(x, y, self.bg);
			}
		}
		self.go_to(0, 0);
	}

	pub fn go_to(&mut self, x: u32, y: u32)
	{
		self.move_coords(x, y);
		self.set_cursor();
	}

	pub fn backspace(&mut self)
	{
		self.go_left();
		self.raw_print_char(' ' as u8);
		self.set_cursor();
	}

	pub fn tab(&mut self)
	{
		let x = self.xpos;
		for _ in (0 .. 4 - (x % 4))
		{
			self.raw_print_char(' ' as u8);
			self.go_right();
		}
		self.set_cursor();
	}

	pub fn crlf(&mut self)
	{
		self.xpos = 0;
		self.ypos = if self.ypos == ROWS - 1 { 0 } else { self.ypos + 1 };
		self.set_cursor();
	}

	fn go_right(&mut self)
	{
		if self.xpos == COLS - 1
		{
			self.xpos = 0;
			self.ypos = (self.ypos + ROWS + 1) % ROWS;
		}
		else
		{
			self.xpos += 1;
		}
	}

	fn go_left(&mut self)
	{
		if self.xpos == 0
		{
			self.xpos = COLS - 1;
			self.ypos = (self.ypos + ROWS - 1) % ROWS;
		}
		else
		{
			self.xpos -= 1;
		}
	}

	fn move_coords(&mut self, x: u32, y: u32)
	{
		let mut newx = x;
		let mut newy = y;
		if newx >= COLS { newx = 0; newy += 1; }
		if newy >= ROWS { newy = 0; }
		self.xpos = newx;
		self.ypos = newy;
	}

	fn set_cursor(&self)
	{
		vga::move_cursor(self.xpos, self.ypos);
	}

	pub fn print_dec(&mut self, v: u32)
	{
		if v == 0
		{
			self.print_char('0');
			return;
		}

		let mut fac = 1;
		let mut nv = v;
		while fac <= v { fac *= 10; }
		fac /= 10;
		while fac > 0
		{
			let n = nv / fac;
			let c = n as u8 + '0' as u8;
			self.raw_print_char(c);
			self.go_right();
			nv -= n * fac;
			fac /= 10;
		}
		self.set_cursor();
	}

	pub fn print_bin(&mut self, v: u32, sz: u32)
	{
		self.print_screen("0b");

		let mut i = (sz - 1) as i32;
		while i >= 0
		{
			let c = match (v >> (i as u32)) & 0x1
			{
				0 => '0',
				_ => '1',
			} as u8;
			self.raw_print_char(c);
			self.go_right();
			i -= 1;
		}
		self.set_cursor();
	}

	pub fn print_hex(&mut self, v: u32, sz: u32)
	{
		self.print_screen("0x");

		let mut i = (sz - 4) as i32;
		while i >= 0
		{
			let c = match (v >> (i as u32)) & 0xF
			{
				c if c <= 9 => c + '0' as u32,
				c => c - 10 + 'A' as u32,
			} as u8;
			self.raw_print_char(c);
			self.go_right();
			i -= 4;
		}
		self.set_cursor();
	}

	pub fn print_char(&mut self, value: char)
	{
		self.raw_print_char(value as u8);
		self.go_right();
		self.set_cursor();
	}

	fn raw_print_char(&self, value: u8)
	{
		vga::putc(self.xpos, self.ypos, value);
		vga::setfg(self.xpos, self.ypos, self.fg);
		vga::setbg(self.xpos, self.ypos, self.bg);
	}

	pub fn print_screen(&mut self, value: &str)
	{
		for c in value.bytes()
		{
			self.raw_print_char(c);
			self.go_right();
		}
		self.set_cursor();
	}
}

impl ::core::fmt::Write for StdioWriter
{
	fn write_str(&mut self, s: &str) -> ::core::fmt::Result
	{
		for b in s.bytes()
		{
			self.raw_print_char(b);
			self.go_right();
		}
		self.set_cursor();
		Ok(())
	}
}
<|endoftext|>


<commit_before>use crate::future::poll_fn;
use crate::time::{delay_until, Delay, Duration, Instant};

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Creates new `Interval` that yields with interval of `duration`. The first
/// tick completes immediately.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// This function is equivalent to `interval_at(Instant::now(), period)`.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{self, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 20ms have elapsed.
/// }
/// ```
///
/// A simple example using `interval` to execute a task every two seconds.
///
/// The difference between `interval` and [`delay_for`] is that an `interval`
/// measures the time since the last tick, which means that `.tick().await`
/// may wait for a shorter time than the duration specified for the interval
/// if some time has passed between calls to `.tick().await`.
///
/// If the tick in the example below was replaced with [`delay_for`], the task
/// would only be executed once every three seconds, and not every two
/// seconds.
///
/// ```
/// use tokio::time;
///
/// async fn task_that_takes_a_second() {
///     println!("hello");
///     time::delay_for(time::Duration::from_secs(1)).await
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(time::Duration::from_secs(2));
///     for _i in 0..5 {
///         interval.tick().await;
///         task_that_takes_a_second().await;
///     }
/// }
/// ```
///
/// [`delay_for`]: crate::time::delay_for()
pub fn interval(period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    interval_at(Instant::now(), period)
}

/// Creates new `Interval` that yields with interval of `period` with the
/// first tick completing at `start`.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{interval_at, Duration, Instant};
///
/// #[tokio::main]
/// async fn main() {
///     let start = Instant::now() + Duration::from_millis(50);
///     let mut interval = interval_at(start, Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 70ms have elapsed.
/// }
/// ```
pub fn interval_at(start: Instant, period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    Interval {
        delay: delay_until(start),
        period,
    }
}

/// Stream returned by [`interval`](interval) and [`interval_at`](interval_at).
#[derive(Debug)]
pub struct Interval {
    /// Future that completes the next time the `Interval` yields a value.
    delay: Delay,

    /// The duration between values yielded by `Interval`.
    period: Duration,
}

impl Interval {
    #[doc(hidden)] // TODO: document
    pub fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
        // Wait for the delay to be done
        ready!(Pin::new(&mut self.delay).poll(cx));

        // Get the `now` by looking at the `delay` deadline
        let now = self.delay.deadline();

        // The next interval value is `duration` after the one that just
        // yielded.
        let next = now + self.period;
        self.delay.reset(next);

        // Return the current instant
        Poll::Ready(now)
    }

    /// Completes when the next instant in the interval has been reached.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::time;
    ///
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let mut interval = time::interval(Duration::from_millis(10));
    ///
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///
    ///     // approximately 20ms have elapsed.
    /// }
    /// ```
    #[allow(clippy::should_implement_trait)] // TODO: rename (tokio-rs/tokio#1261)
    pub async fn tick(&mut self) -> Instant {
        poll_fn(|cx| self.poll_tick(cx)).await
    }
}

#[cfg(feature = "stream")]
impl crate::stream::Stream for Interval {
    type Item = Instant;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Instant>> {
        Poll::Ready(Some(ready!(self.poll_tick(cx))))
    }
}
<commit_msg>time: interval Stream impl requires stream feature (#2695)<commit_after>use crate::future::poll_fn;
use crate::time::{delay_until, Delay, Duration, Instant};

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Creates new `Interval` that yields with interval of `duration`. The first
/// tick completes immediately.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// This function is equivalent to `interval_at(Instant::now(), period)`.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{self, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 20ms have elapsed.
/// }
/// ```
///
/// A simple example using `interval` to execute a task every two seconds.
///
/// The difference between `interval` and [`delay_for`] is that an `interval`
/// measures the time since the last tick, which means that `.tick().await`
/// may wait for a shorter time than the duration specified for the interval
/// if some time has passed between calls to `.tick().await`.
///
/// If the tick in the example below was replaced with [`delay_for`], the task
/// would only be executed once every three seconds, and not every two
/// seconds.
///
/// ```
/// use tokio::time;
///
/// async fn task_that_takes_a_second() {
///     println!("hello");
///     time::delay_for(time::Duration::from_secs(1)).await
/// }
///
/// #[tokio::main]
/// async fn main() {
///     let mut interval = time::interval(time::Duration::from_secs(2));
///     for _i in 0..5 {
///         interval.tick().await;
///         task_that_takes_a_second().await;
///     }
/// }
/// ```
///
/// [`delay_for`]: crate::time::delay_for()
pub fn interval(period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    interval_at(Instant::now(), period)
}

/// Creates new `Interval` that yields with interval of `period` with the
/// first tick completing at `start`.
///
/// An interval will tick indefinitely. At any time, the `Interval` value can be
/// dropped. This cancels the interval.
///
/// # Panics
///
/// This function panics if `period` is zero.
///
/// # Examples
///
/// ```
/// use tokio::time::{interval_at, Duration, Instant};
///
/// #[tokio::main]
/// async fn main() {
///     let start = Instant::now() + Duration::from_millis(50);
///     let mut interval = interval_at(start, Duration::from_millis(10));
///
///     interval.tick().await;
///     interval.tick().await;
///     interval.tick().await;
///
///     // approximately 70ms have elapsed.
/// }
/// ```
pub fn interval_at(start: Instant, period: Duration) -> Interval {
    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");

    Interval {
        delay: delay_until(start),
        period,
    }
}

/// Stream returned by [`interval`](interval) and [`interval_at`](interval_at).
///
/// This type only implements the [`Stream`] trait if the "stream" feature is
/// enabled.
///
/// [`Stream`]: trait@crate::stream::Stream
#[derive(Debug)]
pub struct Interval {
    /// Future that completes the next time the `Interval` yields a value.
    delay: Delay,

    /// The duration between values yielded by `Interval`.
    period: Duration,
}

impl Interval {
    #[doc(hidden)] // TODO: document
    pub fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
        // Wait for the delay to be done
        ready!(Pin::new(&mut self.delay).poll(cx));

        // Get the `now` by looking at the `delay` deadline
        let now = self.delay.deadline();

        // The next interval value is `duration` after the one that just
        // yielded.
        let next = now + self.period;
        self.delay.reset(next);

        // Return the current instant
        Poll::Ready(now)
    }

    /// Completes when the next instant in the interval has been reached.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::time;
    ///
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let mut interval = time::interval(Duration::from_millis(10));
    ///
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///     interval.tick().await;
    ///
    ///     // approximately 20ms have elapsed.
    /// }
    /// ```
    #[allow(clippy::should_implement_trait)] // TODO: rename (tokio-rs/tokio#1261)
    pub async fn tick(&mut self) -> Instant {
        poll_fn(|cx| self.poll_tick(cx)).await
    }
}

#[cfg(feature = "stream")]
impl crate::stream::Stream for Interval {
    type Item = Instant;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Instant>> {
        Poll::Ready(Some(ready!(self.poll_tick(cx))))
    }
}
<|endoftext|>


<commit_before>#![feature(convert)]

extern crate phf_codegen;
extern crate serde_json;
extern crate csv;

use std::env;
use std::fs::File;
use std::io::{BufWriter, BufReader, Write};
use std::path::Path;
use std::collections::HashMap;
use std::mem;

use serde_json::Value;

include!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/intel/description.rs"));

/// We need to convert parsed strings to static because we're reusing
/// the struct definition which declare strings (rightgully) as
/// static in the generated code.
fn string_to_static_str<'a>(s: &'a str) -> &'static str {
    unsafe {
        let ret = mem::transmute(&s as &str);
        mem::forget(s);
        ret
    }
}

fn parse_performance_counters(input: &str) {
    let mut builder = phf_codegen::Map::new();
    let f = File::open(input).unwrap();
    let reader = BufReader::new(f);
    let data: Value = serde_json::from_reader(reader).unwrap();
    let mut all_events = HashMap::new();

    if data.is_array() {
        let entries = data.as_array().unwrap();
        for entry in entries.iter() {

            if !entry.is_object() {
                panic!("Expected JSON object.");
            }

            let mut event_code = Tuple::One(0);
            let mut umask = Tuple::One(0);
            let mut event_name = "";
            let mut brief_description = "";
            let mut public_description = None;
            let mut counter = Counter::Fixed(0);
            let mut counter_ht_off = Counter::Fixed(0);
            let mut pebs_counters = None;
            let mut sample_after_value = 0;
            let mut msr_index = MSRIndex::None;
            let mut msr_value = 0;
            let mut taken_alone = false;
            let mut counter_mask = 0;
            let mut invert = false;
            let mut any_thread = false;
            let mut edge_detect = false;
            let mut pebs = PebsType::Regular;
            let mut precise_store = false;
            let mut data_la = false;
            let mut l1_hit_indication = false;
            let mut errata = None;
            let mut offcore = false;

            let mut do_insert: bool = false;

            let pcn = entry.as_object().unwrap();
            for (key, value) in pcn.iter() {
                if !value.is_string() {
                    panic!("Not a string");
                }
                let value_string = value.as_string().unwrap();
                let value_str = string_to_static_str(value_string).trim();
                let split_str_parts: Vec<&str> = value_string.split(",").map(|x| x.trim()).collect();

                //println!("{:?} {}", key, input);

                match key.as_str() {
                    "EventName" => {
                        if !all_events.contains_key(value_str.clone()) {
                            all_events.insert(value_str, 0);
                            assert!(all_events.contains_key(value_str));
                            do_insert = true;
                        }
                        else {
                            do_insert = false;
                            println!("WARN: Key {} already exists.", value_str);
                        }
                        println!("{:?} {}", value_str, input);

                        event_name = value_str;
                    }

                    "EventCode" => {
                        let split_parts: Vec<u64> = split_str_parts.iter()
                            .map(|x| { assert!(x.starts_with("0x")); u64::from_str_radix(&x[2..], 16).unwrap() })
                            .collect();

                        match split_parts.len() {
                            1 => event_code = Tuple::One(split_parts[0] as u8),
                            2 => event_code = Tuple::Two(split_parts[0] as u8, split_parts[1] as u8),
                            _ => panic!("More than two event codes?")
                        }
                    },

                    "UMask" => {
                        let split_parts: Vec<u64> = split_str_parts.iter()
                            .map(|x| { assert!(x.starts_with("0x")); u64::from_str_radix(&x[2..], 16).unwrap() })
                            .collect();

                        match split_parts.len() {
                            1 => umask = Tuple::One(split_parts[0] as u8),
                            2 => umask = Tuple::Two(split_parts[0] as u8, split_parts[1] as u8),
                            _ => panic!("More than two event codes?")
                        }
                    },

                    "BriefDescription" => brief_description = value_str,

                    "PublicDescription" => {
                        if brief_description != value_str && value_str != "tbd" {
                            public_description = Some(value_str);
                        }
                        else {
                            public_description = None;
                        }
                    },

                    "Counter" => {
                        if value_str.starts_with("Fixed counter") {
                            let mask: u64 = value_str["Fixed counter".len()..]
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter = Counter::Fixed(mask as u8);
                        }
                        else {
                            let mask: u64 = value_str
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter = Counter::Programmable(mask as u8);
                        }
                    },

                    "CounterHTOff" => {
                        if value_str.starts_with("Fixed counter") {
                            let mask: u64 = value_str["Fixed counter".len()..]
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter_ht_off = Counter::Fixed(mask as u8);
                        }
                        else {
                            let mask: u64 = value_str
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter_ht_off = Counter::Programmable(mask as u8);
                        }
                    },

                    "PEBScounters" => {
                        if value_str.starts_with("Fixed counter") {
                            let mask: u64 = value_str["Fixed counter".len()..]
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            pebs_counters = Some(Counter::Fixed(mask as u8));
                        }
                        else {
                            let mask: u64 = value_str
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            pebs_counters = Some(Counter::Programmable(mask as u8));
                        }
                    },

                    "SampleAfterValue" => sample_after_value = u64::from_str_radix(&value_str, 10).unwrap(),

                    "MSRIndex" => {
                        let split_parts: Vec<u64> = value_str
                            .split(",")
                            .map(|x| x.trim())
                            .map(|x| {
                                if x.len() > 2 && x[..2].starts_with("0x") {
                                    u64::from_str_radix(&x[2..], 16).unwrap()
                                }
                                else {
                                    u64::from_str_radix(&x, 10).unwrap()
                                }
                            })
                            .collect();

                            msr_index = match split_parts.len() {
                                1 => {
                                    if split_parts[0] != 0 {
                                        MSRIndex::One(split_parts[0] as u8)
                                    }
                                    else {
                                        MSRIndex::None
                                    }
                                },
                                2 => MSRIndex::Two(split_parts[0] as u8, split_parts[1] as u8),
                                _ => panic!("More than two MSR indexes?")
                            }
                    },
                    "MSRValue" => {
                        msr_value = if value_str.len() > 2 && value_str[..2].starts_with("0x") {
                            u64::from_str_radix(&value_str[2..], 16).unwrap()
                        }
                        else {
                            u64::from_str_radix(&value_str, 10).unwrap()
                        }
                    },
                    "TakenAlone" => {
                        taken_alone = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        };
                    },
                    "CounterMask" => {
                        counter_mask = if value_str.len() > 2 && value_str[..2].starts_with("0x") {
                            u8::from_str_radix(&value_str[2..], 16).unwrap()
                        }
                        else {
                            u8::from_str_radix(&value_str, 10).unwrap()
                        }
                    },
                    "Invert" => {
                        invert = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        };
                    }
                    "AnyThread" => any_thread = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        },
                    "EdgeDetect" => edge_detect = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        },
                    "PEBS" => {
                        pebs = match value_str.trim() {
                            "0" => PebsType::Regular,
                            "1" => PebsType::PebsOrRegular,
                            "2" => PebsType::PebsOnly,
                            _ => panic!("Unknown PEBS type: {}", value_str),
                        }
                    },
                    "PRECISE_STORE" => precise_store = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        },
                    "Data_LA" => data_la = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        },
                    "L1_Hit_Indication" => l1_hit_indication = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                        },
                    "Errata" => {
                        errata = if value_str != "null" {
                            Some(value_str)
                        }
                        else {
                            None
                        };
                    },
                    "Offcore" => offcore = match value_str.trim() {
                            "0" => false,
                            "1" => true,
                            _ => panic!("Unknown boolean value {}", value_str),
                    },
                    "ELLC" => {
                        // Ignored due to missing documentation.
                    },
                    _ => panic!("Unknown member: {} in file {}", key, input),
                };
            }

            let ipcd = IntelPerformanceCounterDescription::new(
                event_code,
                umask,
                event_name,
                brief_description,
                public_description,
                counter,
                counter_ht_off,
                pebs_counters,
                sample_after_value,
                msr_index,
                msr_value,
                taken_alone,
                counter_mask,
                invert,
                any_thread,
                edge_detect,
                pebs,
                precise_store,
                data_la,
                l1_hit_indication,
                errata,
                offcore
            );

            //println!("{:?}", ipcd.event_name);
            if do_insert == true {
                builder.entry(ipcd.event_name, format!("{:?}", ipcd).as_str());
            }
        }
    }
    else {
        panic!("JSON data is not an array.");
    }

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());
    write!(&mut file, "pub static PERFORMANCE_COUNTER_HASWELL: phf::Map<&'static str, IntelPerformanceCounterDescription> = ").unwrap();
    builder.build(&mut file).unwrap();
    write!(&mut file, ";\n").unwrap();
}

fn main() {

    let mut rdr = csv::Reader::from_file("./perfmon_data/mapfile.csv").unwrap();
    let mut data_files = HashMap::new();

    for record in rdr.decode() {
        let (family_model, version, file_name, event_type): (String, String, String, String) = record.unwrap();
        if !data_files.contains_key(&file_name) {
            println!("{} {} {} {}", family_model, version, file_name, event_type);

            data_files.insert(Box::new(file_name), 0);
        }
    }

    for file in data_files.keys() {
        if file.contains("_core_") {
            println!("Processing {:?}", file);
            parse_performance_counters(format!("perfmon_data{}", file).as_str());
        }
    }
}
<commit_msg>Update build script.<commit_after>#![feature(convert)]

extern crate phf_codegen;
extern crate serde_json;
extern crate csv;

use std::ascii::AsciiExt;
use std::env;
use std::fs::File;
use std::io::{BufWriter, BufReader, Write};
use std::path::Path;
use std::collections::HashMap;
use std::mem;

use serde_json::Value;

include!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/intel/description.rs"));

/// We need to convert parsed strings to static because we're reusing
/// the struct definition which declare strings (rightgully) as
/// static in the generated code.
fn string_to_static_str<'a>(s: &'a str) -> &'static str {
    unsafe {
        let ret = mem::transmute(&s as &str);
        mem::forget(s);
        ret
    }
}

fn parse_bool(input: &str) -> bool {
    match input.trim() {
        "0" => false,
        "1" => true,
        _ => panic!("Unknown boolean value {}", input),
    }
}

fn parse_performance_counters(input: &str, stem: &str, variable: &str) {
    let mut builder = phf_codegen::Map::new();
    let f = File::open(input).unwrap();
    let reader = BufReader::new(f);
    let data: Value = serde_json::from_reader(reader).unwrap();
    let mut all_events = HashMap::new();

    if data.is_array() {
        let entries = data.as_array().unwrap();
        for entry in entries.iter() {

            if !entry.is_object() {
                panic!("Expected JSON object.");
            }

            let mut event_code = Tuple::One(0);
            let mut umask = Tuple::One(0);
            let mut event_name = "";
            let mut brief_description = "";
            let mut public_description = None;
            let mut counter = Counter::Fixed(0);
            let mut counter_ht_off = Counter::Fixed(0);
            let mut pebs_counters = None;
            let mut sample_after_value = 0;
            let mut msr_index = MSRIndex::None;
            let mut msr_value = 0;
            let mut taken_alone = false;
            let mut counter_mask = 0;
            let mut invert = false;
            let mut any_thread = false;
            let mut edge_detect = false;
            let mut pebs = PebsType::Regular;
            let mut precise_store = false;
            let mut data_la = false;
            let mut l1_hit_indication = false;
            let mut errata = None;
            let mut offcore = false;

            let mut do_insert: bool = false;

            let pcn = entry.as_object().unwrap();
            for (key, value) in pcn.iter() {
                if !value.is_string() {
                    panic!("Not a string");
                }
                let value_string = value.as_string().unwrap();
                let value_str = string_to_static_str(value_string).trim();
                let split_str_parts: Vec<&str> = value_string.split(",").map(|x| x.trim()).collect();

                match key.as_str() {
                    "EventName" => {
                        if !all_events.contains_key(value_str.clone()) {
                            all_events.insert(value_str, 0);
                            assert!(all_events.contains_key(value_str));
                            do_insert = true;
                        }
                        else {
                            do_insert = false;
                            println!("WARN: Key {} already exists.", value_str);
                        }
                        event_name = value_str;
                    }

                    "EventCode" => {
                        let split_parts: Vec<u64> = split_str_parts.iter()
                            .map(|x| { assert!(x.starts_with("0x")); u64::from_str_radix(&x[2..], 16).unwrap() })
                            .collect();

                        match split_parts.len() {
                            1 => event_code = Tuple::One(split_parts[0] as u8),
                            2 => event_code = Tuple::Two(split_parts[0] as u8, split_parts[1] as u8),
                            _ => panic!("More than two event codes?")
                        }
                    },

                    "UMask" => {
                        let split_parts: Vec<u64> = split_str_parts.iter()
                            .map(|x| { assert!(x.starts_with("0x")); u64::from_str_radix(&x[2..], 16).unwrap() })
                            .collect();

                        match split_parts.len() {
                            1 => umask = Tuple::One(split_parts[0] as u8),
                            2 => umask = Tuple::Two(split_parts[0] as u8, split_parts[1] as u8),
                            _ => panic!("More than two event codes?")
                        }
                    },

                    "BriefDescription" => brief_description = value_str,

                    "PublicDescription" => {
                        if brief_description != value_str && value_str != "tbd" {
                            public_description = Some(value_str);
                        }
                        else {
                            public_description = None;
                        }
                    },

                    "Counter" => {
                        if value_str.starts_with("Fixed counter") {
                            let mask: u64 = value_str["Fixed counter".len()..]
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter = Counter::Fixed(mask as u8);
                        }
                        else {
                            let mask: u64 = value_str
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter = Counter::Programmable(mask as u8);
                        }
                    },

                    "CounterHTOff" => {
                        if value_str.starts_with("Fixed counter") {
                            let mask: u64 = value_str["Fixed counter".len()..]
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter_ht_off = Counter::Fixed(mask as u8);
                        }
                        else {
                            let mask: u64 = value_str
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            counter_ht_off = Counter::Programmable(mask as u8);
                        }
                    },

                    "PEBScounters" => {
                        if value_str.starts_with("Fixed counter") {
                            let mask: u64 = value_str["Fixed counter".len()..]
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            pebs_counters = Some(Counter::Fixed(mask as u8));
                        }
                        else {
                            let mask: u64 = value_str
                                .split(",")
                                .map(|x| x.trim())
                                .map(|x| u64::from_str_radix(&x, 10).unwrap())
                                .fold(0, |acc, c| { assert!(c < 8); acc | 1 << c });
                            pebs_counters = Some(Counter::Programmable(mask as u8));
                        }
                    },

                    "SampleAfterValue" => sample_after_value = u64::from_str_radix(&value_str, 10).unwrap(),

                    "MSRIndex" => {
                        let split_parts: Vec<u64> = value_str
                            .split(",")
                            .map(|x| x.trim())
                            .map(|x| {
                                if x.len() > 2 && x[..2].starts_with("0x") {
                                    u64::from_str_radix(&x[2..], 16).unwrap()
                                }
                                else {
                                    u64::from_str_radix(&x, 10).unwrap()
                                }
                            })
                            .collect();

                            msr_index = match split_parts.len() {
                                1 => {
                                    if split_parts[0] != 0 {
                                        MSRIndex::One(split_parts[0] as u8)
                                    }
                                    else {
                                        MSRIndex::None
                                    }
                                },
                                2 => MSRIndex::Two(split_parts[0] as u8, split_parts[1] as u8),
                                _ => panic!("More than two MSR indexes?")
                            }
                    },
                    "MSRValue" => {
                        msr_value = if value_str.len() > 2 && value_str[..2].starts_with("0x") {
                            u64::from_str_radix(&value_str[2..], 16).unwrap()
                        }
                        else {
                            u64::from_str_radix(&value_str, 10).unwrap()
                        }
                    },
                    "TakenAlone" => {
                        taken_alone = parse_bool(value_str);
                    },
                    "CounterMask" => {
                        counter_mask = if value_str.len() > 2 && value_str[..2].starts_with("0x") {
                            u8::from_str_radix(&value_str[2..], 16).unwrap()
                        }
                        else {
                            u8::from_str_radix(&value_str, 10).unwrap()
                        }
                    },
                    "Invert" => {
                        invert = parse_bool(value_str);
                    }
                    "AnyThread" => any_thread = parse_bool(value_str),
                    "EdgeDetect" => edge_detect = parse_bool(value_str),
                    "PEBS" => {
                        pebs = match value_str.trim() {
                            "0" => PebsType::Regular,
                            "1" => PebsType::PebsOrRegular,
                            "2" => PebsType::PebsOnly,
                            _ => panic!("Unknown PEBS type: {}", value_str),
                        }
                    },
                    "PRECISE_STORE" => precise_store = parse_bool(value_str),
                    "Data_LA" => data_la = parse_bool(value_str),
                    "L1_Hit_Indication" => l1_hit_indication = parse_bool(value_str),
                    "Errata" => {
                        errata = if value_str != "null" {
                            Some(value_str)
                        }
                        else {
                            None
                        };
                    },
                    "Offcore" => offcore = parse_bool(value_str),
                    "ELLC" => {
                        // Ignored due to missing documentation.
                    },
                    _ => panic!("Unknown member: {} in file {}", key, input),
                };
            }

            let ipcd = IntelPerformanceCounterDescription::new(
                event_code,
                umask,
                event_name,
                brief_description,
                public_description,
                counter,
                counter_ht_off,
                pebs_counters,
                sample_after_value,
                msr_index,
                msr_value,
                taken_alone,
                counter_mask,
                invert,
                any_thread,
                edge_detect,
                pebs,
                precise_store,
                data_la,
                l1_hit_indication,
                errata,
                offcore
            );

            //println!("{:?}", ipcd.event_name);
            if do_insert == true {
                builder.entry(ipcd.event_name, format!("{:?}", ipcd).as_str());
            }
        }
    }
    else {
        panic!("JSON data is not an array.");
    }

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join(format!("{}.rs", stem));
    let mut file = BufWriter::new(File::create(&path).unwrap());
    write!(&mut file, "pub static {}: phf::Map<&'static str, IntelPerformanceCounterDescription> = ", variable).unwrap();
    builder.build(&mut file).unwrap();
    write!(&mut file, ";\n").unwrap();
}

fn main() {

    let mut rdr = csv::Reader::from_file("./perfmon_data/mapfile.csv").unwrap();
    let mut data_files = HashMap::new();

    for record in rdr.decode() {
        let (family_model, version, file_name, event_type): (String, String, String, String) = record.unwrap();
        if !data_files.contains_key(&file_name) {
            println!("{} {} {} {}", family_model, version, file_name, event_type);
            data_files.insert(Box::new(file_name), (family_model, version, event_type));
        }
    }

    for (file, data) in &data_files {
        if file.contains("_core_") {
            let (ref family_model, ref version, ref event_type): (String, String, String) = *data;

            println!("Processing {:?} {} {} {}", file, family_model, version, event_type);

            let path = Path::new(file.as_str());
            let stem = path.file_stem().unwrap().to_str().unwrap();
            let stem_upper = stem.to_ascii_uppercase();
            let version_start = stem_upper.find("_V").unwrap();
            let (variable, _) = stem_upper.split_at(version_start);
            parse_performance_counters(format!("perfmon_data{}", file).as_str(), stem, variable);
        }
    }
    //panic!("done");
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::fs;
use std::env;
use std::path::Path;

fn build_libuniarch(arch_path: &std::path::PathBuf) {
    let arch_content = fs::read_dir(arch_path).unwrap();
    let mut gcc_config = gcc::Config::new();

    for p in arch_content {
        let path = p.unwrap().path();
        let extension = path.extension().unwrap().to_str().unwrap();

        if extension == "S" {
            gcc_config.file(path.to_str().unwrap().clone());
        }
    }

    gcc_config.compile("libuniarch.a");
}

fn main() {
    let target = "x86";
    let out_dir = env::var("OUT_DIR").unwrap();
    let out_dir_path = Path::new(&out_dir[..]);
    let arch_path = Path::new("src/arch/").join(target);

    fs::copy(arch_path.join("linker.ld"),
             out_dir_path.join("linker.ld")).unwrap();

    build_libuniarch(&arch_path);
}
<commit_msg>build.rs: Add detection of the target architecture<commit_after>extern crate gcc;

use std::fs;
use std::env;
use std::path::Path;

fn get_target() -> Option<&'static str> {
    let env_target = env::var("TARGET").unwrap();
    let v: Vec<&str> = env_target.split('-').collect();

    match *v.first().unwrap() {
        "i686" => Some("x86"),
        "x86_64" => Some("x86_64"),
        _ => None,
    }
}

fn build_libuniarch(arch_path: &std::path::PathBuf) {
    let arch_content = fs::read_dir(arch_path).unwrap();
    let mut gcc_config = gcc::Config::new();

    for p in arch_content {
        let path = p.unwrap().path();
        let extension = path.extension().unwrap().to_str().unwrap();

        if extension == "S" {
            gcc_config.file(path.to_str().unwrap().clone());
        }
    }

    gcc_config.compile("libuniarch.a");
}

fn main() {
    let target = match get_target() {
        Some(t) => t,
        None => panic!("Unable to determine the target arch"),
    };
    let out_dir = env::var("OUT_DIR").unwrap();
    let out_dir_path = Path::new(&out_dir[..]);
    let arch_path = Path::new("src/arch/").join(target);

    fs::copy(arch_path.join("linker.ld"),
             out_dir_path.join("linker.ld")).unwrap();

    build_libuniarch(&arch_path);
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system cups
    // shared library.
    println!("cargo:rustc-link-lib=cups");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // These fail with size issues.
        .opaque_type("__msfilterreq")
        .opaque_type("group_req")
        .opaque_type("group_source_req")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>Fix linux bindings<commit_after>extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system cups
    // shared library.
    println!("cargo:rustc-link-lib=cups");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // These fail with size issues.
        .opaque_type("__msfilterreq")
        .opaque_type("group_req")
        .opaque_type("group_source_req")
        // This fails with "`IPPORT_RESERVED` already defined".
        .hide_type("IPPORT_RESERVED")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>extern crate capnpc;

fn main() {

    // CAPNP_INCLUDE_DIR=$(shell dirname $(shell which capnp))/../include

    let prefix = {
        let output = ::std::process::Command::new("which").arg("capnp")
            .output().unwrap().stdout;
        let path = ::std::path::Path::new(::std::str::from_utf8(&output).unwrap());
        let mut path1 = path.parent().unwrap().parent().unwrap().to_path_buf();
        path1.push("include/capnp");
        path1
    };

    ::capnpc::compile(&prefix,
                      &[&prefix.clone().join("rpc.capnp"),
                        &prefix.join("rpc-twoparty.capnp")]).unwrap();
}
<commit_msg>Use imports to shorten lines<commit_after>use std::str;
use std::path::Path;
use std::process::Command;

extern crate capnpc;

fn main() {

    // CAPNP_INCLUDE_DIR=$(shell dirname $(shell which capnp))/../include

    let prefix = {
        let output = Command::new("which")
                             .arg("capnp")
                             .output()
                             .unwrap().stdout;

        let path = Path::new(str::from_utf8(&output).unwrap());
        let mut path1 = path.parent().unwrap().parent().unwrap().to_path_buf();
        path1.push("include/capnp");
        path1
    };

    capnpc::compile(&prefix,
                    &[&prefix.clone().join("rpc.capnp"),
                      &prefix.join("rpc-twoparty.capnp")]).unwrap();
}
<|endoftext|>


<commit_before>fn main() {
    let nightly = std::env::var_os("CARGO_FEATURE_NIGHTLY").is_some();
    let has_stable_alloc = || autocfg::new().probe_rustc_version(1, 36);

    if nightly || has_stable_alloc() {
        autocfg::emit("has_extern_crate_alloc")
    }
}
<commit_msg>Only rerun build script if build script changes<commit_after>fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let nightly = std::env::var_os("CARGO_FEATURE_NIGHTLY").is_some();
    let has_stable_alloc = || autocfg::new().probe_rustc_version(1, 36);

    if nightly || has_stable_alloc() {
        autocfg::emit("has_extern_crate_alloc")
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::path::{PathBuf, Path};
use std::fs;

use storage::Storage;
use storage::{ByteEncodable, ByteDecodable};
use utils::persistence::{Volatile, Persistent};

use index::boolean_index;
use index::boolean_index::{Result, Error, BooleanIndex};
use index::boolean_index::posting::Listing;

const REQUIRED_FILES: [&'static str; 2] = [boolean_index::VOCAB_FILENAME, boolean_index::STATISTICS_FILENAME];

/// `IndexBuilder` is used to build `BooleanIndex` instances
pub struct IndexBuilder<TTerm, TStorage> {
    persistence: Option<PathBuf>,
    _storage: PhantomData<TStorage>,
    _term: PhantomData<TTerm>,
}

impl<TTerm, TStorage> IndexBuilder<TTerm, TStorage>
    where TTerm: Ord,
          TStorage: Storage<Listing>
{
    /// Creates a new instance of `IndexBuilder`
    pub fn new() -> Self {
        IndexBuilder {
            persistence: None,
            _storage: PhantomData,
            _term: PhantomData,
        }
    }
}

impl<TTerm, TStorage> IndexBuilder<TTerm, TStorage>
    where TTerm: Ord,
          TStorage: Storage<Listing> + Volatile + 'static
{
    /// Creates a volatile instance of `BooleanIndex`
    /// At the moment `BooleanIndex` does not support adding or removing
    /// documents from the index.
    /// So all index which should be indexed need to be passed to this method
    pub fn create<TCollection, TDoc>(&self, documents: TCollection) -> Result<BooleanIndex<TTerm>>
        where TCollection: Iterator<Item = TDoc>,
              TDoc: Iterator<Item = TTerm>
    {
        BooleanIndex::new(TStorage::new(), documents)
    }
}

impl<TTerm, TStorage> IndexBuilder<TTerm, TStorage>
    where TTerm: Ord + ByteDecodable + ByteEncodable,
          TStorage: Storage<Listing> + Persistent + 'static
{
    /// Enables a persistent index at the passed path.
    /// `at` must be either a prefilled directory if the `load` method is to be
    /// called
    /// or an empty directory if a new index is created with
    /// `create_persistence`
    pub fn persist(mut self, at: &Path) -> Self {
        self.persistence = Some(at.to_path_buf());
        self
    }

    /// A new index is created and saved in the directory passed to the
    /// `persist` method
    /// Returns a `BuilderError` if `persist` was not called or if directory is
    /// not empty
    pub fn create_persistent<TDocsIterator, TDocIterator>(&self,
                                                          documents: TDocsIterator)
                                                          -> Result<BooleanIndex<TTerm>>
        where TDocsIterator: Iterator<Item = TDocIterator>,
              TDocIterator: Iterator<Item = TTerm>
    {
        let path = try!(self.check_persist_path());
        BooleanIndex::new_persistent(TStorage::create(path).unwrap(), documents, path)
    }

    /// Loads an index from a previously filled directory.
    /// Returns a `BuilderError` if directory is empty or does not contain
    /// valid data
    pub fn load(&self) -> Result<BooleanIndex<TTerm>> {
        let path = try!(self.check_persist_path());
        BooleanIndex::load::<TStorage>(path)
    }

    fn check_persist_path(&self) -> Result<&Path> {
        if let Some(ref path) = self.persistence {
            if path.is_dir() {
                let paths = try!(fs::read_dir(path));
                // Path is a directory and seems to exist. Lets see if all the files are present
                let mut required_files = Self::required_files();
                for path in paths.filter(|p| p.is_ok()).map(|p| p.unwrap()) {
                    if let Some(pos) = required_files.iter().position(|f| (**f) == path.file_name()) {
                        required_files.swap_remove(pos);
                    }
                }
                if required_files.is_empty() {
                    Ok(path)
                } else {
                    Err(Error::MissingIndexFiles(required_files))
                }
            } else {
                Err(Error::PersistPathIsFile)
            }
        } else {
            Err(Error::PersistPathNotSpecified)
        }
    }

    fn required_files() -> Vec<&'static str> {
        let mut required_files = REQUIRED_FILES.to_vec();
        required_files.extend_from_slice(TStorage::associated_files());
        required_files
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use index::boolean_index::Error;
    use storage::FsStorage;
    use std::env;
    use std::fs;

    #[test]
    fn empty_folder() {
        let path = &env::temp_dir().join("perlin_test_empty_dir");
        fs::create_dir_all(path).unwrap();

        let result = IndexBuilder::<usize, FsStorage<_>>::new().persist(path).load();
        assert!(if let Err(Error::MissingIndexFiles(_)) = result {
            true
        } else {
            false
        });
    }

    #[test]
    fn file_not_folder() {
        let path = &env::temp_dir().join("perlin_test_file.bin");
        fs::File::create(path).unwrap();

        let result = IndexBuilder::<usize, FsStorage<_>>::new().persist(path).load();
        assert!(if let Err(Error::PersistPathIsFile) = result {
            true
        } else {
            false
        });
    }

    #[test]
    fn corrupt_file() {
        let path = &env::temp_dir().join("perlin_corrupted_files_test_dir");
        fs::create_dir_all(path).unwrap();
        for file in IndexBuilder::<usize, FsStorage<_>>::required_files() {
            fs::File::create(path.join(file)).unwrap();
        }

        let result = IndexBuilder::<usize, FsStorage<_>>::new().persist(path).load();
        assert!(if let Err(Error::CorruptedIndexFile(_)) = result {
            true
        } else {
            false
        });
    }
}
<commit_msg>Fix bug in index_builder<commit_after>use std::marker::PhantomData;
use std::path::{PathBuf, Path};
use std::fs;

use storage::Storage;
use storage::{ByteEncodable, ByteDecodable};
use utils::persistence::{Volatile, Persistent};

use index::boolean_index;
use index::boolean_index::{Result, Error, BooleanIndex};
use index::boolean_index::posting::Listing;

const REQUIRED_FILES: [&'static str; 2] = [boolean_index::VOCAB_FILENAME, boolean_index::STATISTICS_FILENAME];

/// `IndexBuilder` is used to build `BooleanIndex` instances
pub struct IndexBuilder<TTerm, TStorage> {
    persistence: Option<PathBuf>,
    _storage: PhantomData<TStorage>,
    _term: PhantomData<TTerm>,
}

impl<TTerm, TStorage> IndexBuilder<TTerm, TStorage>
    where TTerm: Ord,
          TStorage: Storage<Listing>
{
    /// Creates a new instance of `IndexBuilder`
    pub fn new() -> Self {
        IndexBuilder {
            persistence: None,
            _storage: PhantomData,
            _term: PhantomData,
        }
    }
}

impl<TTerm, TStorage> IndexBuilder<TTerm, TStorage>
    where TTerm: Ord,
          TStorage: Storage<Listing> + Volatile + 'static
{
    /// Creates a volatile instance of `BooleanIndex`
    /// At the moment `BooleanIndex` does not support adding or removing
    /// documents from the index.
    /// So all index which should be indexed need to be passed to this method
    pub fn create<TCollection, TDoc>(&self, documents: TCollection) -> Result<BooleanIndex<TTerm>>
        where TCollection: Iterator<Item = TDoc>,
              TDoc: Iterator<Item = TTerm>
    {
        BooleanIndex::new(TStorage::new(), documents)
    }
}

impl<TTerm, TStorage> IndexBuilder<TTerm, TStorage>
    where TTerm: Ord + ByteDecodable + ByteEncodable,
          TStorage: Storage<Listing> + Persistent + 'static
{
    /// Enables a persistent index at the passed path.
    /// `at` must be either a prefilled directory if the `load` method is to be
    /// called
    /// or an empty directory if a new index is created with
    /// `create_persistence`
    pub fn persist(mut self, at: &Path) -> Self {
        self.persistence = Some(at.to_path_buf());
        self
    }

    /// A new index is created and saved in the directory passed to the
    /// `persist` method
    /// Returns a `BuilderError` if `persist` was not called or if directory is
    /// not empty
    pub fn create_persistent<TDocsIterator, TDocIterator>(&self,
                                                          documents: TDocsIterator)
                                                          -> Result<BooleanIndex<TTerm>>
        where TDocsIterator: Iterator<Item = TDocIterator>,
              TDocIterator: Iterator<Item = TTerm>
    {
        let path = try!(self.check_persist_path(false));
        BooleanIndex::new_persistent(TStorage::create(path).unwrap(), documents, path)
    }

    /// Loads an index from a previously filled directory.
    /// Returns a `BuilderError` if directory is empty or does not contain
    /// valid data
    pub fn load(&self) -> Result<BooleanIndex<TTerm>> {
        let path = try!(self.check_persist_path(true));
        BooleanIndex::load::<TStorage>(path)
    }

    fn check_persist_path(&self, check_for_existing_files: bool) -> Result<&Path> {
        if let Some(ref path) = self.persistence {
            if path.is_dir() {
                let paths = try!(fs::read_dir(path));
                // Path is a directory and seems to exist. Lets see if all the files are present
                if !check_for_existing_files {
                    return Ok(path);
                }
                let mut required_files = Self::required_files();
                for path in paths.filter(|p| p.is_ok()).map(|p| p.unwrap()) {
                    if let Some(pos) = required_files.iter().position(|f| (**f) == path.file_name()) {
                        required_files.swap_remove(pos);
                    }
                }
                if required_files.is_empty() {
                    Ok(path)
                } else {
                    Err(Error::MissingIndexFiles(required_files))
                }
            } else {
                Err(Error::PersistPathIsFile)
            }
        } else {
            Err(Error::PersistPathNotSpecified)
        }
    }

    fn required_files() -> Vec<&'static str> {
        let mut required_files = REQUIRED_FILES.to_vec();
        required_files.extend_from_slice(TStorage::associated_files());
        required_files
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use index::boolean_index::Error;
    use storage::FsStorage;
    use std::env;
    use std::fs;

    #[test]
    fn empty_folder() {
        let path = &env::temp_dir().join("perlin_test_empty_dir");
        fs::create_dir_all(path).unwrap();

        let result = IndexBuilder::<usize, FsStorage<_>>::new().persist(path).load();
        assert!(if let Err(Error::MissingIndexFiles(_)) = result {
            true
        } else {
            false
        });
    }

    #[test]
    fn file_not_folder() {
        let path = &env::temp_dir().join("perlin_test_file.bin");
        fs::File::create(path).unwrap();

        let result = IndexBuilder::<usize, FsStorage<_>>::new().persist(path).load();
        assert!(if let Err(Error::PersistPathIsFile) = result {
            true
        } else {
            false
        });
    }

    #[test]
    fn corrupt_file() {
        let path = &env::temp_dir().join("perlin_corrupted_files_test_dir");
        fs::create_dir_all(path).unwrap();
        for file in IndexBuilder::<usize, FsStorage<_>>::required_files() {
            fs::File::create(path.join(file)).unwrap();
        }

        let result = IndexBuilder::<usize, FsStorage<_>>::new().persist(path).load();
        assert!(if let Err(Error::CorruptedIndexFile(_)) = result {
            true
        } else {
            false
        });
    }
}
<|endoftext|>