<commit_before>use hdr_histogram::simple_hdr_histogram::*;

#[test]
fn count_at_value_on_empty() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(0, h.get_count_at_value(1).unwrap());
    assert_eq!(0, h.get_count_at_value(5000).unwrap());
    assert_eq!(0, h.get_count_at_value(100000).unwrap());
}

#[test]
fn count_at_value_after_record() {
    let mut h = init_histo(1, 100000, 3);

    h.record_single_value(5000).unwrap();

    assert_eq!(0, h.get_count_at_value(1).unwrap());
    assert_eq!(1, h.get_count_at_value(5000).unwrap());
    assert_eq!(0, h.get_count_at_value(100000).unwrap());
}

#[test]
fn can_get_count_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let count = h.get_count();
    assert_eq!(1, count);
}

#[test]
fn can_get_max_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let max = h.get_max();
    assert_eq!(5000, max);
}

#[test]
fn can_record_single_value() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();
}

#[test]
fn can_compute_indexes_for_smallest_value() {
    let h = init_histo(1, 100000, 3);
    let value = 1;
    assert_eq!(0, h.get_bucket_index(value));
    assert_eq!(1, h.get_sub_bucket_index(value, 0));
    assert_eq!(1, h.counts_array_index(value));
}

#[test]
fn can_compute_counts_array_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.counts_array_index(5000);

    assert_eq!(3298, result);
}

#[test]
fn can_get_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_bucket_index(5000);
    assert_eq!(2, result)
}

#[test]
fn can_get_sub_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_sub_bucket_index(5000, 2);
    assert_eq!(1250, result)
}

#[test]
fn sub_bucket_count_medium_precision() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(2048_usize, h.sub_bucket_count);
    assert_eq!(1024_usize, h.sub_bucket_half_count);
    assert_eq!(10, h.sub_bucket_half_count_magnitude);
    assert_eq!(2047, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_min_precision() {
    let h = init_histo(1, 100000, 0);

    assert_eq!(2_usize, h.sub_bucket_count);
    assert_eq!(1_usize, h.sub_bucket_half_count);
    assert_eq!(0, h.sub_bucket_half_count_magnitude);
    assert_eq!(1, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_max_precision() {
    let h = init_histo(1, 100000, 5);

    assert_eq!(262144_usize, h.sub_bucket_count);
    assert_eq!(131072usize, h.sub_bucket_half_count);
    assert_eq!(17, h.sub_bucket_half_count_magnitude);
    assert_eq!(262143, h.sub_bucket_mask);
}

#[test]
fn unit_magnitude_mask_1() {
    let h = init_histo(1, 100000, 5);

    assert_eq!(0, h.unit_magnitude);
    assert_eq!(0, h.unit_magnitude_mask);
}

#[test]
fn unit_magnitude_mask_2() {
    let h = init_histo(2, 100000, 5);

    assert_eq!(1, h.unit_magnitude);
    assert_eq!(1, h.unit_magnitude_mask);
}

#[test]
fn unit_magnitude_mask_3() {
    let h = init_histo(3, 100000, 5);

    assert_eq!(1, h.unit_magnitude);
    assert_eq!(1, h.unit_magnitude_mask);
}

#[test]
fn unit_magnitude_mask_1000() {
    let h = init_histo(1000, 100000, 5);

    assert_eq!(9, h.unit_magnitude);
    assert_eq!(511, h.unit_magnitude_mask);
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram<u64> {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = (1_u64 << unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
    ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = ((sub_bucket_count - 1) << unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    SimpleHdrHistogram {
        leading_zeros_count_base: leading_zero_count_base,
        unit_magnitude: unit_magnitude,
        sub_bucket_mask: sub_bucket_mask,
        sub_bucket_count: sub_bucket_count,
        sub_bucket_half_count: sub_bucket_half_count,
        sub_bucket_half_count_magnitude: sub_bucket_half_count_magnitude,
        counts: vec![0; counts_arr_len],
        counts_array_length: counts_arr_len,
        normalizing_index_offset: 0_usize, // 0 for normal Histogram ctor in Java impl
        min_non_zero_value: u64::max_value(),
        total_count: 0,
        max_value: 0,
        unit_magnitude_mask: unit_magnitude_mask
    }
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // TODO is this cast ok?
    let mut smallest_untrackable_value: u64 = (sub_bucket_count << unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value << 1;
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<commit_msg>Add tests for bucket count, and simplify count array length calculation a little<commit_after>use hdr_histogram::simple_hdr_histogram::*;

#[test]
fn count_at_value_on_empty() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(0, h.get_count_at_value(1).unwrap());
    assert_eq!(0, h.get_count_at_value(5000).unwrap());
    assert_eq!(0, h.get_count_at_value(100000).unwrap());
}

#[test]
fn count_at_value_after_record() {
    let mut h = init_histo(1, 100000, 3);

    h.record_single_value(5000).unwrap();

    assert_eq!(0, h.get_count_at_value(1).unwrap());
    assert_eq!(1, h.get_count_at_value(5000).unwrap());
    assert_eq!(0, h.get_count_at_value(100000).unwrap());
}

#[test]
fn can_get_count_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let count = h.get_count();
    assert_eq!(1, count);
}

#[test]
fn can_get_max_after_record() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();

    let max = h.get_max();
    assert_eq!(5000, max);
}

#[test]
fn can_record_single_value() {
    let mut h = init_histo(1, 100000, 3);
    h.record_single_value(5000).unwrap();
}

#[test]
fn can_compute_indexes_for_smallest_value() {
    let h = init_histo(1, 100000, 3);
    let value = 1;
    assert_eq!(0, h.get_bucket_index(value));
    assert_eq!(1, h.get_sub_bucket_index(value, 0));
    assert_eq!(1, h.counts_array_index(value));
}

#[test]
fn can_compute_counts_array_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.counts_array_index(5000);

    assert_eq!(3298, result);
}

#[test]
fn can_get_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_bucket_index(5000);
    assert_eq!(2, result)
}

#[test]
fn can_get_sub_bucket_index() {
    let h = init_histo(1, 100000, 3);
    let result = h.get_sub_bucket_index(5000, 2);
    assert_eq!(1250, result)
}

#[test]
fn sub_bucket_count_medium_precision() {
    let h = init_histo(1, 100000, 3);

    assert_eq!(2048_usize, h.sub_bucket_count);
    assert_eq!(1024_usize, h.sub_bucket_half_count);
    assert_eq!(10, h.sub_bucket_half_count_magnitude);
    assert_eq!(2047, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_min_precision() {
    let h = init_histo(1, 100000, 0);

    assert_eq!(2_usize, h.sub_bucket_count);
    assert_eq!(1_usize, h.sub_bucket_half_count);
    assert_eq!(0, h.sub_bucket_half_count_magnitude);
    assert_eq!(1, h.sub_bucket_mask);
}

#[test]
fn sub_bucket_count_max_precision() {
    let h = init_histo(1, 100000, 5);

    assert_eq!(262144_usize, h.sub_bucket_count);
    assert_eq!(131072usize, h.sub_bucket_half_count);
    assert_eq!(17, h.sub_bucket_half_count_magnitude);
    assert_eq!(262143, h.sub_bucket_mask);
}

#[test]
fn unit_magnitude_mask_1() {
    let h = init_histo(1, 100000, 5);

    assert_eq!(0, h.unit_magnitude);
    assert_eq!(0, h.unit_magnitude_mask);
}

#[test]
fn unit_magnitude_mask_2() {
    let h = init_histo(2, 100000, 5);

    assert_eq!(1, h.unit_magnitude);
    assert_eq!(1, h.unit_magnitude_mask);
}

#[test]
fn unit_magnitude_mask_3() {
    let h = init_histo(3, 100000, 5);

    assert_eq!(1, h.unit_magnitude);
    assert_eq!(1, h.unit_magnitude_mask);
}

#[test]
fn unit_magnitude_mask_1000() {
    let h = init_histo(1000, 100000, 5);

    assert_eq!(9, h.unit_magnitude);
    assert_eq!(511, h.unit_magnitude_mask);
}

#[test]
fn buckets_needed_for_value_small() {
    assert_eq!(1, buckets_needed_for_value(1900, 2048_usize, 0));
}

#[test]
fn buckets_needed_for_value_med() {
    // 2048 * 2^6 > 100000, so 7 buckets total
    assert_eq!(7, buckets_needed_for_value(100000, 2048_usize, 0));
}

#[test]
fn buckets_needed_for_value_big() {
    // should hit the case where it detects impending overflow
    // 2^51 * 2048 == 2^62, so that's 52 buckets, + 1 more to reach the +1 in the value
    assert_eq!(53, buckets_needed_for_value((1_u64 << 62) + 1, 2048_usize, 0));
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram<u64> {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = (1_u64 << unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
    ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = ((sub_bucket_count - 1) << unit_magnitude) as u64;

    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let counts_arr_len = counts_arr_len(bucket_count, sub_bucket_count);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    SimpleHdrHistogram {
        leading_zeros_count_base: leading_zero_count_base,
        unit_magnitude: unit_magnitude,
        sub_bucket_mask: sub_bucket_mask,
        sub_bucket_count: sub_bucket_count,
        sub_bucket_half_count: sub_bucket_half_count,
        sub_bucket_half_count_magnitude: sub_bucket_half_count_magnitude,
        counts: vec![0; counts_arr_len],
        counts_array_length: counts_arr_len,
        normalizing_index_offset: 0_usize, // 0 for normal Histogram ctor in Java impl
        min_non_zero_value: u64::max_value(),
        total_count: 0,
        max_value: 0,
        unit_magnitude_mask: unit_magnitude_mask
    }
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // sub_bucket_count is 2 * 10^precision, so fairly small and certainly fits in u64.
    // If unit magnitude is too big, this will panic, but not much we can do about it.
    // Pretty unlikely to have a large unit_magnitude (you'd need at least 46 to cause the max
    // sized sub_bucket_count of 2^18 to overflow...)
    let mut smallest_untrackable_value: u64 = (sub_bucket_count as u64) << unit_magnitude;
    let mut buckets_needed = 1_usize;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value << 1;
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len(bucket_count: usize, sub_bucket_count: usize) -> usize {
    (bucket_count + 1) * (sub_bucket_count / 2)
}<|endoftext|>


<commit_before>//! Just a dumping ground for cli stuff

use rustup::{self, Cfg, Notification, Toolchain, UpdateStatus};
use rustup::telemetry_analysis::TelemetryAnalysis;
use errors::*;
use rustup_utils::utils;
use rustup_utils::notify::NotificationLevel;
use self_update;
use std::io::{Write, BufRead, BufReader};
use std::process::{Command, Stdio};
use std::path::Path;
use std::{cmp, iter};
use std::sync::Arc;
use std::time::Duration;
use std;
use term2;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub enum Confirm {
    Yes, No, Advanced
}

pub fn confirm_advanced() -> Result<Confirm> {
    println!("");
    println!("1) Proceed with installation (default)");
    println!("2) Customize installation");
    println!("3) Cancel installation");

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "1"|"" => Confirm::Yes,
        "2" => Confirm::Advanced,
        _ => Confirm::No,
    };

    println!("");

    Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
    println!("{}", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default.to_string())
    } else {
        Ok(input)
    }
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
    println!("{}", question);

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default)
    } else {
        match &*input {
            "y" | "Y" | "yes" => Ok(true),
            "n" | "N" | "no" => Ok(false),
            _ => Ok(default)
        }
    }

}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(
        "unable to read from stdin for confirmation".into())
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Ok(try!(Cfg::from_env(Arc::new(move |n: Notification| {
       if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))))

}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: rustup::Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, rustup::Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

pub fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            cmd.stdin(Stdio::null());
            cmd.stdout(Stdio::piped());
            cmd.stderr(Stdio::piped());
            toolchain.set_ldpath(&mut cmd);

            // some toolchains are faulty with some combinations of platforms and
            // may fail to launch but also to timely terminate.
            // (known cases include Rust 1.3.0 through 1.10.0 in recent macOS Sierra.)
            // we guard against such cases by enforcing a reasonable timeout to read.
            let mut line1 = None;
            if let Ok(mut child) = cmd.spawn() {
                let timeout = Duration::new(1, 0);
                match child.wait_timeout(timeout) {
                    Ok(Some(status)) if status.success() => {
                        let out = child.stdout.expect("Child::stdout requested but not present");
                        let mut line = String::new();
                        if BufReader::new(out).read_line(&mut line).is_ok() {
                            let lineend = line.trim_right_matches(&['\r', '\n'][..]).len();
                            line.truncate(lineend);
                            line1 = Some(line);
                        }
                    }
                    Ok(None) => {
                        let _ = child.kill();
                    }
                    Ok(Some(_)) | Err(_) => {}
                }
            }

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            let target = component.component.target.as_ref().expect("rust-std should have a target");
            if component.required {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (default)", target);
                let _ = t.reset();
            } else if component.installed {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (installed)", target);
                let _ = t.reset();
            } else if component.available {
                let _ = writeln!(t, "{}", target);
            }
        }
    }

    Ok(())
}

pub fn list_components(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        let name = component.component.name();
        if component.required {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (default)", name);
            let _ = t.reset();
        } else if component.installed {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (installed)", name);
            let _ = t.reset();
        } else if component.available {
            let _ = writeln!(t, "{}", name);
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let toolchains = try!(cfg.list_toolchains());

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let overrides = try!(cfg.settings_file.with(|s| Ok(s.overrides.clone())));

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        let mut any_not_exist = false;
        for (k, v) in overrides {
            let dir_exists = Path::new(&k).is_dir();
            if !dir_exists {
                any_not_exist = true;
            }
            println!("{:<40}\t{:<20}",
                     utils::format_path_for_display(&k) +
                     if dir_exists {
                         ""
                     } else {
                         " (not a directory)"
                     },
                     v)
        }
        if any_not_exist {
            println!("");
            info!("you may remove overrides for non-existent directories with
`rustup override unset --nonexistent`");
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    concat!(env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")))
}

pub fn report_error(e: &Error) {
    err!("{}", e);

    for e in e.iter().skip(1) {
        info!("caused by: {}", e);
    }

    if show_backtrace() {
        if let Some(backtrace) = e.backtrace() {
            info!("backtrace:");
            println!("");
            println!("{:?}", backtrace);
        }
    } else {
    }

    fn show_backtrace() -> bool {
        use std::env;
        use std::ops::Deref;

        if env::var("RUST_BACKTRACE").as_ref().map(Deref::deref) == Ok("1") {
            return true;
        }

        for arg in env::args() {
            if arg == "-v" || arg == "--verbose" {
                return true;
            }
        }

        false
    }
}

pub fn show_telemetry(analysis: TelemetryAnalysis) -> Result<()> {
    println!("Telemetry Analysis");

    println!("{}", analysis);

    Ok(())
}
<commit_msg>Auto merge of #1130 - mati865:master, r=Diggsey<commit_after>//! Just a dumping ground for cli stuff

use rustup::{self, Cfg, Notification, Toolchain, UpdateStatus};
use rustup::telemetry_analysis::TelemetryAnalysis;
use errors::*;
use rustup_utils::utils;
use rustup_utils::notify::NotificationLevel;
use self_update;
use std::io::{Write, BufRead, BufReader};
use std::process::{Command, Stdio};
use std::path::Path;
use std::{cmp, iter};
use std::sync::Arc;
use std::time::Duration;
use std;
use term2;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub enum Confirm {
    Yes, No, Advanced
}

pub fn confirm_advanced() -> Result<Confirm> {
    println!("");
    println!("1) Proceed with installation (default)");
    println!("2) Customize installation");
    println!("3) Cancel installation");

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "1"|"" => Confirm::Yes,
        "2" => Confirm::Advanced,
        _ => Confirm::No,
    };

    println!("");

    Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
    println!("{}", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default.to_string())
    } else {
        Ok(input)
    }
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
    println!("{}", question);

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default)
    } else {
        match &*input {
            "y" | "Y" | "yes" => Ok(true),
            "n" | "N" | "no" => Ok(false),
            _ => Ok(default)
        }
    }

}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(
        "unable to read from stdin for confirmation".into())
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Ok(try!(Cfg::from_env(Arc::new(move |n: Notification| {
       if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))))

}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: rustup::Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, rustup::Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

pub fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            cmd.stdin(Stdio::null());
            cmd.stdout(Stdio::piped());
            cmd.stderr(Stdio::piped());
            toolchain.set_ldpath(&mut cmd);

            // some toolchains are faulty with some combinations of platforms and
            // may fail to launch but also to timely terminate.
            // (known cases include Rust 1.3.0 through 1.10.0 in recent macOS Sierra.)
            // we guard against such cases by enforcing a reasonable timeout to read.
            let mut line1 = None;
            if let Ok(mut child) = cmd.spawn() {
                let timeout = Duration::new(3, 0);
                match child.wait_timeout(timeout) {
                    Ok(Some(status)) if status.success() => {
                        let out = child.stdout.expect("Child::stdout requested but not present");
                        let mut line = String::new();
                        if BufReader::new(out).read_line(&mut line).is_ok() {
                            let lineend = line.trim_right_matches(&['\r', '\n'][..]).len();
                            line.truncate(lineend);
                            line1 = Some(line);
                        }
                    }
                    Ok(None) => {
                        let _ = child.kill();
                        return String::from("(timeout reading rustc version)")
                    }
                    Ok(Some(_)) | Err(_) => {}
                }
            }

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            let target = component.component.target.as_ref().expect("rust-std should have a target");
            if component.required {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (default)", target);
                let _ = t.reset();
            } else if component.installed {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (installed)", target);
                let _ = t.reset();
            } else if component.available {
                let _ = writeln!(t, "{}", target);
            }
        }
    }

    Ok(())
}

pub fn list_components(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        let name = component.component.name();
        if component.required {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (default)", name);
            let _ = t.reset();
        } else if component.installed {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (installed)", name);
            let _ = t.reset();
        } else if component.available {
            let _ = writeln!(t, "{}", name);
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let toolchains = try!(cfg.list_toolchains());

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let overrides = try!(cfg.settings_file.with(|s| Ok(s.overrides.clone())));

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        let mut any_not_exist = false;
        for (k, v) in overrides {
            let dir_exists = Path::new(&k).is_dir();
            if !dir_exists {
                any_not_exist = true;
            }
            println!("{:<40}\t{:<20}",
                     utils::format_path_for_display(&k) +
                     if dir_exists {
                         ""
                     } else {
                         " (not a directory)"
                     },
                     v)
        }
        if any_not_exist {
            println!("");
            info!("you may remove overrides for non-existent directories with
`rustup override unset --nonexistent`");
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    concat!(env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")))
}

pub fn report_error(e: &Error) {
    err!("{}", e);

    for e in e.iter().skip(1) {
        info!("caused by: {}", e);
    }

    if show_backtrace() {
        if let Some(backtrace) = e.backtrace() {
            info!("backtrace:");
            println!("");
            println!("{:?}", backtrace);
        }
    } else {
    }

    fn show_backtrace() -> bool {
        use std::env;
        use std::ops::Deref;

        if env::var("RUST_BACKTRACE").as_ref().map(Deref::deref) == Ok("1") {
            return true;
        }

        for arg in env::args() {
            if arg == "-v" || arg == "--verbose" {
                return true;
            }
        }

        false
    }
}

pub fn show_telemetry(analysis: TelemetryAnalysis) -> Result<()> {
    println!("Telemetry Analysis");

    println!("{}", analysis);

    Ok(())
}
<|endoftext|>


<commit_before>//! Facilities for implementing quiescence searching.
//!
//! Quiescence search is a restricted search which considers only a
//! limited set of moves (for example: winning captures, pawn
//! promotions to queen, check evasions). The goal is to statically
//! evaluate only "quiet" positions (positions where there are no
//! winning tactical moves to be made). Although this search can
//! cheaply and correctly resolve many simple tactical issues, it is
//! completely blind to the more complex ones.
//!
//! To implement your own quiescence search routine, you must define a
//! type that implements the `Qsearch` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use chesstypes::*;
use board::bitsets::*;
use board::tables::BoardGeometry;
use board::{Board, BoardEvaluator};
use search::QsearchResult;

/// Parameters describing a quiescence search.
pub struct QsearchParams<'a, T: MoveGenerator + 'a> {
    /// A mutable reference to the root position for the search.
    ///
    /// **Important note:** The search routine may use this reference
    /// to do and undo moves, but when the search is finished, all
    /// played moves must be taken back so that the board is restored
    /// to its original state.
    pub position: &'a mut T,

    /// The requested search depth.
    ///
    /// This is the depth at which the main search stops and the
    /// quiescence search takes on. It should be between `DEPTH_MIN`
    /// and `DEPTH_MAX`. Normally, it will be zero or less. The
    /// quiescence search implementation may decide to perform less
    /// thorough analysis when `depth` is smaller.
    pub depth: Depth,

    /// The lower bound for the new search.
    ///
    /// Should be no lesser than `VALUE_MIN`.
    pub lower_bound: Value,

    /// The upper bound for the new search.
    ///
    /// Should be greater than `lower_bound`, but no greater than
    /// `VALUE_MAX`.
    pub upper_bound: Value,

    /// Position's static evaluation, or `VALUE_UNKNOWN`.
    ///
    /// Saves the re-calculation if position's static evaluation is
    /// already available.
    pub static_evaluation: Value,
}

/// A trait for performing quiescence searches.
pub trait Qsearch: SetOption + Send {
    /// The type of move generator that the implementation works with.
    type MoveGenerator: MoveGenerator;

    /// The type of result object that the search produces.
    type QsearchResult: QsearchResult;

    /// Performs a quiescence search and returns a result object.
    fn qsearch(params: QsearchParams<Self::MoveGenerator>) -> Self::QsearchResult;
}

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position, can generate all or a
/// subset of all legal moves, perform static exchange evaluation,
/// play a selected move and take it back. It provides a position
/// evaluator, and can calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type BoardEvaluator: BoardEvaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method calculates the hash value
    /// "from scratch", which can be too slow for some use cases. (See
    /// `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::BoardEvaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Calculates the static exchange evaluation (SEE) value for a
    /// move.
    ///
    /// This method returns the likely evaluation change (material) to
    /// be lost or gained as a result of a given move. It examines the
    /// consequence of a series of exchanges on the destination square
    /// after a given move. The result is calculated without actually
    /// doing any moves on the board.
    fn calc_see(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < NO_PIECE);
        debug_assert!(m.captured_piece() <= NO_PIECE);
        const PIECE_VALUES: [Value; 7] = [10000, 975, 500, 325, 325, 100, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        let geometry = BoardGeometry::get();
        let behind_blocker: &[Bitboard; 64] = &geometry.squares_behind_blocker[exchange_square];
        let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
        let color: &[Bitboard; 2] = &self.board().pieces.color;
        let occupied = self.board().occupied;
        let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
        let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

        // `may_xray` holds the set of pieces that may block attacks
        // from other pieces. We will consider adding new
        // attackers/defenders every time a piece from the `may_xray`
        // set makes a capture.
        let may_xray = piece_type[PAWN] | piece_type[BISHOP] | piece_type[ROOK] | piece_type[QUEEN];

        // These variables will be updated on each capture:
        let mut us = self.board().to_move;
        let mut depth = 0;
        let mut piece;
        let mut orig_square_bb = 1 << m.orig_square();
        let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                          self.attacks_to(BLACK, exchange_square);

        // The `gain` array will hold the total material gained at
        // each `depth`, from the viewpoint of the side that made the
        // last capture (`us`).
        let mut gain: [Value; 34] = unsafe { uninitialized() };
        gain[0] = if m.move_type() == MOVE_PROMOTION {
            piece = Move::piece_from_aux_data(m.aux_data());
            PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
        } else {
            piece = m.played_piece();
            PIECE_VALUES[m.captured_piece()]
        };

        // Examine the possible exchanges, fill the `gain` array.
        'exchange: while orig_square_bb != 0 {
            // Store a speculative value that will be used if the
            // captured piece happens to be defended.
            gain[depth + 1] = PIECE_VALUES[piece] - gain[depth];

            if max(-gain[depth], gain[depth + 1]) < 0 {
                // The side that made the last capture wins even if
                // the captured piece happens to be defended. This is
                // good enough for our purposes, so we stop here.
                break;
            }

            // Register that `orig_square_bb` is now vacant.
            attackers_and_defenders &= !orig_square_bb;

            // Consider adding new attackers/defenders, now that
            // `orig_square_bb` is vacant.
            if orig_square_bb & may_xray != 0 {
                attackers_and_defenders |= {
                    let behind = behind_blocker[bitscan_forward(orig_square_bb)] & occupied;
                    match behind & straight_sliders &
                          geometry.attacks_from(ROOK, exchange_square, behind) {
                        0 => {
                            // Not a straight slider -- possibly a diagonal slider.
                            behind & diag_sliders &
                            geometry.attacks_from(BISHOP, exchange_square, behind)
                        }
                        x => x,
                    }
                };
            }

            // Change the side to move.
            us ^= 1;

            // Find the next piece to enter the exchange. (The least
            // valuable piece belonging to the side to move.)
            let candidates = attackers_and_defenders & color[us];
            if candidates != 0 {
                for p in (KING..NO_PIECE).rev() {
                    let bb = candidates & piece_type[p];
                    if bb != 0 {
                        depth += 1;
                        piece = p;
                        orig_square_bb = ls1b(bb);
                        continue 'exchange;
                    }
                }
            }
            break 'exchange;
        }

        // Negamax the `gain` array for the final static exchange
        // evaluation. (The `gain` array actually represents an unary
        // tree, at each node of which the player can either continue
        // the exchange or back off.)
        unsafe {
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
        }
        gain[0]
    }
}
<commit_msg>improve comment<commit_after>//! Facilities for implementing quiescence searching.
//!
//! Quiescence search is a restricted search which considers only a
//! limited set of moves (for example: winning captures, pawn
//! promotions to queen, check evasions). The goal is to statically
//! evaluate only "quiet" positions (positions where there are no
//! winning tactical moves to be made). Although this search can
//! cheaply and correctly resolve many simple tactical issues, it is
//! completely blind to the more complex ones.
//!
//! To implement your own quiescence search routine, you must define a
//! type that implements the `Qsearch` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use chesstypes::*;
use board::bitsets::*;
use board::tables::BoardGeometry;
use board::{Board, BoardEvaluator};
use search::QsearchResult;

/// Parameters describing a quiescence search.
pub struct QsearchParams<'a, T: MoveGenerator + 'a> {
    /// A mutable reference to the root position for the search.
    ///
    /// **Important note:** The search routine may use this reference
    /// to do and undo moves, but when the search is finished, all
    /// played moves must be taken back so that the board is restored
    /// to its original state.
    pub position: &'a mut T,

    /// The requested search depth.
    ///
    /// This is the depth at which the main search stops and the
    /// quiescence search takes on. It should be between `DEPTH_MIN`
    /// and `DEPTH_MAX`. Normally, it will be zero or less. The
    /// quiescence search implementation may decide to perform less
    /// thorough analysis when `depth` is smaller.
    pub depth: Depth,

    /// The lower bound for the new search.
    ///
    /// Should be no lesser than `VALUE_MIN`.
    pub lower_bound: Value,

    /// The upper bound for the new search.
    ///
    /// Should be greater than `lower_bound`, but no greater than
    /// `VALUE_MAX`.
    pub upper_bound: Value,

    /// Position's static evaluation, or `VALUE_UNKNOWN`.
    ///
    /// Saves the re-calculation if position's static evaluation is
    /// already available.
    pub static_evaluation: Value,
}

/// A trait for performing quiescence searches.
pub trait Qsearch: SetOption + Send {
    /// The type of move generator that the implementation works with.
    type MoveGenerator: MoveGenerator;

    /// The type of result object that the search produces.
    type QsearchResult: QsearchResult;

    /// Performs a quiescence search and returns a result object.
    fn qsearch(params: QsearchParams<Self::MoveGenerator>) -> Self::QsearchResult;
}

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position, can generate all or a
/// subset of all legal moves, perform static exchange evaluation,
/// play a selected move and take it back. It provides a position
/// evaluator, and can calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type BoardEvaluator: BoardEvaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method calculates the hash value
    /// "from scratch", which can be too slow for some use cases. (See
    /// `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::BoardEvaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Calculates the static exchange evaluation (SEE) value for a
    /// move.
    ///
    /// This method returns the likely evaluation change (material) to
    /// be lost or gained as a result of a given move. It examines the
    /// consequence of a series of exchanges on the destination square
    /// after a given move. The result is calculated without actually
    /// doing any moves on the board.
    fn calc_see(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < NO_PIECE);
        debug_assert!(m.captured_piece() <= NO_PIECE);
        const PIECE_VALUES: [Value; 7] = [10000, 975, 500, 325, 325, 100, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        let geometry = BoardGeometry::get();
        let behind_blocker: &[Bitboard; 64] = &geometry.squares_behind_blocker[exchange_square];
        let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
        let color: &[Bitboard; 2] = &self.board().pieces.color;
        let occupied = self.board().occupied;
        let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
        let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

        // `may_xray` holds the set of pieces that may block attacks
        // from other pieces. We will consider adding new
        // attackers/defenders every time a piece from the `may_xray`
        // set makes a capture.
        let may_xray = piece_type[PAWN] | piece_type[BISHOP] | piece_type[ROOK] | piece_type[QUEEN];

        // These variables will be updated on each capture:
        let mut us = self.board().to_move;
        let mut depth = 0;
        let mut piece;
        let mut orig_square_bb = 1 << m.orig_square();
        let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                          self.attacks_to(BLACK, exchange_square);

        // The `gain` array will hold the total material gained at
        // each `depth`, from the viewpoint of the side that made the
        // last capture (`us`).
        let mut gain: [Value; 34] = unsafe { uninitialized() };
        gain[0] = if m.move_type() == MOVE_PROMOTION {
            piece = Move::piece_from_aux_data(m.aux_data());
            PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
        } else {
            piece = m.played_piece();
            PIECE_VALUES[m.captured_piece()]
        };

        // Examine the possible exchanges, fill the `gain` array.
        'exchange: while orig_square_bb != 0 {
            // Store a speculative value that will be used if the
            // captured piece happens to be defended.
            gain[depth + 1] = PIECE_VALUES[piece] - gain[depth];

            if max(-gain[depth], gain[depth + 1]) < 0 {
                // The side that made the last capture wins even if
                // the captured piece happens to be defended. So, we
                // stop here to save precious CPU cycles. Note that
                // here we may happen to return an incorrect SEE
                // value, but the sign will be correct, which is by
                // far the most important information.
                break;
            }

            // Register that `orig_square_bb` is now vacant.
            attackers_and_defenders &= !orig_square_bb;

            // Consider adding new attackers/defenders, now that
            // `orig_square_bb` is vacant.
            if orig_square_bb & may_xray != 0 {
                attackers_and_defenders |= {
                    let behind = behind_blocker[bitscan_forward(orig_square_bb)] & occupied;
                    match behind & straight_sliders &
                          geometry.attacks_from(ROOK, exchange_square, behind) {
                        0 => {
                            // Not a straight slider -- possibly a diagonal slider.
                            behind & diag_sliders &
                            geometry.attacks_from(BISHOP, exchange_square, behind)
                        }
                        x => x,
                    }
                };
            }

            // Change the side to move.
            us ^= 1;

            // Find the next piece to enter the exchange. (The least
            // valuable piece belonging to the side to move.)
            let candidates = attackers_and_defenders & color[us];
            if candidates != 0 {
                for p in (KING..NO_PIECE).rev() {
                    let bb = candidates & piece_type[p];
                    if bb != 0 {
                        depth += 1;
                        piece = p;
                        orig_square_bb = ls1b(bb);
                        continue 'exchange;
                    }
                }
            }
            break 'exchange;
        }

        // Negamax the `gain` array for the final static exchange
        // evaluation. (The `gain` array actually represents an unary
        // tree, at each node of which the player can either continue
        // the exchange or back off.)
        unsafe {
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
        }
        gain[0]
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::net;
use std::str;
use std::time::Duration;

use clap::{App, Arg};
use log::{error, info, trace};

use uuid::Uuid;

use futures::join;
use futures::prelude::*;
use tokio::net::TcpStream;
use tokio::prelude::*;

use mqtt::control::variable_header::ConnectReturnCode;
use mqtt::packet::*;
use mqtt::TopicFilter;
use mqtt::{Decodable, Encodable, QualityOfService};

fn generate_client_id() -> String {
    format!("/MQTT/rust/{}", Uuid::new_v4())
}

#[tokio::main]
async fn main() {
    // configure logging
    env::set_var(
        "RUST_LOG",
        env::var_os("RUST_LOG").unwrap_or_else(|| "info".into()),
    );
    env_logger::init();

    let matches = App::new("sub-client")
        .author("Y. T. Chung <zonyitoo@gmail.com>")
        .arg(
            Arg::with_name("SERVER")
                .short("S")
                .long("server")
                .takes_value(true)
                .required(true)
                .help("MQTT server address (host:port)"),
        )
        .arg(
            Arg::with_name("SUBSCRIBE")
                .short("s")
                .long("subscribe")
                .takes_value(true)
                .multiple(true)
                .required(true)
                .help("Channel filter to subscribe"),
        )
        .arg(
            Arg::with_name("USER_NAME")
                .short("u")
                .long("username")
                .takes_value(true)
                .help("Login user name"),
        )
        .arg(
            Arg::with_name("PASSWORD")
                .short("p")
                .long("password")
                .takes_value(true)
                .help("Password"),
        )
        .arg(
            Arg::with_name("CLIENT_ID")
                .short("i")
                .long("client-identifier")
                .takes_value(true)
                .help("Client identifier"),
        )
        .get_matches();

    let server_addr = matches.value_of("SERVER").unwrap();
    let client_id = matches
        .value_of("CLIENT_ID")
        .map(|x| x.to_owned())
        .unwrap_or_else(generate_client_id);
    let channel_filters: Vec<(TopicFilter, QualityOfService)> = matches
        .values_of("SUBSCRIBE")
        .unwrap()
        .map(|c| {
            (
                TopicFilter::new(c.to_string()).unwrap(),
                QualityOfService::Level0,
            )
        })
        .collect();

    let keep_alive = 10;

    info!("Connecting to {:?} ... ", server_addr);
    let mut stream = net::TcpStream::connect(server_addr).unwrap();
    info!("Connected!");

    info!("Client identifier {:?}", client_id);
    let mut conn = ConnectPacket::new("MQTT", client_id);
    conn.set_clean_session(true);
    conn.set_keep_alive(keep_alive);
    let mut buf = Vec::new();
    conn.encode(&mut buf).unwrap();
    stream.write_all(&buf[..]).unwrap();

    let connack = ConnackPacket::decode(&mut stream).unwrap();
    trace!("CONNACK {:?}", connack);

    if connack.connect_return_code() != ConnectReturnCode::ConnectionAccepted {
        panic!(
            "Failed to connect to server, return code {:?}",
            connack.connect_return_code()
        );
    }

    // const CHANNEL_FILTER: &'static str = "typing-speed-test.aoeu.eu";
    info!("Applying channel filters {:?} ...", channel_filters);
    let sub = SubscribePacket::new(10, channel_filters);
    let mut buf = Vec::new();
    sub.encode(&mut buf).unwrap();
    stream.write_all(&buf[..]).unwrap();

    loop {
        let packet = match VariablePacket::decode(&mut stream) {
            Ok(pk) => pk,
            Err(err) => {
                error!("Error in receiving packet {:?}", err);
                continue;
            }
        };
        trace!("PACKET {:?}", packet);

        if let VariablePacket::SubackPacket(ref ack) = packet {
            if ack.packet_identifier() != 10 {
                panic!("SUBACK packet identifier not match");
            }

            info!("Subscribed!");
            break;
        }
    }

    // connection made, start the async work
    let mut stream = TcpStream::from_std(stream).unwrap();
    let (mut mqtt_read, mut mqtt_write) = stream.split();

    let ping_time = Duration::new((keep_alive / 2) as u64, 0);
    let mut ping_stream = tokio::time::interval(ping_time);

    let ping_sender = async move {
        while let Some(_) = ping_stream.next().await {
            info!("Sending PINGREQ to broker");

            let pingreq_packet = PingreqPacket::new();

            let mut buf = Vec::new();
            pingreq_packet.encode(&mut buf).unwrap();
            mqtt_write.write_all(&buf).await.unwrap();
        }
    };

    let receiver = async move {
        while let Ok(packet) = VariablePacket::parse(&mut mqtt_read).await {
            trace!("PACKET {:?}", packet);

            match packet {
                VariablePacket::PingrespPacket(..) => {
                    info!("Receiving PINGRESP from broker ..");
                }
                VariablePacket::PublishPacket(ref publ) => {
                    let msg = match str::from_utf8(&publ.payload_ref()[..]) {
                        Ok(msg) => msg,
                        Err(err) => {
                            error!("Failed to decode publish message {:?}", err);
                            continue;
                        }
                    };
                    info!("PUBLISH ({}): {}", publ.topic_name(), msg);
                }
                _ => {}
            }
        }
    };

    join!(ping_sender, receiver);
}
<commit_msg>Fix clippy redundant_pattern_matching<commit_after>use std::env;
use std::io::Write;
use std::net;
use std::str;
use std::time::Duration;

use clap::{App, Arg};
use log::{error, info, trace};

use uuid::Uuid;

use futures::join;
use futures::prelude::*;
use tokio::net::TcpStream;
use tokio::prelude::*;

use mqtt::control::variable_header::ConnectReturnCode;
use mqtt::packet::*;
use mqtt::TopicFilter;
use mqtt::{Decodable, Encodable, QualityOfService};

fn generate_client_id() -> String {
    format!("/MQTT/rust/{}", Uuid::new_v4())
}

#[tokio::main]
async fn main() {
    // configure logging
    env::set_var(
        "RUST_LOG",
        env::var_os("RUST_LOG").unwrap_or_else(|| "info".into()),
    );
    env_logger::init();

    let matches = App::new("sub-client")
        .author("Y. T. Chung <zonyitoo@gmail.com>")
        .arg(
            Arg::with_name("SERVER")
                .short("S")
                .long("server")
                .takes_value(true)
                .required(true)
                .help("MQTT server address (host:port)"),
        )
        .arg(
            Arg::with_name("SUBSCRIBE")
                .short("s")
                .long("subscribe")
                .takes_value(true)
                .multiple(true)
                .required(true)
                .help("Channel filter to subscribe"),
        )
        .arg(
            Arg::with_name("USER_NAME")
                .short("u")
                .long("username")
                .takes_value(true)
                .help("Login user name"),
        )
        .arg(
            Arg::with_name("PASSWORD")
                .short("p")
                .long("password")
                .takes_value(true)
                .help("Password"),
        )
        .arg(
            Arg::with_name("CLIENT_ID")
                .short("i")
                .long("client-identifier")
                .takes_value(true)
                .help("Client identifier"),
        )
        .get_matches();

    let server_addr = matches.value_of("SERVER").unwrap();
    let client_id = matches
        .value_of("CLIENT_ID")
        .map(|x| x.to_owned())
        .unwrap_or_else(generate_client_id);
    let channel_filters: Vec<(TopicFilter, QualityOfService)> = matches
        .values_of("SUBSCRIBE")
        .unwrap()
        .map(|c| {
            (
                TopicFilter::new(c.to_string()).unwrap(),
                QualityOfService::Level0,
            )
        })
        .collect();

    let keep_alive = 10;

    info!("Connecting to {:?} ... ", server_addr);
    let mut stream = net::TcpStream::connect(server_addr).unwrap();
    info!("Connected!");

    info!("Client identifier {:?}", client_id);
    let mut conn = ConnectPacket::new("MQTT", client_id);
    conn.set_clean_session(true);
    conn.set_keep_alive(keep_alive);
    let mut buf = Vec::new();
    conn.encode(&mut buf).unwrap();
    stream.write_all(&buf[..]).unwrap();

    let connack = ConnackPacket::decode(&mut stream).unwrap();
    trace!("CONNACK {:?}", connack);

    if connack.connect_return_code() != ConnectReturnCode::ConnectionAccepted {
        panic!(
            "Failed to connect to server, return code {:?}",
            connack.connect_return_code()
        );
    }

    // const CHANNEL_FILTER: &'static str = "typing-speed-test.aoeu.eu";
    info!("Applying channel filters {:?} ...", channel_filters);
    let sub = SubscribePacket::new(10, channel_filters);
    let mut buf = Vec::new();
    sub.encode(&mut buf).unwrap();
    stream.write_all(&buf[..]).unwrap();

    loop {
        let packet = match VariablePacket::decode(&mut stream) {
            Ok(pk) => pk,
            Err(err) => {
                error!("Error in receiving packet {:?}", err);
                continue;
            }
        };
        trace!("PACKET {:?}", packet);

        if let VariablePacket::SubackPacket(ref ack) = packet {
            if ack.packet_identifier() != 10 {
                panic!("SUBACK packet identifier not match");
            }

            info!("Subscribed!");
            break;
        }
    }

    // connection made, start the async work
    let mut stream = TcpStream::from_std(stream).unwrap();
    let (mut mqtt_read, mut mqtt_write) = stream.split();

    let ping_time = Duration::new((keep_alive / 2) as u64, 0);
    let mut ping_stream = tokio::time::interval(ping_time);

    let ping_sender = async move {
        while ping_stream.next().await.is_some() {
            info!("Sending PINGREQ to broker");

            let pingreq_packet = PingreqPacket::new();

            let mut buf = Vec::new();
            pingreq_packet.encode(&mut buf).unwrap();
            mqtt_write.write_all(&buf).await.unwrap();
        }
    };

    let receiver = async move {
        while let Ok(packet) = VariablePacket::parse(&mut mqtt_read).await {
            trace!("PACKET {:?}", packet);

            match packet {
                VariablePacket::PingrespPacket(..) => {
                    info!("Receiving PINGRESP from broker ..");
                }
                VariablePacket::PublishPacket(ref publ) => {
                    let msg = match str::from_utf8(&publ.payload_ref()[..]) {
                        Ok(msg) => msg,
                        Err(err) => {
                            error!("Failed to decode publish message {:?}", err);
                            continue;
                        }
                    };
                    info!("PUBLISH ({}): {}", publ.topic_name(), msg);
                }
                _ => {}
            }
        }
    };

    join!(ping_sender, receiver);
}
<|endoftext|>


<commit_before>use std::io;

macro_rules! readln {
    () => {
        {
            let mut line = String::new();
            match io::stdin().read_line(&mut line) {
                Ok(n) => Some(line.trim().to_string()),
                Err(e) => None
            }
        }
    };
}

fn console_title(title: &str) {

}

#[no_mangle]
pub fn main() {
    console_title("Test");

    println!("Type help for a command list");
    while let Some(line) = readln!() {
        let mut args: Vec<String> = Vec::new();
        for arg in line.split(' ') {
            args.push(arg.to_string());
        }

        if let Some(command) = args.get(0) {
            println!("# {}", line);

            if command == "panic" {
                panic!("Test panic");
            } else {
                println!("Commands: panic");
            }
        }
    }
}
<commit_msg>Adding `ls` command for test.rs<commit_after>use std::{io, fs};

macro_rules! readln {
    () => {
        {
            let mut line = String::new();
            match io::stdin().read_line(&mut line) {
                Ok(n) => Some(line.trim().to_string()),
                Err(e) => None
            }
        }
    };
}

fn console_title(title: &str) {

}

#[no_mangle]
pub fn main() {
    console_title("Test");

    println!("Type help for a command list");
    while let Some(line) = readln!() {
        let args: Vec<String> = line.split(' ').map(|arg| arg.to_string()).collect();

        if let Some(command) = args.get(0) {
            println!("# {}", line);

            match &command[..]
            {
                "panic" => panic!("Test panic"),
                "ls" => {
                    // TODO: when libredox is completed
                    //fs::read_dir("/").unwrap().map(|dir| println!("{}", dir));
                }
                _ => println!("Commands: panic"),
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate gl;
extern crate glfw;
extern crate time;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;

macro_rules! gl_str {
    ($string_literal:expr) => (concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar)
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;

    out vec3 Color;

    void main() {
        Color = color;
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;

    out vec4 out_color;

    void main() {
        out_color = vec4(Color, 1.0);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: GLfloat, y: GLfloat,

    // Color.
    r: GLfloat, g: GLfloat, b: GLfloat,
}

static VERTICES: [Vertex; 6] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right

    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0 }, // Bottom-left
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
        buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create a vertex array object.
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                size_of::<Vertex>() as GLint, std::ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                size_of::<Vertex>() as GLint,
                                std::ptr::null().offset(2 * size_of::<GLfloat>() as isize));
    }

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices.
            gl::DrawArrays(gl::TRIANGLES, 0, VERTICES.len() as GLint);
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<commit_msg>Draw a rectangle with an element buffer and no repeated vertices.<commit_after>extern crate gl;
extern crate glfw;
extern crate time;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;

macro_rules! gl_str {
    ($string_literal:expr) => (concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar)
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;

    out vec3 Color;

    void main() {
        Color = color;
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;

    out vec4 out_color;

    void main() {
        out_color = vec4(Color, 1.0);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: GLfloat, y: GLfloat,

    // Color.
    r: GLfloat, g: GLfloat, b: GLfloat,
}

static VERTICES: [Vertex; 4] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0 }, // Bottom-left
];

static ELEMENTS: [GLuint; 6] = [
    0, 1, 2, // Top-right triangle
    2, 3, 0, // Bottom-left triangle
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
        buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;
    let mut ebo = 0;

    unsafe {
        // Create a vertex array object.
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Create an element buffer object and copy the element data to it.
        gl::GenBuffers(1, &mut ebo);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                       mem::size_of_val(&ELEMENTS) as GLsizeiptr,
                       ELEMENTS.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint, std::ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                std::ptr::null().offset(2 * mem::size_of::<GLfloat>() as isize));
    }

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw the triangles described by the elements array.
            gl::DrawElements(gl::TRIANGLES, ELEMENTS.len() as GLint, gl::UNSIGNED_INT,
                             std::ptr::null());
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<|endoftext|>