<commit_before>use std::env;
use std::io::{stdout, stderr, Write};
use std::path::{Path, PathBuf};
use std::fs::metadata;
use std::os::unix::fs::MetadataExt;

use libc::getuid;

use options::build_mode::{build_mode, BuildMode};
use config::{Config, Settings, find_config};
use config::read_settings::{read_settings, MergedSettings};
use argparse::{ArgumentParser, Store, List, Collect, Print, StoreFalse, StoreTrue};

mod list;
mod user;
mod pack;
mod push;
mod build;
mod storage;
mod underscore;
mod completion;
mod commands;

mod supervisor;
mod simple;

mod wrap;
pub mod system;
pub mod network;
mod socket;
mod volumes;
mod options;
mod prerequisites;

pub struct Context {
    config: Config,
    settings: Settings,
    ext_settings: MergedSettings,
    workdir: PathBuf,
    config_dir: PathBuf,
    build_mode: BuildMode,
    prerequisites: bool,
    isolate_network: bool
}

fn check_export(cmd: &String) -> Option<String> {
    if cmd == "/proc/self/exe" {
        return None;
    }
    match cmd.rfind("/") {
        Some(slash) => {
            let exe = &cmd[slash+1..];
            if exe == "vagga" || exe.starts_with("vagga_") {
                Some(exe.to_owned())
            } else {
                None
            }
        }
        None => Some(cmd.clone()),
    }
}

pub fn run(input_args: Vec<String>) -> i32 {
    let mut err = stderr();
    let workdir = env::current_dir().unwrap();

    let (config, cfg_dir) = match find_config(&workdir, true) {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };
    // Not sure this is a best place, but the variable is needed for correct
    // reading of settings
    if let Some(x) = env::var_os("HOME") {
        env::set_var("_VAGGA_HOME", x);
    }

    let (ext_settings, int_settings) = match read_settings(&cfg_dir)
    {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };

    let mut commands = Vec::<String>::new();
    let mut cname = "".to_string();
    let mut args = vec!();
    let mut set_env = Vec::<String>::new();
    let mut propagate_env = Vec::<String>::new();
    let mut bmode = Default::default();
    let mut owner_check = true;
    let mut prerequisites = true;
    let mut isolate_network = false;

    let export_command = input_args.get(0).and_then(check_export);
    if !int_settings.run_symlinks_as_commands || export_command.is_none() {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a command in container, optionally builds container if that
            does not exists or outdated.

            Run `vagga` without arguments to see the list of commands.
            ");
        ap.add_option(&["-V", "--version"],
            Print(env!("VAGGA_VERSION").to_string()),
            "Show vagga version and exit");
        ap.refer(&mut set_env)
          .add_option(&["-E", "--env", "--environ"], Collect,
                "Set environment variable for running command")
          .metavar("NAME=VALUE");
        ap.refer(&mut propagate_env)
          .add_option(&["-e", "--use-env"], Collect,
                "Propagate variable VAR into command environment")
          .metavar("VAR");
        ap.refer(&mut owner_check)
          .add_option(&["--ignore-owner-check"], StoreFalse,
                "Ignore checking owner of the project directory");
        ap.refer(&mut prerequisites)
            .add_option(&["--no-prerequisites"], StoreFalse,
            "Run only specified command(s), don't run prerequisites");
        ap.refer(&mut isolate_network)
            .add_option(
                &["--isolate-network", "--no-network", "--no-net"],
                StoreTrue,
                "Run command(s) inside isolated network");
        build_mode(&mut ap, &mut bmode);
        ap.refer(&mut commands)
          .add_option(&["-m", "--run-multi"], List, "
            Run the following list of commands. Each without an arguments.
            When any of them fails, stop the chain. Basically it's the
            shortcut to `vagga cmd1 && vagga cmd2` except containers for
            `cmd2` are built beforehand, for your convenience. Also builtin
            commands (those starting with underscore) do not work with
            `vagga -m`");
        ap.refer(&mut cname)
          .add_argument("command", Store,
                "A vagga command to run");
        ap.refer(&mut args)
          .add_argument("args", List,
                "Arguments for the command");
        ap.stop_on_first_argument(true);
        ap.silence_double_dash(false);
        match ap.parse(input_args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return 0,
            Err(_) => return 122,
        }
    } else {
        let export_command = export_command.unwrap();
        for (name, cmd) in &config.commands {
            match cmd.link() {
                Some(ref lnk) if lnk.name == export_command => {
                    cname = name.clone();
                }
                _ => {}
            }
        }
        if cname == "" {
            writeln!(&mut err, "Can't find command {:?}", export_command).ok();
            return 127;
        }
    }

    if &cname[..] == "_network" {
        args.insert(0, "vagga _network".to_string());
        return ::network::run(args);
    }

    if owner_check {
        let uid = unsafe { getuid() };
        match metadata(&cfg_dir) {
            Ok(ref stat) if stat.uid() == uid  => {}
            Ok(_) => {
                if uid == 0 {
                    writeln!(&mut err, "You should not run vagga as root \
                        (see http://bit.ly/err_root)").ok();
                    return 122;
                } else {
                    warn!("You are running vagga as a user \
                        different from the owner of project directory. \
                        You may not have needed permissions \
                        (see http://bit.ly/err_root)");
                }
            }
            Err(e) => {
                writeln!(&mut err, "Can't stat {:?}: {}", cfg_dir, e).ok();
                return 126;
            }
        }
    }

    let int_workdir = workdir.strip_prefix(&cfg_dir)
                             .unwrap_or(&Path::new("."));

    for k in propagate_env.into_iter() {
        if k.chars().find(|&c| c == '=').is_some() {
            writeln!(&mut err, "Environment variable name \
                (for option `-e`/`--use-env`) \
                can't contain equals `=` character. \
                To set key-value pair use `-E`/`--environ` option").ok();
            return 126;
        } else {
            env::set_var(&("VAGGAENV_".to_string() + &k[..]),
                env::var_os(&k).unwrap_or(From::from("")));
        }
    }
    for pair in set_env.into_iter() {
        let mut pairiter = pair[..].splitn(2, '=');
        let key = "VAGGAENV_".to_string() + pairiter.next().unwrap();
        if let Some(value) = pairiter.next() {
            env::set_var(&key, value.to_string());
        } else {
            env::remove_var(&key);
        }
    }

    let context = Context {
        config: config,
        settings: int_settings,
        ext_settings: ext_settings,
        workdir: int_workdir.to_path_buf(),
        config_dir: cfg_dir.to_path_buf(),
        build_mode: bmode,
        prerequisites: prerequisites,
        isolate_network: isolate_network,
    };

    if commands.len() > 0 {
        let result = user::run_multiple_commands(&context, commands);
        match result {
            Ok(rc) => {
                return rc;
            }
            Err(text) =>  {
                writeln!(&mut err, "{}", text).ok();
                return 121;
            }
        }
    }

    let result:Result<i32, String> = match &cname[..] {
        "" => {
            list::print_help(&context.config)
        }
        "_create_netns" => {
            network::create_netns(&context.config, args)
        }
        "_destroy_netns" => {
            network::destroy_netns(&context.config, args)
        }
        "_list" => {
            list::print_list(&context.config, args)
        }
        "_version_hash" => {
            underscore::version_hash(&context, &cname, args)
        }
        "_build_shell" | "_clean" | "_check_overlayfs_support" => {
            underscore::passthrough(&context, &cname, args)
        }
        "_base_dir" => {
            println!("{}", cfg_dir.display());
            Ok(1)
        }
        "_relative_work_dir" => {
            println!("{}", int_workdir.display());
            Ok(1)
        }
        "_build" => {
            build::build_command(&context, args)
        }
        "_run" => {
            underscore::run_command(&context, args)
        }
        "_run_in_netns" => {
            underscore::run_in_netns(&context, cname, args)
        }
        "_pack_image" => {
            pack::pack_command(&context, args)
        }
        "_push_image" => {
            push::push_command(&context, args)
        }
        "_init_storage_dir" => {
            storage::init_dir(&context.ext_settings, &cfg_dir, args)
        }
        "_compgen" => {
            completion::generate_completions(&context.config, args)
        }
        "_update_commands" => {
            commands::update_commands(&context, args)
        }
        _ => {
            user::run_user_command(&context, cname, args)
        }
    };

    match result {
        Ok(rc) => {
            return rc;
        }
        Err(text) =>  {
            writeln!(&mut err, "{}", text).ok();
            return 121;
        }
    }
}
<commit_msg>Fix typo in symlink processing code<commit_after>use std::env;
use std::io::{stdout, stderr, Write};
use std::path::{Path, PathBuf};
use std::fs::metadata;
use std::os::unix::fs::MetadataExt;

use libc::getuid;

use options::build_mode::{build_mode, BuildMode};
use config::{Config, Settings, find_config};
use config::read_settings::{read_settings, MergedSettings};
use argparse::{ArgumentParser, Store, List, Collect, Print, StoreFalse, StoreTrue};

mod list;
mod user;
mod pack;
mod push;
mod build;
mod storage;
mod underscore;
mod completion;
mod commands;

mod supervisor;
mod simple;

mod wrap;
pub mod system;
pub mod network;
mod socket;
mod volumes;
mod options;
mod prerequisites;

pub struct Context {
    config: Config,
    settings: Settings,
    ext_settings: MergedSettings,
    workdir: PathBuf,
    config_dir: PathBuf,
    build_mode: BuildMode,
    prerequisites: bool,
    isolate_network: bool
}

fn check_export(cmd: &String) -> Option<String> {
    if cmd == "/proc/self/exe" {
        return None;
    }
    match cmd.rfind("/") {
        Some(slash) => {
            let exe = &cmd[slash+1..];
            if exe == "vagga" || exe.starts_with("vagga_") {
                None
            } else {
                Some(exe.to_owned())
            }
        }
        None => Some(cmd.clone()),
    }
}

pub fn run(input_args: Vec<String>) -> i32 {
    let mut err = stderr();
    let workdir = env::current_dir().unwrap();

    let (config, cfg_dir) = match find_config(&workdir, true) {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };
    // Not sure this is a best place, but the variable is needed for correct
    // reading of settings
    if let Some(x) = env::var_os("HOME") {
        env::set_var("_VAGGA_HOME", x);
    }

    let (ext_settings, int_settings) = match read_settings(&cfg_dir)
    {
        Ok(tup) => tup,
        Err(e) => {
            writeln!(&mut err, "{}", e).ok();
            return 126;
        }
    };

    let mut commands = Vec::<String>::new();
    let mut cname = "".to_string();
    let mut args = vec!();
    let mut set_env = Vec::<String>::new();
    let mut propagate_env = Vec::<String>::new();
    let mut bmode = Default::default();
    let mut owner_check = true;
    let mut prerequisites = true;
    let mut isolate_network = false;

    let export_command = input_args.get(0).and_then(check_export);
    if !int_settings.run_symlinks_as_commands || export_command.is_none() {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a command in container, optionally builds container if that
            does not exists or outdated.

            Run `vagga` without arguments to see the list of commands.
            ");
        ap.add_option(&["-V", "--version"],
            Print(env!("VAGGA_VERSION").to_string()),
            "Show vagga version and exit");
        ap.refer(&mut set_env)
          .add_option(&["-E", "--env", "--environ"], Collect,
                "Set environment variable for running command")
          .metavar("NAME=VALUE");
        ap.refer(&mut propagate_env)
          .add_option(&["-e", "--use-env"], Collect,
                "Propagate variable VAR into command environment")
          .metavar("VAR");
        ap.refer(&mut owner_check)
          .add_option(&["--ignore-owner-check"], StoreFalse,
                "Ignore checking owner of the project directory");
        ap.refer(&mut prerequisites)
            .add_option(&["--no-prerequisites"], StoreFalse,
            "Run only specified command(s), don't run prerequisites");
        ap.refer(&mut isolate_network)
            .add_option(
                &["--isolate-network", "--no-network", "--no-net"],
                StoreTrue,
                "Run command(s) inside isolated network");
        build_mode(&mut ap, &mut bmode);
        ap.refer(&mut commands)
          .add_option(&["-m", "--run-multi"], List, "
            Run the following list of commands. Each without an arguments.
            When any of them fails, stop the chain. Basically it's the
            shortcut to `vagga cmd1 && vagga cmd2` except containers for
            `cmd2` are built beforehand, for your convenience. Also builtin
            commands (those starting with underscore) do not work with
            `vagga -m`");
        ap.refer(&mut cname)
          .add_argument("command", Store,
                "A vagga command to run");
        ap.refer(&mut args)
          .add_argument("args", List,
                "Arguments for the command");
        ap.stop_on_first_argument(true);
        ap.silence_double_dash(false);
        match ap.parse(input_args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return 0,
            Err(_) => return 122,
        }
    } else {
        let export_command = export_command.unwrap();
        for (name, cmd) in &config.commands {
            match cmd.link() {
                Some(ref lnk) if lnk.name == export_command => {
                    cname = name.clone();
                }
                _ => {}
            }
        }
        if cname == "" {
            writeln!(&mut err, "Can't find command {:?}", export_command).ok();
            return 127;
        }
    }

    if &cname[..] == "_network" {
        args.insert(0, "vagga _network".to_string());
        return ::network::run(args);
    }

    if owner_check {
        let uid = unsafe { getuid() };
        match metadata(&cfg_dir) {
            Ok(ref stat) if stat.uid() == uid  => {}
            Ok(_) => {
                if uid == 0 {
                    writeln!(&mut err, "You should not run vagga as root \
                        (see http://bit.ly/err_root)").ok();
                    return 122;
                } else {
                    warn!("You are running vagga as a user \
                        different from the owner of project directory. \
                        You may not have needed permissions \
                        (see http://bit.ly/err_root)");
                }
            }
            Err(e) => {
                writeln!(&mut err, "Can't stat {:?}: {}", cfg_dir, e).ok();
                return 126;
            }
        }
    }

    let int_workdir = workdir.strip_prefix(&cfg_dir)
                             .unwrap_or(&Path::new("."));

    for k in propagate_env.into_iter() {
        if k.chars().find(|&c| c == '=').is_some() {
            writeln!(&mut err, "Environment variable name \
                (for option `-e`/`--use-env`) \
                can't contain equals `=` character. \
                To set key-value pair use `-E`/`--environ` option").ok();
            return 126;
        } else {
            env::set_var(&("VAGGAENV_".to_string() + &k[..]),
                env::var_os(&k).unwrap_or(From::from("")));
        }
    }
    for pair in set_env.into_iter() {
        let mut pairiter = pair[..].splitn(2, '=');
        let key = "VAGGAENV_".to_string() + pairiter.next().unwrap();
        if let Some(value) = pairiter.next() {
            env::set_var(&key, value.to_string());
        } else {
            env::remove_var(&key);
        }
    }

    let context = Context {
        config: config,
        settings: int_settings,
        ext_settings: ext_settings,
        workdir: int_workdir.to_path_buf(),
        config_dir: cfg_dir.to_path_buf(),
        build_mode: bmode,
        prerequisites: prerequisites,
        isolate_network: isolate_network,
    };

    if commands.len() > 0 {
        let result = user::run_multiple_commands(&context, commands);
        match result {
            Ok(rc) => {
                return rc;
            }
            Err(text) =>  {
                writeln!(&mut err, "{}", text).ok();
                return 121;
            }
        }
    }

    let result:Result<i32, String> = match &cname[..] {
        "" => {
            list::print_help(&context.config)
        }
        "_create_netns" => {
            network::create_netns(&context.config, args)
        }
        "_destroy_netns" => {
            network::destroy_netns(&context.config, args)
        }
        "_list" => {
            list::print_list(&context.config, args)
        }
        "_version_hash" => {
            underscore::version_hash(&context, &cname, args)
        }
        "_build_shell" | "_clean" | "_check_overlayfs_support" => {
            underscore::passthrough(&context, &cname, args)
        }
        "_base_dir" => {
            println!("{}", cfg_dir.display());
            Ok(1)
        }
        "_relative_work_dir" => {
            println!("{}", int_workdir.display());
            Ok(1)
        }
        "_build" => {
            build::build_command(&context, args)
        }
        "_run" => {
            underscore::run_command(&context, args)
        }
        "_run_in_netns" => {
            underscore::run_in_netns(&context, cname, args)
        }
        "_pack_image" => {
            pack::pack_command(&context, args)
        }
        "_push_image" => {
            push::push_command(&context, args)
        }
        "_init_storage_dir" => {
            storage::init_dir(&context.ext_settings, &cfg_dir, args)
        }
        "_compgen" => {
            completion::generate_completions(&context.config, args)
        }
        "_update_commands" => {
            commands::update_commands(&context, args)
        }
        _ => {
            user::run_user_command(&context, cname, args)
        }
    };

    match result {
        Ok(rc) => {
            return rc;
        }
        Err(text) =>  {
            writeln!(&mut err, "{}", text).ok();
            return 121;
        }
    }
}
<|endoftext|>


<commit_before>
extern crate clap;

// Time Start: Mon, 02 Dec 2019 12:59:41 -0500
// Time Finish 1: Mon, 02 Dec 2019 14:46:54 -0500 (1 hour, 47 minutes, 13 seconds)
// Time Finish 2: Mon, 02 Dec 2019 14:53:56 -0500 (7 minutes, 2 seconds)
// Time Total: 1 hour, 54 minutes, 15 seconds

use std::convert::TryFrom;
use std::fmt;
use std::fs;

use clap::{Arg, App};

struct Intcode {
    program: Vec<i32>,
    pos: usize,
}

impl Intcode {
    fn new() -> Intcode {
        return Intcode { program: Vec::new(), pos: 0 };
    }

    fn load(fname: &String) -> Intcode {
        let mut ic = Intcode::new();
        // One line, CSV integers
        let csv = fs::read_to_string(fname).unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        for instr in csv.trim().split(',') {
            ic.program.push(
                instr.parse().unwrap_or_else(|err| panic!("Not an integer '{}' in {}: {}", instr, fname, err))
            );
        }
        return ic;
    }

    fn is_halted(&self) -> bool { 99 == *self.program.get(self.pos).unwrap_or(&99) }

    fn run(&mut self) {
        while self.step() { }
    }

    fn step(&mut self) -> bool {
        let step = match self.peeka(0) {
            1 => {
                let (a, b, c) = (self.peeka(1),  self.peeka(2),  self.peeka(3)); // immutable borrow
                self.add(a, b, c); // mutable borrow
                4
            },
            2 => {
                let (a, b, c) = (self.peeka(1),  self.peeka(2),  self.peeka(3)); // immutable borrow
                self.mul(a, b, c); // mutable borrow
                4
            },
            99 => 0,
            x_ => panic!("Unknown command at position {}: {}", self.pos, x_),
        };

        self.pos += step;
        return step > 0;
    }

    fn add(&mut self, a: usize, b: usize, c: usize) {
        self.program[c] = self.program[a] + self.program[b];
    }

    fn mul(&mut self, a: usize, b: usize, c: usize) {
        self.program[c] = self.program[a] * self.program[b];
    }

    fn get(&self, i: usize) -> i32 { self.program[i] }
    fn peek(&self, i: usize) -> i32 { self.get(self.pos + i) }
    fn geta(&self, i: usize) -> usize {
        usize::try_from(
            self.program[i]
        ).unwrap_or_else(|err| panic!("Expected address at position {}, found '{}' instead: {}", i, self.program[i], err))
    }
    fn peeka(&self, i: usize) -> usize { self.geta(self.pos + i) }
}

impl fmt::Display for Intcode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.program)
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 02")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("02.in"));

    {
        let mut ic = Intcode::load(&fname);
        ic.program[1] = 12;
        ic.program[2] = 2;
        ic.run();
        println!("Part 1: {}", ic.get(0));
    }

    for noun in 0..99 {
        for verb in 0..99 {
            let mut ic = Intcode::load(&fname);
            ic.program[1] = noun;
            ic.program[2] = verb;
            ic.run();
            if ic.get(0) == 19690720 {
                println!("Part 2: got 19690720 with noun={}, verb={}, key={}", noun, verb, 100 * noun + verb);
                return;
            }
        }
    }
}
<commit_msg>Sigh, python-style ranges<commit_after>
extern crate clap;

// Time Start: Mon, 02 Dec 2019 12:59:41 -0500
// Time Finish 1: Mon, 02 Dec 2019 14:46:54 -0500 (1 hour, 47 minutes, 13 seconds)
// Time Finish 2: Mon, 02 Dec 2019 14:53:56 -0500 (7 minutes, 2 seconds)
// Time Total: 1 hour, 54 minutes, 15 seconds

use std::convert::TryFrom;
use std::fmt;
use std::fs;

use clap::{Arg, App};

struct Intcode {
    program: Vec<i32>,
    pos: usize,
}

impl Intcode {
    fn new() -> Intcode {
        return Intcode { program: Vec::new(), pos: 0 };
    }

    fn load(fname: &String) -> Intcode {
        let mut ic = Intcode::new();
        // One line, CSV integers
        let csv = fs::read_to_string(fname).unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));

        for instr in csv.trim().split(',') {
            ic.program.push(
                instr.parse().unwrap_or_else(|err| panic!("Not an integer '{}' in {}: {}", instr, fname, err))
            );
        }
        return ic;
    }

    fn is_halted(&self) -> bool { 99 == *self.program.get(self.pos).unwrap_or(&99) }

    fn run(&mut self) {
        while self.step() { }
    }

    fn step(&mut self) -> bool {
        let step = match self.peeka(0) {
            1 => {
                let (a, b, c) = (self.peeka(1),  self.peeka(2),  self.peeka(3)); // immutable borrow
                self.add(a, b, c); // mutable borrow
                4
            },
            2 => {
                let (a, b, c) = (self.peeka(1),  self.peeka(2),  self.peeka(3)); // immutable borrow
                self.mul(a, b, c); // mutable borrow
                4
            },
            99 => 0,
            x_ => panic!("Unknown command at position {}: {}", self.pos, x_),
        };

        self.pos += step;
        return step > 0;
    }

    fn add(&mut self, a: usize, b: usize, c: usize) {
        self.program[c] = self.program[a] + self.program[b];
    }

    fn mul(&mut self, a: usize, b: usize, c: usize) {
        self.program[c] = self.program[a] * self.program[b];
    }

    fn get(&self, i: usize) -> i32 { self.program[i] }
    fn peek(&self, i: usize) -> i32 { self.get(self.pos + i) }
    fn geta(&self, i: usize) -> usize {
        usize::try_from(
            self.program[i]
        ).unwrap_or_else(|err| panic!("Expected address at position {}, found '{}' instead: {}", i, self.program[i], err))
    }
    fn peeka(&self, i: usize) -> usize { self.geta(self.pos + i) }
}

impl fmt::Display for Intcode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.program)
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 02")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("02.in"));

    {
        let mut ic = Intcode::load(&fname);
        ic.program[1] = 12;
        ic.program[2] = 2;
        ic.run();
        println!("Part 1: {}", ic.get(0));
    }

    for noun in 0..100 {
        for verb in 0..100 {
            let mut ic = Intcode::load(&fname);
            ic.program[1] = noun;
            ic.program[2] = verb;
            ic.run();
            if ic.get(0) == 19690720 {
                println!("Part 2: got 19690720 with noun={}, verb={}, key={}", noun, verb, 100 * noun + verb);
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::Error;
use loading::*;
use semver::Version;
use std::ffi::CStr;
use std::mem::transmute;
use std::os::raw::c_char;
use std::path::PathBuf;

pub fn find_python() -> Result<PathBuf, Error> {
    let locations = get_candidate_locations();
    for path in locations {
        unsafe {
            match load_library(&path, true) {
                Ok(handle) => {
                    if let Ok(ptr) = find_symbol(handle, "Py_GetVersion") {
                        let py_getversion: unsafe extern "C" fn() -> *const c_char = transmute(ptr);
                        let version = CStr::from_ptr(py_getversion());
                        if let Ok(version) = version.to_str() {
                            if let Some(version) = version.split(" ").next() {
                                if let Ok(version) = Version::parse(version) {
                                    if version.major == 3 && version.minor >= 3 {
                                        free_library(handle)?;
                                        return Ok(path);
                                    }
                                }
                            }
                        }
                    }
                    free_library(handle)?;
                }
                Err(_) => {}
            }
        }
    }
    Err("No suitable Python 3 installation found.".into())
}

#[cfg(target_os = "linux")]
fn get_candidate_locations() -> Vec<PathBuf> {
    use std::io::{BufRead, BufReader};

    fn query_sysconfig() -> Result<PathBuf, Error> {
        let result = std::process::Command::new("python3")
            .arg("-c")
            .arg("import sysconfig; print(sysconfig.get_config_var('INSTSONAME'))")
            .output()?;
        if !result.status.success() {
            return Err(format!("python exit code: {:?}", result.status.code()).into());
        }
        let stdout = BufReader::new(&result.stdout[..]);
        let mut lines = stdout.lines();
        let path = PathBuf::from(lines.next().unwrap()?);
        Ok(path)
    }

    match query_sysconfig() {
        Ok(path) => vec![path],
        Err(err) => {
            eprintln!("{}", err);
            vec![]
        }
    }
}

#[cfg(target_os = "macos")]
fn get_candidate_locations() -> Vec<PathBuf> {
    use std::io::{BufRead, BufReader};

    fn query_sysconfig() -> Result<Vec<PathBuf>, Error> {
        let result = std::process::Command::new("python3")
            .arg("-c")
            .arg("import sysconfig; print(sysconfig.get_config_var('PYTHONFRAMEWORKPREFIX')); print(sysconfig.get_config_var('LDLIBRARY'))")
            .output()?;
        if !result.status.success() {
            return Err(format!("python exit code: {:?}", result.status.code()).into());
        }
        let stdout = BufReader::new(&result.stdout[..]);
        let mut lines = stdout.lines();
        let prefix = lines.next().unwrap()?;
        let libname = lines.next().unwrap()?;

        let mut results = vec![];
        results.push(PathBuf::from(&libname));

        let mut path = PathBuf::from(prefix);
        path.push(&libname);
        results.push(path);

        let mut path = PathBuf::from("/Library/Developer/CommandLineTools/Library/Frameworks");
        path.push(&libname);
        results.push(path);

        Ok(results)
    }

    match query_sysconfig() {
        Ok(results) => results,
        Err(err) => {
            eprintln!("{}", err);
            vec![]
        }
    }
}

#[cfg(target_os = "windows")]
fn get_candidate_locations() -> Vec<PathBuf> {
    use winreg::enums::*;

    let mut results = vec![];
    for hive in &[HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE] {
        if let Ok(hk_python) = winreg::RegKey::predef(*hive).open_subkey("Software\\Python\\PythonCore") {
            for ver_tag in hk_python.enum_keys() {
                if let Ok(ver_tag) = ver_tag {
                    if let Ok(hk_version) = hk_python.open_subkey(ver_tag) {
                        if let Ok(hk_install_path) = hk_version.open_subkey("InstallPath") {
                            if let Ok(install_path) = hk_install_path.get_value::<String, _>("") {
                                let mut path = PathBuf::from(install_path);
                                path.push("python3.dll");
                                results.push(path);
                            }
                        }
                    }
                }
            }
        }
    }
    results
}
<commit_msg>find_python<commit_after>use crate::Error;
use loading::*;
use semver::Version;
use std::ffi::CStr;
use std::mem::transmute;
use std::os::raw::c_char;
use std::path::PathBuf;

pub fn find_python() -> Result<PathBuf, Error> {
    let locations = get_candidate_locations();
    for path in locations {
        unsafe {
            match load_library(&path, true) {
                Ok(handle) => {
                    if let Ok(ptr) = find_symbol(handle, "Py_GetVersion") {
                        let py_getversion: unsafe extern "C" fn() -> *const c_char = transmute(ptr);
                        let version = CStr::from_ptr(py_getversion());
                        if let Ok(version) = version.to_str() {
                            if let Some(version) = version.split(" ").next() {
                                if let Ok(version) = Version::parse(version) {
                                    if version.major == 3 && version.minor >= 3 {
                                        free_library(handle)?;
                                        return Ok(path);
                                    }
                                }
                            }
                        }
                    }
                    free_library(handle)?;
                }
                Err(_) => {}
            }
        }
    }
    Err("No suitable Python 3 installation found.".into())
}

#[cfg(target_os = "linux")]
fn get_candidate_locations() -> Vec<PathBuf> {
    use std::io::{BufRead, BufReader};

    fn query_sysconfig() -> Result<PathBuf, Error> {
        let result = std::process::Command::new("python3")
            .arg("-c")
            .arg("import sysconfig; print(sysconfig.get_config_var('INSTSONAME'))")
            .output()?;
        if !result.status.success() {
            return Err(format!("python exit code: {:?}", result.status.code()).into());
        }
        let stdout = BufReader::new(&result.stdout[..]);
        let mut lines = stdout.lines();
        let path = PathBuf::from(lines.next().unwrap()?);
        Ok(path)
    }

    match query_sysconfig() {
        Ok(path) => vec![path],
        Err(err) => {
            eprintln!("{}", err);
            vec![]
        }
    }
}

#[cfg(target_os = "macos")]
fn get_candidate_locations() -> Vec<PathBuf> {
    use std::io::{BufRead, BufReader};

    fn query_sysconfig() -> Result<Vec<PathBuf>, Error> {
        let result = std::process::Command::new("python3")
            .arg("-c")
            .arg("import sys,sysconfig; print(sys.base_exec_prefix); print(sysconfig.get_config_var('INSTSONAME'))")
            .output()?;
        if !result.status.success() {
            return Err(format!("python exit code: {:?}", result.status.code()).into());
        }
        let stdout = BufReader::new(&result.stdout[..]);
        let mut lines = stdout.lines();

        let prefix = lines.next().unwrap()?; // e.g. '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7'
        let libname = lines.next().unwrap()?; // e.g. 'Python3.framework/Versions/3.7/Python3'

        let mut results = vec![];

        let mut path = PathBuf::from(&prefix);
        path.push("Python3");
        results.push(path);

        let mut path = PathBuf::from(&prefix);
        path.push("Python");
        results.push(path);

        let mut path = PathBuf::from(&prefix);
        path.pop();
        path.pop();
        path.pop();
        path.push(&libname);
        results.push(path);

        results.push(PathBuf::from(&libname));

        Ok(results)
    }

    match query_sysconfig() {
        Ok(results) => results,
        Err(err) => {
            eprintln!("{}", err);
            vec![]
        }
    }
}

#[cfg(target_os = "windows")]
fn get_candidate_locations() -> Vec<PathBuf> {
    use winreg::enums::*;

    let mut results = vec![];

    if let Ok(python_home) = std::env::var("PYTHONHOME") {
        let mut path = PathBuf::from(python_home);
        path.push("python3.dll");
        results.push(path);
    }

    for hive in &[HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE] {
        if let Ok(hk_python) = winreg::RegKey::predef(*hive).open_subkey("Software\\Python\\PythonCore") {
            for ver_tag in hk_python.enum_keys() {
                if let Ok(ver_tag) = ver_tag {
                    if let Ok(hk_version) = hk_python.open_subkey(ver_tag) {
                        if let Ok(hk_install_path) = hk_version.open_subkey("InstallPath") {
                            if let Ok(install_path) = hk_install_path.get_value::<String, _>("") {
                                let mut path = PathBuf::from(install_path);
                                path.push("python3.dll");
                                results.push(path);
                            }
                        }
                    }
                }
            }
        }
    }
    results
}
<|endoftext|>


<commit_before>import ctypes::*;

#[abi = "cdecl"]
#[link_name = ""]
native mod libc {
    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    #[link_name = "_open"]
    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> c_int;
    #[link_name = "_close"]
    fn close(fd: fd_t) -> c_int;
    type FILE;
    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
    fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
    fn fclose(f: FILE);
    fn fflush(f: FILE) -> c_int;
    fn fsync(fd: fd_t) -> c_int;
    fn fileno(f: FILE) -> fd_t;
    fn fgetc(f: FILE) -> c_int;
    fn ungetc(c: c_int, f: FILE);
    fn feof(f: FILE) -> c_int;
    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
    fn ftell(f: FILE) -> long;
    fn _pipe(fds: *mutable fd_t, size: unsigned, mode: c_int) -> c_int;
}

mod libc_constants {
    const O_RDONLY: c_int    = 0i32;
    const O_WRONLY: c_int    = 1i32;
    const O_RDWR: c_int      = 2i32;
    const O_APPEND: c_int    = 8i32;
    const O_CREAT: c_int     = 256i32;
    const O_EXCL: c_int      = 1024i32;
    const O_TRUNC: c_int     = 512i32;
    const O_TEXT: c_int      = 16384i32;
    const O_BINARY: c_int    = 32768i32;
    const O_NOINHERIT: c_int = 128i32;
    const S_IRUSR: unsigned  = 256u32; // really _S_IREAD  in win32
    const S_IWUSR: unsigned  = 128u32; // really _S_IWRITE in win32
}

type DWORD = u32;
type HMODULE = uint;
type LPTSTR = str::sbuf;
type LPCTSTR = str::sbuf;

#[abi = "stdcall"]
native mod kernel32 {
    type LPSECURITY_ATTRIBUTES;
    fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: uint) ->
       uint;
    fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> int;
    fn GetModuleFileNameA(hModule: HMODULE,
                          lpFilename: LPTSTR,
                          nSize: DWORD) -> DWORD;
    fn CreateDirectoryA(lpPathName: LPCTSTR,
                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES) -> bool;
    fn RemoveDirectoryA(lpPathName: LPCTSTR) -> bool;
    fn SetCurrentDirectoryA(lpPathName: LPCTSTR) -> bool;
}

// FIXME turn into constants
fn exec_suffix() -> str { ret ".exe"; }
fn target_os() -> str { ret "win32"; }

fn dylib_filename(base: str) -> str { ret base + ".dll"; }

fn pipe() -> {in: fd_t, out: fd_t} {
    // Windows pipes work subtly differently than unix pipes, and their
    // inheritance has to be handled in a different way that I don't fully
    // understand. Here we explicitly make the pipe non-inheritable,
    // which means to pass it to a subprocess they need to be duplicated
    // first, as in rust_run_program.
    let fds = {mutable in: 0i32, mutable out: 0i32};
    let res =
        os::libc::_pipe(ptr::mut_addr_of(fds.in), 1024u32,
                        libc_constants::O_BINARY |
                            libc_constants::O_NOINHERIT);
    assert (res == 0i32);
    assert (fds.in != -1i32 && fds.in != 0i32);
    assert (fds.out != -1i32 && fds.in != 0i32);
    ret {in: fds.in, out: fds.out};
}

fn fd_FILE(fd: fd_t) -> libc::FILE {
    ret str::as_buf("r", {|modebuf| libc::_fdopen(fd, modebuf) });
}

fn close(fd: fd_t) -> c_int {
    libc::close(fd)
}

fn fclose(file: libc::FILE) {
    libc::fclose(file)
}

fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
    // FIXME do something more apropriate
    ret libc::fsync(fd);
}

#[abi = "cdecl"]
native mod rustrt {
    fn rust_process_wait(handle: c_int) -> c_int;
    fn rust_getcwd() -> str;
}

fn waitpid(pid: pid_t) -> i32 { ret rustrt::rust_process_wait(pid); }

fn getcwd() -> str { ret rustrt::rust_getcwd(); }

fn get_exe_path() -> option::t<fs::path> {
    // FIXME: This doesn't handle the case where the buffer is too small
    let bufsize = 1023u;
    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize));
    ret str::as_buf(path, { |path_buf|
        if kernel32::GetModuleFileNameA(0u, path_buf,
                                        bufsize as u32) != 0u32 {
            option::some(fs::dirname(path) + fs::path_sep())
        } else {
            option::none
        }
    });
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>stdlib: Win32 fsync is just fail<commit_after>import ctypes::*;

#[abi = "cdecl"]
#[link_name = ""]
native mod libc {
    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    #[link_name = "_open"]
    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> c_int;
    #[link_name = "_close"]
    fn close(fd: fd_t) -> c_int;
    type FILE;
    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
    fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
    fn fclose(f: FILE);
    fn fflush(f: FILE) -> c_int;
    fn fileno(f: FILE) -> fd_t;
    fn fgetc(f: FILE) -> c_int;
    fn ungetc(c: c_int, f: FILE);
    fn feof(f: FILE) -> c_int;
    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
    fn ftell(f: FILE) -> long;
    fn _pipe(fds: *mutable fd_t, size: unsigned, mode: c_int) -> c_int;
}

mod libc_constants {
    const O_RDONLY: c_int    = 0i32;
    const O_WRONLY: c_int    = 1i32;
    const O_RDWR: c_int      = 2i32;
    const O_APPEND: c_int    = 8i32;
    const O_CREAT: c_int     = 256i32;
    const O_EXCL: c_int      = 1024i32;
    const O_TRUNC: c_int     = 512i32;
    const O_TEXT: c_int      = 16384i32;
    const O_BINARY: c_int    = 32768i32;
    const O_NOINHERIT: c_int = 128i32;
    const S_IRUSR: unsigned  = 256u32; // really _S_IREAD  in win32
    const S_IWUSR: unsigned  = 128u32; // really _S_IWRITE in win32
}

type DWORD = u32;
type HMODULE = uint;
type LPTSTR = str::sbuf;
type LPCTSTR = str::sbuf;

#[abi = "stdcall"]
native mod kernel32 {
    type LPSECURITY_ATTRIBUTES;
    fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: uint) ->
       uint;
    fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> int;
    fn GetModuleFileNameA(hModule: HMODULE,
                          lpFilename: LPTSTR,
                          nSize: DWORD) -> DWORD;
    fn CreateDirectoryA(lpPathName: LPCTSTR,
                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES) -> bool;
    fn RemoveDirectoryA(lpPathName: LPCTSTR) -> bool;
    fn SetCurrentDirectoryA(lpPathName: LPCTSTR) -> bool;
}

// FIXME turn into constants
fn exec_suffix() -> str { ret ".exe"; }
fn target_os() -> str { ret "win32"; }

fn dylib_filename(base: str) -> str { ret base + ".dll"; }

fn pipe() -> {in: fd_t, out: fd_t} {
    // Windows pipes work subtly differently than unix pipes, and their
    // inheritance has to be handled in a different way that I don't fully
    // understand. Here we explicitly make the pipe non-inheritable,
    // which means to pass it to a subprocess they need to be duplicated
    // first, as in rust_run_program.
    let fds = {mutable in: 0i32, mutable out: 0i32};
    let res =
        os::libc::_pipe(ptr::mut_addr_of(fds.in), 1024u32,
                        libc_constants::O_BINARY |
                            libc_constants::O_NOINHERIT);
    assert (res == 0i32);
    assert (fds.in != -1i32 && fds.in != 0i32);
    assert (fds.out != -1i32 && fds.in != 0i32);
    ret {in: fds.in, out: fds.out};
}

fn fd_FILE(fd: fd_t) -> libc::FILE {
    ret str::as_buf("r", {|modebuf| libc::_fdopen(fd, modebuf) });
}

fn close(fd: fd_t) -> c_int {
    libc::close(fd)
}

fn fclose(file: libc::FILE) {
    libc::fclose(file)
}

fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
    // FIXME
}

#[abi = "cdecl"]
native mod rustrt {
    fn rust_process_wait(handle: c_int) -> c_int;
    fn rust_getcwd() -> str;
}

fn waitpid(pid: pid_t) -> i32 { ret rustrt::rust_process_wait(pid); }

fn getcwd() -> str { ret rustrt::rust_getcwd(); }

fn get_exe_path() -> option::t<fs::path> {
    // FIXME: This doesn't handle the case where the buffer is too small
    let bufsize = 1023u;
    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize));
    ret str::as_buf(path, { |path_buf|
        if kernel32::GetModuleFileNameA(0u, path_buf,
                                        bufsize as u32) != 0u32 {
            option::some(fs::dirname(path) + fs::path_sep())
        } else {
            option::none
        }
    });
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
//! only be one owner of a `Box`, and the owner can decide to mutate the
//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer
//! type intended for sharing memory within a thread. An `Rc` pointer wraps a
//! type, `T`, and only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using `Box`) is too
//! constraining for an application, and is often paired with the `Cell` or
//! `RefCell` types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`](sync/index.html) type is the threadsafe equivalent of the `Rc`
//! type. It provides all the same functionality of `Rc`, except it requires
//! that the contained type `T` is shareable. Additionally, `Arc<T>` is itself
//! sendable while `Rc<T>` is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.

#![allow(unused_attributes)]
#![unstable(feature = "alloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
#![no_std]
#![needs_allocator]

#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]

#![warn(deprecated_in_future)]
#![warn(intra_doc_link_resolution_failure)]
#![warn(missing_debug_implementations)]

#![cfg_attr(not(test), feature(fn_traits))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]

#![feature(allocator_api)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fmt_internals)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
#![feature(nll)]
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(specialization)]
#![feature(split_ascii_whitespace)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]

// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;
#[cfg(test)]
extern crate rand;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

#[unstable(feature = "futures_api",
           reason = "futures in libcore are unstable",
           issue = "50547")]
pub mod task;
// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
#[cfg(test)]
mod boxed_test;
pub mod collections;
#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
pub mod sync;
pub mod rc;
pub mod raw_vec;
pub mod prelude;
pub mod borrow;
pub mod fmt;
pub mod slice;
pub mod str;
pub mod string;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}
<commit_msg>liballoc: remove redundant extern crate.<commit_after>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
//! only be one owner of a `Box`, and the owner can decide to mutate the
//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer
//! type intended for sharing memory within a thread. An `Rc` pointer wraps a
//! type, `T`, and only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using `Box`) is too
//! constraining for an application, and is often paired with the `Cell` or
//! `RefCell` types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`](sync/index.html) type is the threadsafe equivalent of the `Rc`
//! type. It provides all the same functionality of `Rc`, except it requires
//! that the contained type `T` is shareable. Additionally, `Arc<T>` is itself
//! sendable while `Rc<T>` is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.

#![allow(unused_attributes)]
#![unstable(feature = "alloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
#![no_std]
#![needs_allocator]

#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]

#![warn(deprecated_in_future)]
#![warn(intra_doc_link_resolution_failure)]
#![warn(missing_debug_implementations)]

#![cfg_attr(not(test), feature(fn_traits))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]

#![feature(allocator_api)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fmt_internals)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
#![feature(nll)]
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(specialization)]
#![feature(split_ascii_whitespace)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]

// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

#[unstable(feature = "futures_api",
           reason = "futures in libcore are unstable",
           issue = "50547")]
pub mod task;
// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
#[cfg(test)]
mod boxed_test;
pub mod collections;
#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
pub mod sync;
pub mod rc;
pub mod raw_vec;
pub mod prelude;
pub mod borrow;
pub mod fmt;
pub mod slice;
pub mod str;
pub mod string;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(warnings)]

extern crate gcc;
extern crate build_helper;

use std::env;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");
    println!("cargo:rerun-if-changed=build.rs");

    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
        !target.contains("emscripten") && !target.contains("fuchsia") && !target.contains("redox") {
        build_libbacktrace(&host, &target);
    }

    if target.contains("linux") {
        if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else if !target.contains("musl") || target.contains("mips") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=magenta");
        println!("cargo:rustc-link-lib=mxio");
        println!("cargo:rustc-link-lib=launchpad"); // for std::process
    } else if target.contains("redox") {
        println!("cargo:rustc-link-lib=openlibm");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    let mut stack = src_dir.read_dir().unwrap()
                           .map(|e| e.unwrap())
                           .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    let compiler = gcc::Config::new().get_compiler();
    // only msvc returns None for ar so unwrap is okay
    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
}
<commit_msg>Static link openlibm<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(warnings)]

extern crate gcc;
extern crate build_helper;

use std::env;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");
    println!("cargo:rerun-if-changed=build.rs");

    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
        !target.contains("emscripten") && !target.contains("fuchsia") && !target.contains("redox") {
        build_libbacktrace(&host, &target);
    }

    if target.contains("linux") {
        if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else if !target.contains("musl") || target.contains("mips") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=magenta");
        println!("cargo:rustc-link-lib=mxio");
        println!("cargo:rustc-link-lib=launchpad"); // for std::process
    } else if target.contains("redox") {
        println!("cargo:rustc-link-lib=static=openlibm");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    let mut stack = src_dir.read_dir().unwrap()
                           .map(|e| e.unwrap())
                           .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }

    let compiler = gcc::Config::new().get_compiler();
    // only msvc returns None for ar so unwrap is okay
    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
}
<|endoftext|>


<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use std::io::Read;
use std::io::Error;
use std::slice;

pub fn get_u8_vec<R: Read>(mut reader: R) -> Result<Vec<u8>,Error> {
    let mut string_vec: Vec<u8> = Vec::new();

    loop {
        let u8_char = reader.read_u8()?;
        if u8_char == 0x00 {
            break
        } else {
            string_vec.push(u8_char);
        }
    }

    Ok(string_vec)
}

pub fn get_u8_vec_utf16<R: Read>(mut reader: R) -> Result<Vec<u8>,Error>{
    let mut u16_vec: Vec<u16> = Vec::new();

    loop {
        let u16_char = reader.read_u16::<LittleEndian>()?;
        if u16_char == 0x0000 {
            break
        } else {
            u16_vec.push(u16_char);
        }
    }

    let u8_slice: &[u8] = unsafe {
        slice::from_raw_parts(u16_vec.as_ptr() as *const u8, u16_vec.len() * 2)
    };

    Ok(u8_slice.to_vec())
}

pub fn get_u16_vec<R: Read>(mut reader: R) -> Result<Vec<u16>,Error> {
    let mut string_vec: Vec<u16> = Vec::new();

    loop {
        let u16_char = reader.read_u16::<LittleEndian>()?;
        if u16_char == 0x0000 {
            break
        } else {
            string_vec.push(u16_char);
        }
    }

    Ok(string_vec)
}
<commit_msg>Added string read helper methods<commit_after>use byteorder::{ReadBytesExt, LittleEndian};
use encoding::all::UTF_16LE;
use encoding::{Encoding, DecoderTrap};
use lnkpkg::errors::{LnkError};
use std::io::Read;
use std::io::Error;
use std::slice;

pub fn read_string_utf8<R: Read>(mut reader: R) -> Result<String,LnkError> {
    // Reads into a string till a null char is reached
    let utf8_buffer = get_u8_vec(&mut reader)?;
    Ok(
        String::from_utf8(utf8_buffer)?
    )
}

pub fn read_string_utf16<R: Read>(mut reader: R) -> Result<String,LnkError> {
    // Reads into a string till a null char is reached
    let utf16_buffer = get_u8_vec_utf16(&mut reader)?;
    let utf16_string = match UTF_16LE.decode(&utf16_buffer.as_slice(),DecoderTrap::Ignore) {
        Ok(utf16) => utf16,
        Err(error) => return Err(
            LnkError::utf16_decode_error(
                format!("Error decoding name in volume_label_unicode field. [{}]",error)
            )
        )
    };
    Ok(utf16_string)
}

pub fn get_u8_vec<R: Read>(mut reader: R) -> Result<Vec<u8>,Error> {
    let mut string_vec: Vec<u8> = Vec::new();

    loop {
        let u8_char = reader.read_u8()?;
        if u8_char == 0x00 {
            break
        } else {
            string_vec.push(u8_char);
        }
    }

    Ok(string_vec)
}

pub fn get_u8_vec_utf16<R: Read>(mut reader: R) -> Result<Vec<u8>,Error>{
    let mut u16_vec: Vec<u16> = Vec::new();

    loop {
        let u16_char = reader.read_u16::<LittleEndian>()?;
        if u16_char == 0x0000 {
            break
        } else {
            u16_vec.push(u16_char);
        }
    }

    let u8_slice: &[u8] = unsafe {
        slice::from_raw_parts(u16_vec.as_ptr() as *const u8, u16_vec.len() * 2)
    };

    Ok(u8_slice.to_vec())
}

pub fn get_u16_vec<R: Read>(mut reader: R) -> Result<Vec<u16>,Error> {
    let mut string_vec: Vec<u16> = Vec::new();

    loop {
        let u16_char = reader.read_u16::<LittleEndian>()?;
        if u16_char == 0x0000 {
            break
        } else {
            string_vec.push(u16_char);
        }
    }

    Ok(string_vec)
}
<|endoftext|>


<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	cmd.env("CARGO_TERM_COLOR", "always");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not sucessful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>Remove comment for resolved issue<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	cmd.env("CARGO_TERM_COLOR", "always");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	// HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not sucessful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate concrust;
extern crate test;
#[macro_use]
extern crate expectest;

pub use concrust::queue::ArrayBlockingQueue;
pub use concrust::queue::BlockingQueue;

pub use expectest::prelude::{be_equal_to, be_ok};

pub use std::thread;
pub use std::thread::JoinHandle;
pub use std::sync::{Arc, Barrier};
pub use std::result::Result;

const NUMBER_OF_ELEMENTS: i64 = 1000;
const NUMBER_OF_PROCCESS: i64 = 5;

#[bench]
fn multiple_consumers_multiple_producer_default_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = multiple_consumers_multiple_producer_iter(
                ArrayBlockingQueue::new(),
                Arc::new(Barrier::new(11)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn multiple_consumers_multiple_producer_small_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = multiple_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 20) as usize),
                Arc::new(Barrier::new(11)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn multiple_consumers_multiple_producer_large_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = multiple_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 2) as usize),
                Arc::new(Barrier::new(11)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

fn multiple_consumers_multiple_producer_iter(queue: ArrayBlockingQueue<i64>, barrier: Arc<Barrier>, oper: i64) -> i64 {
    let mut consumers = Vec::with_capacity(NUMBER_OF_PROCCESS as usize);
    for _ in 0..NUMBER_OF_PROCCESS {
        consumers.push(spawn_consumer(&queue, &barrier, oper));
        spawn_producer(&queue, &barrier, oper);
    }
    barrier.wait();
    consumers.into_iter().map(|c| c.join().unwrap()).fold(0, |acc, v| { acc + v } )
}

fn multiple_consumers_producer_setup() -> (i64, i64) {
    let operation_number = NUMBER_OF_ELEMENTS / NUMBER_OF_PROCCESS;
    (operation_number, sum(operation_number) * NUMBER_OF_PROCCESS)
}

#[bench]
fn single_consumers_multiple_producer_default_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumers_multiple_producer_iter(
                ArrayBlockingQueue::new(),
                Arc::new(Barrier::new(7)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result))
        }
    );
}

#[bench]
fn single_consumers_multiple_producer_small_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_PROCCESS / 20) as usize),
                Arc::new(Barrier::new(7)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result))
        }
    );
}

#[bench]
fn single_consumers_multiple_producer_large_queue_size(bencher: &mut test::Bencher) {
    let (oper, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_PROCCESS / 2) as usize),
                Arc::new(Barrier::new(7)),
                oper
            );
            expect!(actual_result).to(be_equal_to(expected_result))
        }
    );
}

fn single_consumers_multiple_producer_iter(queue: ArrayBlockingQueue<i64>, barrier: Arc<Barrier>, oper: i64) -> i64{
    let c_handle = spawn_consumer(&queue, &barrier, NUMBER_OF_PROCCESS);
    for _ in 0..NUMBER_OF_PROCCESS {
        spawn_producer(&queue, &barrier, oper);
    }
    barrier.wait();
    c_handle.join().unwrap()
}

#[bench]
fn single_consumer_single_producer_default_queue_size(bencher: &mut test::Bencher) {
    let expected_result = single_consumer_single_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumer_single_producer_iter(
                ArrayBlockingQueue::new(),
                Arc::new(Barrier::new(3))
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn single_consumer_single_producer_small_queue_size(bencher: &mut test::Bencher) {
    let expected_result = single_consumer_single_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumer_single_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 20) as usize),
                Arc::new(Barrier::new(3))
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn single_consumer_single_producer_large_queue_size(bencher: &mut test::Bencher) {
    let expected_result = single_consumer_single_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumer_single_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 2) as usize),
                Arc::new(Barrier::new(3))
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

fn single_consumer_single_producer_iter(queue: ArrayBlockingQueue<i64>, barrier: Arc<Barrier>) -> i64 {
    let handle = spawn_consumer(&queue, &barrier, NUMBER_OF_ELEMENTS);
    spawn_producer(&queue, &barrier, NUMBER_OF_ELEMENTS);
    barrier.wait();
    handle.join().unwrap()
}

fn single_consumer_single_producer_setup() -> i64 {
    sum(NUMBER_OF_ELEMENTS)
}

pub fn sum(last: i64) -> i64 {
    (last - 1) * last / 2
}

pub fn spawn_consumer<'q, 'b>(queue: &'q ArrayBlockingQueue<i64>, barrier: &'b Arc<Barrier>, oper: i64) -> JoinHandle<i64> {
    let consume = queue.clone();
    let barrier_cons = barrier.clone();
    thread::spawn(
        move || {
            barrier_cons.wait();
            let mut sum = 0;
            for _ in 0..oper {
                sum += consume.dequeue();
            }
            sum
        }
    )
}

pub fn spawn_producer<'q, 'b>(queue: &'q ArrayBlockingQueue<i64>, barrier: &'b Arc<Barrier>, oper: i64) {
    let produce = queue.clone();
    let barrier_prod = barrier.clone();
    thread::spawn(
        move || {
            barrier_prod.wait();
            for i in 0..oper {
                produce.enqueue(i);
            }
        }
    );
}
<commit_msg>fix benchmarks result<commit_after>#![feature(test)]

extern crate concrust;
extern crate test;
#[macro_use]
extern crate expectest;

pub use concrust::queue::ArrayBlockingQueue;
pub use concrust::queue::BlockingQueue;

pub use expectest::prelude::{be_equal_to, be_ok};

pub use std::thread;
pub use std::thread::JoinHandle;
pub use std::sync::{Arc, Barrier};
pub use std::result::Result;

const NUMBER_OF_ELEMENTS: i64 = 1000;
const NUMBER_OF_PROCCESS: i64 = 5;

#[bench]
fn multiple_consumers_multiple_producer_default_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = multiple_consumers_multiple_producer_iter(
                ArrayBlockingQueue::new(),
                Arc::new(Barrier::new(11)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn multiple_consumers_multiple_producer_small_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = multiple_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 20) as usize),
                Arc::new(Barrier::new(11)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn multiple_consumers_multiple_producer_large_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = multiple_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 2) as usize),
                Arc::new(Barrier::new(11)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

fn multiple_consumers_multiple_producer_iter(queue: ArrayBlockingQueue<i64>, barrier: Arc<Barrier>, oper: i64) -> i64 {
    let mut consumers = Vec::with_capacity(NUMBER_OF_PROCCESS as usize);
    for _ in 0..NUMBER_OF_PROCCESS {
        consumers.push(spawn_consumer(&queue, &barrier, oper));
        spawn_producer(&queue, &barrier, oper);
    }
    barrier.wait();
    consumers.into_iter().map(|c| c.join().unwrap()).fold(0, |acc, v| { acc + v } )
}

fn multiple_consumers_producer_setup() -> (i64, i64) {
    let operation_number = NUMBER_OF_ELEMENTS / NUMBER_OF_PROCCESS;
    (operation_number, sum(operation_number) * NUMBER_OF_PROCCESS)
}

#[bench]
fn single_consumers_multiple_producer_default_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumers_multiple_producer_iter(
                ArrayBlockingQueue::new(),
                Arc::new(Barrier::new(7)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result))
        }
    );
}

#[bench]
fn single_consumers_multiple_producer_small_queue_size(bencher: &mut test::Bencher) {
    let (operation_number, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_PROCCESS / 20) as usize),
                Arc::new(Barrier::new(7)),
                operation_number
            );
            expect!(actual_result).to(be_equal_to(expected_result))
        }
    );
}

#[bench]
fn single_consumers_multiple_producer_large_queue_size(bencher: &mut test::Bencher) {
    let (oper, expected_result) = multiple_consumers_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumers_multiple_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_PROCCESS / 2) as usize),
                Arc::new(Barrier::new(7)),
                oper
            );
            expect!(actual_result).to(be_equal_to(expected_result))
        }
    );
}

fn single_consumers_multiple_producer_iter(queue: ArrayBlockingQueue<i64>, barrier: Arc<Barrier>, oper: i64) -> i64{
    let c_handle = spawn_consumer(&queue, &barrier, NUMBER_OF_ELEMENTS);
    for _ in 0..NUMBER_OF_PROCCESS {
        spawn_producer(&queue, &barrier, oper);
    }
    barrier.wait();
    c_handle.join().unwrap()
}

#[bench]
fn single_consumer_single_producer_default_queue_size(bencher: &mut test::Bencher) {
    let expected_result = single_consumer_single_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumer_single_producer_iter(
                ArrayBlockingQueue::new(),
                Arc::new(Barrier::new(3))
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn single_consumer_single_producer_small_queue_size(bencher: &mut test::Bencher) {
    let expected_result = single_consumer_single_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumer_single_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 20) as usize),
                Arc::new(Barrier::new(3))
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

#[bench]
fn single_consumer_single_producer_large_queue_size(bencher: &mut test::Bencher) {
    let expected_result = single_consumer_single_producer_setup();
    bencher.iter(
        || {
            let actual_result = single_consumer_single_producer_iter(
                ArrayBlockingQueue::with_capacity((NUMBER_OF_ELEMENTS / 2) as usize),
                Arc::new(Barrier::new(3))
            );
            expect!(actual_result).to(be_equal_to(expected_result));
        }
    );
}

fn single_consumer_single_producer_iter(queue: ArrayBlockingQueue<i64>, barrier: Arc<Barrier>) -> i64 {
    let handle = spawn_consumer(&queue, &barrier, NUMBER_OF_ELEMENTS);
    spawn_producer(&queue, &barrier, NUMBER_OF_ELEMENTS);
    barrier.wait();
    handle.join().unwrap()
}

fn single_consumer_single_producer_setup() -> i64 {
    sum(NUMBER_OF_ELEMENTS)
}

pub fn sum(last: i64) -> i64 {
    (last - 1) * last / 2
}

pub fn spawn_consumer<'q, 'b>(queue: &'q ArrayBlockingQueue<i64>, barrier: &'b Arc<Barrier>, oper: i64) -> JoinHandle<i64> {
    let consume = queue.clone();
    let barrier_cons = barrier.clone();
    thread::spawn(
        move || {
            barrier_cons.wait();
            let mut sum = 0;
            for _ in 0..oper {
                sum += consume.dequeue();
            }
            sum
        }
    )
}

pub fn spawn_producer<'q, 'b>(queue: &'q ArrayBlockingQueue<i64>, barrier: &'b Arc<Barrier>, oper: i64) {
    let produce = queue.clone();
    let barrier_prod = barrier.clone();
    thread::spawn(
        move || {
            barrier_prod.wait();
            for i in 0..oper {
                produce.enqueue(i);
            }
        }
    );
}
<|endoftext|>