<commit_before>//! Compares results of image processing functions to existing "truth" images.
//! All test images are taken from the caltech256 dataset.
//! http://authors.library.caltech.edu/7694/

#![feature(core)]
#![feature(test)]
#![feature(unboxed_closures)]

extern crate image;
extern crate test;
#[macro_use]
extern crate imageproc;

use std::path::Path;

use imageproc::utils::{
    load_image_or_panic
};

use imageproc::affine::{
    Interpolation,
    rotate_about_center
};

fn compare_to_truth_rgb(
    input_path: &Path,
    truth_path: &Path,
    op: &Fn(&image::RgbImage) -> image::RgbImage) {

    let truth = load_image_or_panic(&truth_path).to_rgb();
    let input = load_image_or_panic(&input_path).to_rgb();
    let actual = op.call((&input,));

    assert_pixels_eq!(actual, truth);
}

fn compare_to_truth_grayscale(
    input_path: &Path,
    truth_path: &Path,
    op: &Fn(&image::GrayImage) -> image::GrayImage) {

    let truth = load_image_or_panic(&truth_path).to_luma();
    let input = load_image_or_panic(&input_path).to_luma();
    let actual = op.call((&input,));

    assert_pixels_eq!(actual, truth);
}

fn rotate_nearest_about_center(image: &image::RgbImage) -> image::RgbImage {
    rotate_about_center(image, std::f32::consts::PI/4f32, Interpolation::Nearest)
}

#[test]
fn test_rotate_nearest_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_rotate_nearest.png");
    compare_to_truth_rgb(&ip, &tp, &rotate_nearest_about_center);
}

#[test]
fn test_equalize_histogram_grayscale() {
    let ip = Path::new("./tests/data/lumaphant.png");
    let tp = Path::new("./tests/data/truth/lumaphant_eq.png");
    compare_to_truth_grayscale(&ip, &tp, &imageproc::contrast::equalize_histogram);
}

fn rotate_bilinear_about_center(image: &image::RgbImage) -> image::RgbImage {
    rotate_about_center(image, std::f32::consts::PI/4f32, Interpolation::Bilinear)
}

#[test]
fn test_rotate_bilinear_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_rotate_bilinear.png");
    compare_to_truth_rgb(&ip, &tp, &rotate_bilinear_about_center);
}

fn affine_nearest(image: &image::RgbImage) -> image::RgbImage {
    let root_two_inv = 1f32/2f32.sqrt();
    let trans = imageproc::math::Affine2::new(
        imageproc::math::Mat2::new(
            root_two_inv, -root_two_inv,
            root_two_inv, root_two_inv) * 2f32,
        imageproc::math::Vec2::new(50f32, -70f32)
    );

    imageproc::affine::affine(
        image, trans,
        imageproc::affine::Interpolation::Nearest).unwrap()
}

#[test]
fn test_affine_nearest_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_affine_nearest.png");
    compare_to_truth_rgb(&ip, &tp, &affine_nearest);
}

fn affine_bilinear(image: &image::RgbImage) -> image::RgbImage {
    let root_two_inv = 1f32/2f32.sqrt();
    let trans = imageproc::math::Affine2::new(
        imageproc::math::Mat2::new(
            root_two_inv, -root_two_inv,
            root_two_inv, root_two_inv) * 2f32,
        imageproc::math::Vec2::new(50f32, -70f32)
    );

    imageproc::affine::affine(
        image, trans,
        imageproc::affine::Interpolation::Bilinear).unwrap()
}

#[test]
fn test_affine_bilinear_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_affine_bilinear.png");
    compare_to_truth_rgb(&ip, &tp, &affine_bilinear);
}

fn sobel_gradients(image: &image::GrayImage) -> image::GrayImage {
    use imageproc::definitions::Clamp;
    use imageproc::gradients;
    use imageproc::filter;
    filter::map_subpixels(
        &gradients::sobel_gradients(image),
        |x| u8::clamp(x))
}

#[test]
fn test_sobel_gradients() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_gradients.png");
    compare_to_truth_grayscale(&ip, &tp, &sobel_gradients);
}
<commit_msg>Attempt to fix Travis<commit_after>//! Compares results of image processing functions to existing "truth" images.
//! All test images are taken from the caltech256 dataset.
//! http://authors.library.caltech.edu/7694/

#![feature(core)]
#![feature(test)]
#![feature(unboxed_closures)]

extern crate image;
extern crate test;
#[macro_use]
extern crate imageproc;

use std::path::Path;

use imageproc::utils::{
    load_image_or_panic
};

use imageproc::affine::{
    Interpolation,
    rotate_about_center
};

fn compare_to_truth_rgb(
    input_path: &Path,
    truth_path: &Path,
    op: &Fn(&image::RgbImage) -> image::RgbImage) {

    let truth = load_image_or_panic(&truth_path).to_rgb();
    let input = load_image_or_panic(&input_path).to_rgb();
    let actual = op.call((&input,));

    assert_pixels_eq!(actual, truth);
}

fn compare_to_truth_rgb_with_tolerance(
    input_path: &Path,
    truth_path: &Path,
    op: &Fn(&image::RgbImage) -> image::RgbImage,
    tolerance: u8) {

    let truth = load_image_or_panic(&truth_path).to_rgb();
    let input = load_image_or_panic(&input_path).to_rgb();
    let actual = op.call((&input,));

    assert_pixels_eq_within!(actual, truth, tolerance);
}

fn compare_to_truth_grayscale(
    input_path: &Path,
    truth_path: &Path,
    op: &Fn(&image::GrayImage) -> image::GrayImage) {

    let truth = load_image_or_panic(&truth_path).to_luma();
    let input = load_image_or_panic(&input_path).to_luma();
    let actual = op.call((&input,));

    assert_pixels_eq!(actual, truth);
}

fn rotate_nearest_about_center(image: &image::RgbImage) -> image::RgbImage {
    rotate_about_center(image, std::f32::consts::PI/4f32, Interpolation::Nearest)
}

#[test]
fn test_rotate_nearest_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_rotate_nearest.png");
    compare_to_truth_rgb(&ip, &tp, &rotate_nearest_about_center);
}

#[test]
fn test_equalize_histogram_grayscale() {
    let ip = Path::new("./tests/data/lumaphant.png");
    let tp = Path::new("./tests/data/truth/lumaphant_eq.png");
    compare_to_truth_grayscale(&ip, &tp, &imageproc::contrast::equalize_histogram);
}

fn rotate_bilinear_about_center(image: &image::RgbImage) -> image::RgbImage {
    rotate_about_center(image, std::f32::consts::PI/4f32, Interpolation::Bilinear)
}

#[test]
fn test_rotate_bilinear_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_rotate_bilinear.png");
    compare_to_truth_rgb_with_tolerance(&ip, &tp, &rotate_bilinear_about_center, 1);
}

fn affine_nearest(image: &image::RgbImage) -> image::RgbImage {
    let root_two_inv = 1f32/2f32.sqrt();
    let trans = imageproc::math::Affine2::new(
        imageproc::math::Mat2::new(
            root_two_inv, -root_two_inv,
            root_two_inv, root_two_inv) * 2f32,
        imageproc::math::Vec2::new(50f32, -70f32)
    );

    imageproc::affine::affine(
        image, trans,
        imageproc::affine::Interpolation::Nearest).unwrap()
}

#[test]
fn test_affine_nearest_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_affine_nearest.png");
    compare_to_truth_rgb(&ip, &tp, &affine_nearest);
}

fn affine_bilinear(image: &image::RgbImage) -> image::RgbImage {
    let root_two_inv = 1f32/2f32.sqrt();
    let trans = imageproc::math::Affine2::new(
        imageproc::math::Mat2::new(
            root_two_inv, -root_two_inv,
            root_two_inv, root_two_inv) * 2f32,
        imageproc::math::Vec2::new(50f32, -70f32)
    );

    imageproc::affine::affine(
        image, trans,
        imageproc::affine::Interpolation::Bilinear).unwrap()
}

#[test]
fn test_affine_bilinear_rgb() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_affine_bilinear.png");
    compare_to_truth_rgb(&ip, &tp, &affine_bilinear);
}

fn sobel_gradients(image: &image::GrayImage) -> image::GrayImage {
    use imageproc::definitions::Clamp;
    use imageproc::gradients;
    use imageproc::filter;
    filter::map_subpixels(
        &gradients::sobel_gradients(image),
        |x| u8::clamp(x))
}

#[test]
fn test_sobel_gradients() {
    let ip = Path::new("./tests/data/elephant.png");
    let tp = Path::new("./tests/data/truth/elephant_gradients.png");
    compare_to_truth_grayscale(&ip, &tp, &sobel_gradients);
}
<|endoftext|>


<commit_before>use std::os;

fn main() {
	if os::args().len() < 2 {
		println("Error: Please provide a number as argument.");
		return;
	}

	let i = from_str::<int>(os::args()[1].as_slice()).unwrap();
	println!("{:d} has {:d} Collatz steps", i, collatz(i));
}

fn collatz(N: int) -> int {
	if N == 1 { return 0; }
	match N % 2 {
		0 => { 1 + collatz(N/2) }
		_ => { 1 + collatz(N*3+1) }
	}
}
<commit_msg>Bug and style fix<commit_after>use std::os;

fn main() {
	if os::args().len() < 2 {
		println!("Error: Please provide a number as argument.");
		return;
	}

	let i = from_str::<int>(os::args()[1].as_slice()).unwrap();
	println!("{:d} has {:d} Collatz steps", i, collatz(i));
}

fn collatz(n: int) -> int {
	if n == 1 { return 0; }
	match n % 2 {
		0 => { 1 + collatz(n/2) }
		_ => { 1 + collatz(n*3+1) }
	}
}
<|endoftext|>


<commit_before>extern crate gnuplot;
extern crate rustc_serialize;

use std::collections::HashMap;
use rustc_serialize::json;
use std::env;

use std::path::Path;
use std::fs;
use std::fs::File;
use std::io::Write;

use std::fs::DirEntry;
use std::u64;

use gnuplot::*;

fn get_dir_size(direntry: &DirEntry) -> u64 {
  // Initialize with the size of the current directory
  let mut size = direntry.metadata().unwrap().len();
  // Sum up the current file children
  for subfile in get_subfiles(direntry).iter() {
    let subfile_size = subfile.metadata().unwrap().len();
    size += subfile_size;
  }
  // And recurse into subdirectories
  for subdir in get_subdirs(direntry).iter() {
    size += get_dir_size(subdir); }
  size
}

fn is_dir(direntry : &DirEntry) -> bool {
  let metadata = direntry.metadata();
  return match metadata {
    Err(_) => false,
    Ok(metadata) => metadata.is_dir()
  }
}

fn get_subdirs(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subdirs(direntry.path().as_path())
}
fn get_subfiles(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subfiles(direntry.path().as_path())
}

fn get_path_subdirs(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| is_dir(c)).collect::<Vec<_>>()
}
fn get_path_subfiles(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| !is_dir(c)).collect::<Vec<_>>()
}

fn main() {
  let args: Vec<_> = env::args().collect();
  let mut min_size = u64::MAX;
  let mut max_size = 0;
  let arxiv_root = &Path::new(&args[1]);
  let mut arxiv_size_frequencies: HashMap<u64, u64> = HashMap::new();
  let mut arxiv_monthly_sizes: HashMap<String, u64> = HashMap::new();
  let mut arxiv_counts: HashMap<String, u64> = HashMap::new();
  let arxiv_month_dirs = get_path_subdirs(arxiv_root);

  for month_dir in arxiv_month_dirs.iter() {
    println!("-- Measuring {:?}", month_dir.file_name().to_str().unwrap());
    let mut monthly_size = 0;
    let month_papers = get_subdirs(month_dir);
    // Record how many papers were submitted in that month
    arxiv_counts.insert(month_dir.file_name().to_str().unwrap().to_string(), month_papers.len() as u64);

    for paper_dir in month_papers.iter() {
      // Record the size of each paper directory
      let paper_size = get_dir_size(paper_dir) / 1024; // In KB
      if paper_size > max_size {
        max_size = paper_size;
      }
      if paper_size < min_size {
        min_size = paper_size;
      }
      monthly_size += paper_size;

      let size_frequency = arxiv_size_frequencies.entry(paper_size).or_insert(0);
      *size_frequency += 1;
    }
    arxiv_monthly_sizes.insert(month_dir.file_name().to_str().unwrap().to_string(), monthly_size);
  }

  // Print the recorded stats

  let mut f = File::create("arxiv_submission_counts.json").unwrap();
  f.write_all(json::encode(&arxiv_counts).unwrap().as_bytes());

  let mut f2 = File::create("arxiv_monthly_sizes.json").unwrap();
  f2.write_all(json::encode(&arxiv_monthly_sizes).unwrap().as_bytes());

  let mut f3 = File::create("arxiv_size_frequencies.json").unwrap();
  f3.write_all(json::encode(&arxiv_size_frequencies).unwrap().as_bytes());

  // arXiv months in order
  // TODO: Only current as of 1505, you'll have to extend manually next time this is run
  let ordered_months = [
    "9107", "9108", "9109", "9110", "9111", "9112", "9201", "9202", "9203", "9204", "9205", "9206", "9207", "9208", "9209",
    "9210", "9211", "9212", "9301", "9302", "9303", "9304", "9305", "9306", "9307", "9308", "9309", "9310", "9311", "9312",
    "9401", "9402", "9403", "9404", "9405", "9406", "9407", "9408", "9409", "9410", "9411", "9412", "9501", "9502", "9503",
    "9504", "9505", "9506", "9507", "9508", "9509", "9510", "9511", "9512", "9601", "9602", "9603", "9604", "9605", "9606",
    "9607", "9608", "9609", "9610", "9611", "9612", "9701", "9702", "9703", "9704", "9705", "9706", "9707", "9708", "9709",
    "9710", "9711", "9712", "9801", "9802", "9803", "9804", "9805", "9806", "9807", "9808", "9809", "9810", "9811", "9812",
    "9901", "9902", "9903", "9904", "9905", "9906", "9907", "9908", "9909", "9910", "9911", "9912", "0001", "0002", "0003",
    "0004", "0005", "0006", "0007", "0008", "0009", "0010", "0011", "0012", "0101", "0102", "0103", "0104", "0105", "0106",
    "0107", "0108", "0109", "0110", "0111", "0112", "0201", "0202", "0203", "0204", "0205", "0206", "0207", "0208", "0209",
    "0210", "0211", "0212", "0301", "0302", "0303", "0304", "0305", "0306", "0307", "0308", "0309", "0310", "0311", "0312",
    "0401", "0402", "0403", "0404", "0405", "0406", "0407", "0408", "0409", "0410", "0411", "0412", "0501", "0502", "0503",
    "0504", "0505", "0506", "0507", "0508", "0509", "0510", "0511", "0512", "0601", "0602", "0603", "0604", "0605", "0606",
    "0607", "0608", "0609", "0610", "0611", "0612", "0701", "0702", "0703", "0704", "0705", "0706", "0707", "0708", "0709",
    "0710", "0711", "0712", "0801", "0802", "0803", "0804", "0805", "0806", "0807", "0808", "0809", "0810", "0811", "0812",
    "0901", "0902", "0903", "0904", "0905", "0906", "0907", "0908", "0909", "0910", "0911", "0912", "1001", "1002", "1003",
    "1004", "1005", "1006", "1007", "1008", "1009", "1010", "1011", "1012", "1101", "1102", "1103", "1104", "1105", "1106",
    "1107", "1108", "1109", "1110", "1111", "1112", "1201", "1202", "1203", "1204", "1205", "1206", "1207", "1208", "1209",
    "1210", "1211", "1212", "1301", "1302", "1303", "1304", "1305", "1306", "1307", "1308", "1309", "1310", "1311", "1312",
    "1401", "1402", "1403", "1404", "1405", "1406", "1407", "1408", "1409", "1410", "1411", "1412", "1501", "1502", "1503",
    "1504", "1505"];

  // Plot of paper counts by month:
  let zero = 0 as u64;
  let ordered_counts = ordered_months.iter().map(|m|
    match arxiv_counts.get(&m.to_string()) {
        Some(counts) => counts,
        None => &zero
    });
  let ordered_month_xcoords = 1..ordered_months.len()+1;

  let mut fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_counts, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submitted papers", &[Rotate(90.0)])
  .set_title("arXiv TeX submission counts", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_counts.png");
  fg.show();

  // Plot of submission counts by month:
  let ordered_sizes = ordered_months.iter().map(|m|
    match arxiv_monthly_sizes.get(&m.to_string()) {
        Some(&counts) => counts,
        None => zero
    });
  fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_sizes, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submission size in MB", &[Rotate(90.0)])
  .set_title("arXiv TeX submission sizes by month", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_sizes.png");
  fg.show();

  // Plot average paper size in KB
  // Plot of submission size by month:

  let freq_keys = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.0);
  let freq_values = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.1);

  fg = Figure::new();
  fg.axes2d()
  .points(freq_keys, freq_values, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("Paper size in KB", &[Rotate(45.0)])
  .set_y_label("Paper count", &[Rotate(90.0)])
  .set_title("arXiv TeX paper sizes", &[]);

  fg.set_terminal("pngcairo", "arxiv_paper_sizes.png");
  fg.show();

}<commit_msg>using more sophisticated rust for writing the stats files<commit_after>extern crate gnuplot;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::hash::Hash;
use rustc_serialize::*;

use std::env;

use std::path::Path;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::io::Result;

use std::fs::DirEntry;
use std::u64;

use gnuplot::*;

fn get_dir_size(direntry: &DirEntry) -> u64 {
  // Initialize with the size of the current directory
  let mut size = direntry.metadata().unwrap().len();
  // Sum up the current file children
  for subfile in get_subfiles(direntry).iter() {
    let subfile_size = subfile.metadata().unwrap().len();
    size += subfile_size;
  }
  // And recurse into subdirectories
  for subdir in get_subdirs(direntry).iter() {
    size += get_dir_size(subdir); }
  size
}

fn is_dir(direntry : &DirEntry) -> bool {
  let metadata = direntry.metadata();
  return match metadata {
    Err(_) => false,
    Ok(metadata) => metadata.is_dir()
  }
}

fn get_subdirs(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subdirs(direntry.path().as_path())
}
fn get_subfiles(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subfiles(direntry.path().as_path())
}

fn get_path_subdirs(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| is_dir(c)).collect::<Vec<_>>()
}
fn get_path_subfiles(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| !is_dir(c)).collect::<Vec<_>>()
}

fn write_stats<K: Hash + Eq + Encodable, V: Encodable>(name : &'static str, counts : &HashMap<K,V>) -> std::io::Result<()> {
  let mut f = try!(File::create(name));
  try!(f.write_all(json::encode(&counts).unwrap().as_bytes()));
  Ok(())
}

fn main() {
  let args: Vec<_> = env::args().collect();
  let mut min_size = u64::MAX;
  let mut max_size = 0;
  let arxiv_root = &Path::new(&args[1]);
  let mut arxiv_size_frequencies: HashMap<u64, u64> = HashMap::new();
  let mut arxiv_monthly_sizes: HashMap<String, u64> = HashMap::new();
  let mut arxiv_counts: HashMap<String, u64> = HashMap::new();
  let arxiv_month_dirs = get_path_subdirs(arxiv_root);

  for month_dir in arxiv_month_dirs.iter() {
    println!("-- Measuring {:?}", month_dir.file_name().to_str().unwrap());
    let mut monthly_size = 0;
    let month_papers = get_subdirs(month_dir);
    // Record how many papers were submitted in that month
    arxiv_counts.insert(month_dir.file_name().to_str().unwrap().to_string(), month_papers.len() as u64);

    for paper_dir in month_papers.iter() {
      // Record the size of each paper directory
      let paper_size = get_dir_size(paper_dir) / 1024; // In KB
      if paper_size > max_size {
        max_size = paper_size;
      }
      if paper_size < min_size {
        min_size = paper_size;
      }
      monthly_size += paper_size;

      let size_frequency = arxiv_size_frequencies.entry(paper_size).or_insert(0);
      *size_frequency += 1;
    }
    arxiv_monthly_sizes.insert(month_dir.file_name().to_str().unwrap().to_string(), monthly_size);
  }

  // Print the recorded stats
  match write_stats("arxiv_submission_counts.json", &arxiv_counts) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  match write_stats("arxiv_monthly_sizes.json", &arxiv_monthly_sizes) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  match write_stats("arxiv_size_frequencies.json", &arxiv_size_frequencies) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  // arXiv months in order
  // TODO: Only current as of 1505, you'll have to extend manually next time this is run
  let ordered_months = [
    "9107", "9108", "9109", "9110", "9111", "9112", "9201", "9202", "9203", "9204", "9205", "9206", "9207", "9208", "9209",
    "9210", "9211", "9212", "9301", "9302", "9303", "9304", "9305", "9306", "9307", "9308", "9309", "9310", "9311", "9312",
    "9401", "9402", "9403", "9404", "9405", "9406", "9407", "9408", "9409", "9410", "9411", "9412", "9501", "9502", "9503",
    "9504", "9505", "9506", "9507", "9508", "9509", "9510", "9511", "9512", "9601", "9602", "9603", "9604", "9605", "9606",
    "9607", "9608", "9609", "9610", "9611", "9612", "9701", "9702", "9703", "9704", "9705", "9706", "9707", "9708", "9709",
    "9710", "9711", "9712", "9801", "9802", "9803", "9804", "9805", "9806", "9807", "9808", "9809", "9810", "9811", "9812",
    "9901", "9902", "9903", "9904", "9905", "9906", "9907", "9908", "9909", "9910", "9911", "9912", "0001", "0002", "0003",
    "0004", "0005", "0006", "0007", "0008", "0009", "0010", "0011", "0012", "0101", "0102", "0103", "0104", "0105", "0106",
    "0107", "0108", "0109", "0110", "0111", "0112", "0201", "0202", "0203", "0204", "0205", "0206", "0207", "0208", "0209",
    "0210", "0211", "0212", "0301", "0302", "0303", "0304", "0305", "0306", "0307", "0308", "0309", "0310", "0311", "0312",
    "0401", "0402", "0403", "0404", "0405", "0406", "0407", "0408", "0409", "0410", "0411", "0412", "0501", "0502", "0503",
    "0504", "0505", "0506", "0507", "0508", "0509", "0510", "0511", "0512", "0601", "0602", "0603", "0604", "0605", "0606",
    "0607", "0608", "0609", "0610", "0611", "0612", "0701", "0702", "0703", "0704", "0705", "0706", "0707", "0708", "0709",
    "0710", "0711", "0712", "0801", "0802", "0803", "0804", "0805", "0806", "0807", "0808", "0809", "0810", "0811", "0812",
    "0901", "0902", "0903", "0904", "0905", "0906", "0907", "0908", "0909", "0910", "0911", "0912", "1001", "1002", "1003",
    "1004", "1005", "1006", "1007", "1008", "1009", "1010", "1011", "1012", "1101", "1102", "1103", "1104", "1105", "1106",
    "1107", "1108", "1109", "1110", "1111", "1112", "1201", "1202", "1203", "1204", "1205", "1206", "1207", "1208", "1209",
    "1210", "1211", "1212", "1301", "1302", "1303", "1304", "1305", "1306", "1307", "1308", "1309", "1310", "1311", "1312",
    "1401", "1402", "1403", "1404", "1405", "1406", "1407", "1408", "1409", "1410", "1411", "1412", "1501", "1502", "1503",
    "1504", "1505"];

  // Plot of paper counts by month:
  let zero = 0 as u64;
  let ordered_counts = ordered_months.iter().map(|m|
    match arxiv_counts.get(&m.to_string()) {
        Some(counts) => counts,
        None => &zero
    });
  let ordered_month_xcoords = 1..ordered_months.len()+1;

  let mut fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_counts, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submitted papers", &[Rotate(90.0)])
  .set_title("arXiv TeX submission counts", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_counts.png");
  fg.show();

  // Plot of submission counts by month:
  let ordered_sizes = ordered_months.iter().map(|m|
    match arxiv_monthly_sizes.get(&m.to_string()) {
        Some(&counts) => counts,
        None => zero
    });
  fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_sizes, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submission size in MB", &[Rotate(90.0)])
  .set_title("arXiv TeX submission sizes by month", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_sizes.png");
  fg.show();

  // Plot average paper size in KB
  // Plot of submission size by month:

  let freq_keys = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.0);
  let freq_values = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.1);

  fg = Figure::new();
  fg.axes2d()
  .points(freq_keys, freq_values, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("Paper size in KB", &[Rotate(45.0)])
  .set_y_label("Paper count", &[Rotate(90.0)])
  .set_title("arXiv TeX paper sizes", &[]);

  fg.set_terminal("pngcairo", "arxiv_paper_sizes.png");
  fg.show();

}<|endoftext|>


<commit_before>use rusoto_core::signature;
use rusoto_core::signature::SignedRequest;
use rusoto_core::param::{Params, ServiceParams};
use rusoto_core::region::Region;
use rusoto_core::credential::AwsCredentials;
use generated::{GetObjectRequest, GetObjectError};

/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
/// which require the `copy_source` field to be URL encoded.
///
/// # Examples
///
/// ```
/// use rusoto_s3::CopyObjectRequest;
///
/// let request = CopyObjectRequest {
///     bucket: "my-bucket".to_owned(),
///     key: "my-key".to_owned(),
///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
///     ..Default::default()
/// };
/// ```
pub fn encode_key<T: AsRef<str>>(key: T) -> String {
    signature::encode_uri_path(key.as_ref())
}

/// TODO: document this
pub fn generate_presigned_url(region: &Region, credentials: &AwsCredentials, input: &GetObjectRequest) -> Result<String, GetObjectError> {
    let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);

    let mut request = SignedRequest::new("GET", "s3", &region, &request_uri);

    if let Some(ref if_match) = input.if_match {
        request.add_header("If-Match", &if_match.to_string());
    }

    if let Some(ref if_modified_since) = input.if_modified_since {
        request.add_header("If-Modified-Since", &if_modified_since.to_string());
    }

    if let Some(ref if_none_match) = input.if_none_match {
        request.add_header("If-None-Match", &if_none_match.to_string());
    }

    if let Some(ref if_unmodified_since) = input.if_unmodified_since {
        request.add_header("If-Unmodified-Since", &if_unmodified_since.to_string());
    }

    if let Some(ref range) = input.range {
        request.add_header("Range", &range.to_string());
    }

    if let Some(ref request_payer) = input.request_payer {
        request.add_header("x-amz-request-payer", &request_payer.to_string());
    }

    if let Some(ref sse_customer_algorithm) = input.sse_customer_algorithm {
        request.add_header("x-amz-server-side-encryption-customer-algorithm",
                           &sse_customer_algorithm.to_string());
    }

    if let Some(ref sse_customer_key) = input.sse_customer_key {
        request.add_header("x-amz-server-side-encryption-customer-key",
                           &sse_customer_key.to_string());
    }

    if let Some(ref sse_customer_key_md5) = input.sse_customer_key_md5 {
        request.add_header("x-amz-server-side-encryption-customer-key-MD5",
                           &sse_customer_key_md5.to_string());
    }
    let mut params = Params::new();
    if let Some(ref x) = input.part_number {
        params.put("partNumber", x);
    }
    if let Some(ref x) = input.response_cache_control {
        params.put("response-cache-control", x);
    }
    if let Some(ref x) = input.response_content_disposition {
        params.put("response-content-disposition", x);
    }
    if let Some(ref x) = input.response_content_encoding {
        params.put("response-content-encoding", x);
    }
    if let Some(ref x) = input.response_content_language {
        params.put("response-content-language", x);
    }
    if let Some(ref x) = input.response_content_type {
        params.put("response-content-type", x);
    }
    if let Some(ref x) = input.response_expires {
        params.put("response-expires", x);
    }
    if let Some(ref x) = input.version_id {
        params.put("versionId", x);
    }
    request.set_params(params);

    Ok(request.generate_presigned_url(&credentials))
}
<commit_msg>add generate_presigned_url doc<commit_after>use rusoto_core::signature;
use rusoto_core::signature::SignedRequest;
use rusoto_core::param::{Params, ServiceParams};
use rusoto_core::region::Region;
use rusoto_core::credential::AwsCredentials;
use generated::{GetObjectRequest, GetObjectError};

/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
/// which require the `copy_source` field to be URL encoded.
///
/// # Examples
///
/// ```
/// use rusoto_s3::CopyObjectRequest;
///
/// let request = CopyObjectRequest {
///     bucket: "my-bucket".to_owned(),
///     key: "my-key".to_owned(),
///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
///     ..Default::default()
/// };
/// ```
pub fn encode_key<T: AsRef<str>>(key: T) -> String {
    signature::encode_uri_path(key.as_ref())
}

/// Generate a presigned url given arguments.
///
/// TODO: support another method like put, delete...
///
/// ```
/// extern crate rusoto_core;
/// extern crate rusoto_s3;
///
/// use rusoto_core::region::Region;
/// use rusoto_core::credential::AwsCredentials;
/// use rusoto_s3::util::generate_presigned_url;
/// use rusoto_s3::{GetObjectRequest, GetObjectError};
///
/// fn main() {
///     let region = Region::ApNortheast1;
///     let creds = AwsCredentials::new(
///         "xxx".to_string(),
///         "xxx".to_string(),
///         None,
///         None,
///     );
///     let req = GetObjectRequest {
///         bucket: "xxx".to_string(),
///         key: "xxx.jpg".to_string(),
///         ..Default::default()
///     };
///     let res = generate_presigned_url(&region, &creds, &req);
///     match res {
///       Ok(url) => { println!("{}", url); },
///       Err(err) => { println!("{}", err); },
///     }
/// }
/// ```
pub fn generate_presigned_url(region: &Region, credentials: &AwsCredentials, input: &GetObjectRequest) -> Result<String, GetObjectError> {
    let request_uri = format!("/{bucket}/{key}", bucket = input.bucket, key = input.key);

    let mut request = SignedRequest::new("GET", "s3", &region, &request_uri);

    if let Some(ref if_match) = input.if_match {
        request.add_header("If-Match", &if_match.to_string());
    }

    if let Some(ref if_modified_since) = input.if_modified_since {
        request.add_header("If-Modified-Since", &if_modified_since.to_string());
    }

    if let Some(ref if_none_match) = input.if_none_match {
        request.add_header("If-None-Match", &if_none_match.to_string());
    }

    if let Some(ref if_unmodified_since) = input.if_unmodified_since {
        request.add_header("If-Unmodified-Since", &if_unmodified_since.to_string());
    }

    if let Some(ref range) = input.range {
        request.add_header("Range", &range.to_string());
    }

    if let Some(ref request_payer) = input.request_payer {
        request.add_header("x-amz-request-payer", &request_payer.to_string());
    }

    if let Some(ref sse_customer_algorithm) = input.sse_customer_algorithm {
        request.add_header("x-amz-server-side-encryption-customer-algorithm",
                           &sse_customer_algorithm.to_string());
    }

    if let Some(ref sse_customer_key) = input.sse_customer_key {
        request.add_header("x-amz-server-side-encryption-customer-key",
                           &sse_customer_key.to_string());
    }

    if let Some(ref sse_customer_key_md5) = input.sse_customer_key_md5 {
        request.add_header("x-amz-server-side-encryption-customer-key-MD5",
                           &sse_customer_key_md5.to_string());
    }
    let mut params = Params::new();
    if let Some(ref x) = input.part_number {
        params.put("partNumber", x);
    }
    if let Some(ref x) = input.response_cache_control {
        params.put("response-cache-control", x);
    }
    if let Some(ref x) = input.response_content_disposition {
        params.put("response-content-disposition", x);
    }
    if let Some(ref x) = input.response_content_encoding {
        params.put("response-content-encoding", x);
    }
    if let Some(ref x) = input.response_content_language {
        params.put("response-content-language", x);
    }
    if let Some(ref x) = input.response_content_type {
        params.put("response-content-type", x);
    }
    if let Some(ref x) = input.response_expires {
        params.put("response-expires", x);
    }
    if let Some(ref x) = input.version_id {
        params.put("versionId", x);
    }
    request.set_params(params);

    Ok(request.generate_presigned_url(&credentials))
}
<|endoftext|>


<commit_before>fn plus_one(x: &int) -> int {
    *x + 1
}

fn main() {
    let y = box 10i;

    println!("{:d}", plus_one(&*y));
}
<commit_msg>update code for chapter-07<commit_after>fn plus_one(x: &int) -> int {
    *x + 1
}

fn main() {
    let y = box 10i;

    println!("{}", plus_one(&*y));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{TileOffset, LayoutRect, LayoutSize, LayoutPoint, DeviceUintSize};
use euclid::vec2;
use prim_store::EdgeAaSegmentMask;

/// If repetitions are far enough apart that only one is within
/// the primitive rect, then we can simplify the parameters and
/// treat the primitive as not repeated.
/// This can let us avoid unnecessary work later to handle some
/// of the parameters.
pub fn simplify_repeated_primitive(
    stretch_size: &LayoutSize,
    tile_spacing: &mut LayoutSize,
    prim_rect: &mut LayoutRect,
) {
    let stride = *stretch_size + *tile_spacing;

    if stride.width >= prim_rect.size.width {
        tile_spacing.width = 0.0;
        prim_rect.size.width = f32::min(prim_rect.size.width, stretch_size.width);
    }
    if stride.height >= prim_rect.size.height {
        tile_spacing.height = 0.0;
        prim_rect.size.height = f32::min(prim_rect.size.height, stretch_size.height);
    }
}

pub fn for_each_repetition(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    stride: &LayoutSize,
    callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
) {
    assert!(stride.width > 0.0);
    assert!(stride.height > 0.0);

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let nx = if visible_rect.origin.x > prim_rect.origin.x {
        f32::floor((visible_rect.origin.x - prim_rect.origin.x) / stride.width)
    } else {
        0.0
    };

    let ny = if visible_rect.origin.y > prim_rect.origin.y {
        f32::floor((visible_rect.origin.y - prim_rect.origin.y) / stride.height)
    } else {
        0.0
    };

    let x0 = prim_rect.origin.x + nx * stride.width;
    let y0 = prim_rect.origin.y + ny * stride.height;

    let mut p = LayoutPoint::new(x0, y0);

    let x_most = visible_rect.max_x();
    let y_most = visible_rect.max_y();

    let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
    let y_count = f32::ceil((y_most - y0) / stride.height) as i32;

    for y in 0..y_count {
        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&p, edge_flags);

            p.x += stride.width;
        }

        p.x = x0;
        p.y += stride.height;
    }
}

pub fn for_each_tile(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    device_image_size: &DeviceUintSize,
    device_tile_size: u32,
    callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
) {
    // The image resource is tiled. We have to generate an image primitive
    // for each tile.
    // We need to do this because the image is broken up into smaller tiles in the texture
    // cache and the image shader is not able to work with this type of sparse representation.

    // The tiling logic works as follows:
    //
    //  ###################-+  -+
    //  #    |    |    |//# |   | image size
    //  #    |    |    |//# |   |
    //  #----+----+----+--#-+   |  -+
    //  #    |    |    |//# |   |   | regular tile size
    //  #    |    |    |//# |   |   |
    //  #----+----+----+--#-+   |  -+-+
    //  #////|////|////|//# |   |     | "leftover" height
    //  ################### |  -+  ---+
    //  #----+----+----+----+
    //
    // In the ascii diagram above, a large image is split into tiles of almost regular size.
    // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
    // the regular tiles and are handled separately in the code see leftover_width/height.
    // each generated segment corresponds to a tile in the texture cache, with the
    // assumption that the smaller tiles with leftover sizes are sized to fit their own
    // irregular size in the texture cache.

    // Because we can have very large virtual images we iterate over the visible portion of
    // the image in layer space intead of iterating over device tiles.

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let device_tile_size_f32 = device_tile_size as f32;

    // Ratio between (image space) tile size and image size .
    let tile_dw = device_tile_size_f32 / (device_image_size.width as f32);
    let tile_dh = device_tile_size_f32 / (device_image_size.height as f32);

    // size of regular tiles in layout space.
    let layer_tile_size = LayoutSize::new(
        tile_dw * prim_rect.size.width,
        tile_dh * prim_rect.size.height,
    );

    // The size in pixels of the tiles on the right and bottom edges, smaller
    // than the regular tile size if the image is not a multiple of the tile size.
    // Zero means the image size is a multiple of the tile size.
    let leftover_device_size = DeviceUintSize::new(
        device_image_size.width % device_tile_size,
        device_image_size.height % device_tile_size
    );

    // The size in layer space of the tiles on the right and bottom edges.
    let leftover_layer_size = LayoutSize::new(
        layer_tile_size.width * leftover_device_size.width as f32 / device_tile_size_f32,
        layer_tile_size.height * leftover_device_size.height as f32 / device_tile_size_f32,
    );

    // Offset of the row and column of tiles with leftover size.
    let leftover_offset = TileOffset::new(
        (device_image_size.width / device_tile_size) as u16,
        (device_image_size.height / device_tile_size) as u16,
    );

    // Number of culled out tiles to skip before the first visible tile.
    let t0 = TileOffset::new(
        if visible_rect.origin.x > prim_rect.origin.x {
            f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as u16
        } else {
            0
        },
        if visible_rect.origin.y > prim_rect.origin.y {
            f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as u16
        } else {
            0
        },
    );

    let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
    let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;

    for y in 0..y_count {

        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let tile_offset = t0 + vec2(x, y);

            let mut segment_rect = LayoutRect {
                origin: LayoutPoint::new(
                    prim_rect.origin.x + tile_offset.x as f32 * layer_tile_size.width,
                    prim_rect.origin.y + tile_offset.y as f32 * layer_tile_size.height,
                ),
                size: layer_tile_size,
            };

            if tile_offset.x == leftover_offset.x {
                segment_rect.size.width = leftover_layer_size.width;
            }

            if tile_offset.y == leftover_offset.y {
                segment_rect.size.height = leftover_layer_size.height;
            }

            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&segment_rect, tile_offset, edge_flags);
        }
    }
}
<commit_msg>Add some tests for for_each_tile.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{TileOffset, LayoutRect, LayoutSize, LayoutPoint, DeviceUintSize};
use euclid::vec2;
use prim_store::EdgeAaSegmentMask;

/// If repetitions are far enough apart that only one is within
/// the primitive rect, then we can simplify the parameters and
/// treat the primitive as not repeated.
/// This can let us avoid unnecessary work later to handle some
/// of the parameters.
pub fn simplify_repeated_primitive(
    stretch_size: &LayoutSize,
    tile_spacing: &mut LayoutSize,
    prim_rect: &mut LayoutRect,
) {
    let stride = *stretch_size + *tile_spacing;

    if stride.width >= prim_rect.size.width {
        tile_spacing.width = 0.0;
        prim_rect.size.width = f32::min(prim_rect.size.width, stretch_size.width);
    }
    if stride.height >= prim_rect.size.height {
        tile_spacing.height = 0.0;
        prim_rect.size.height = f32::min(prim_rect.size.height, stretch_size.height);
    }
}

pub fn for_each_repetition(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    stride: &LayoutSize,
    callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
) {
    assert!(stride.width > 0.0);
    assert!(stride.height > 0.0);

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let nx = if visible_rect.origin.x > prim_rect.origin.x {
        f32::floor((visible_rect.origin.x - prim_rect.origin.x) / stride.width)
    } else {
        0.0
    };

    let ny = if visible_rect.origin.y > prim_rect.origin.y {
        f32::floor((visible_rect.origin.y - prim_rect.origin.y) / stride.height)
    } else {
        0.0
    };

    let x0 = prim_rect.origin.x + nx * stride.width;
    let y0 = prim_rect.origin.y + ny * stride.height;

    let mut p = LayoutPoint::new(x0, y0);

    let x_most = visible_rect.max_x();
    let y_most = visible_rect.max_y();

    let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
    let y_count = f32::ceil((y_most - y0) / stride.height) as i32;

    for y in 0..y_count {
        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&p, edge_flags);

            p.x += stride.width;
        }

        p.x = x0;
        p.y += stride.height;
    }
}

pub fn for_each_tile(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    device_image_size: &DeviceUintSize,
    device_tile_size: u32,
    callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
) {
    // The image resource is tiled. We have to generate an image primitive
    // for each tile.
    // We need to do this because the image is broken up into smaller tiles in the texture
    // cache and the image shader is not able to work with this type of sparse representation.

    // The tiling logic works as follows:
    //
    //  ###################-+  -+
    //  #    |    |    |//# |   | image size
    //  #    |    |    |//# |   |
    //  #----+----+----+--#-+   |  -+
    //  #    |    |    |//# |   |   | regular tile size
    //  #    |    |    |//# |   |   |
    //  #----+----+----+--#-+   |  -+-+
    //  #////|////|////|//# |   |     | "leftover" height
    //  ################### |  -+  ---+
    //  #----+----+----+----+
    //
    // In the ascii diagram above, a large image is split into tiles of almost regular size.
    // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
    // the regular tiles and are handled separately in the code see leftover_width/height.
    // each generated segment corresponds to a tile in the texture cache, with the
    // assumption that the smaller tiles with leftover sizes are sized to fit their own
    // irregular size in the texture cache.

    // Because we can have very large virtual images we iterate over the visible portion of
    // the image in layer space intead of iterating over device tiles.

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let device_tile_size_f32 = device_tile_size as f32;

    // Ratio between (image space) tile size and image size .
    let tile_dw = device_tile_size_f32 / (device_image_size.width as f32);
    let tile_dh = device_tile_size_f32 / (device_image_size.height as f32);

    // size of regular tiles in layout space.
    let layer_tile_size = LayoutSize::new(
        tile_dw * prim_rect.size.width,
        tile_dh * prim_rect.size.height,
    );

    // The size in pixels of the tiles on the right and bottom edges, smaller
    // than the regular tile size if the image is not a multiple of the tile size.
    // Zero means the image size is a multiple of the tile size.
    let leftover_device_size = DeviceUintSize::new(
        device_image_size.width % device_tile_size,
        device_image_size.height % device_tile_size
    );

    // The size in layer space of the tiles on the right and bottom edges.
    let leftover_layer_size = LayoutSize::new(
        layer_tile_size.width * leftover_device_size.width as f32 / device_tile_size_f32,
        layer_tile_size.height * leftover_device_size.height as f32 / device_tile_size_f32,
    );

    // Offset of the row and column of tiles with leftover size.
    let leftover_offset = TileOffset::new(
        (device_image_size.width / device_tile_size) as u16,
        (device_image_size.height / device_tile_size) as u16,
    );

    // Number of culled out tiles to skip before the first visible tile.
    let t0 = TileOffset::new(
        if visible_rect.origin.x > prim_rect.origin.x {
            f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as u16
        } else {
            0
        },
        if visible_rect.origin.y > prim_rect.origin.y {
            f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as u16
        } else {
            0
        },
    );

    let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
    let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;

    for y in 0..y_count {

        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let tile_offset = t0 + vec2(x, y);

            let mut segment_rect = LayoutRect {
                origin: LayoutPoint::new(
                    prim_rect.origin.x + tile_offset.x as f32 * layer_tile_size.width,
                    prim_rect.origin.y + tile_offset.y as f32 * layer_tile_size.height,
                ),
                size: layer_tile_size,
            };

            if tile_offset.x == leftover_offset.x {
                segment_rect.size.width = leftover_layer_size.width;
            }

            if tile_offset.y == leftover_offset.y {
                segment_rect.size.height = leftover_layer_size.height;
            }

            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&segment_rect, tile_offset, edge_flags);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;
    use api::{LayoutRect, DeviceUintSize};
    use euclid::{rect, size2};

    // this checks some additional invariants
    fn checked_for_each_tile(
        prim_rect: &LayoutRect,
        visible_rect: &LayoutRect,
        device_image_size: &DeviceUintSize,
        device_tile_size: u32,
        callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
    ) {
        let mut coverage = LayoutRect::zero();
        let mut tiles = HashSet::new();
        for_each_tile(prim_rect,
                      visible_rect,
                      device_image_size,
                      device_tile_size,
                      &mut |tile_rect, tile_offset, tile_flags| {
                          // make sure we don't get sent duplicate tiles
                          assert!(!tiles.contains(&tile_offset));
                          tiles.insert(tile_offset);
                          coverage = coverage.union(tile_rect);
                          assert!(prim_rect.contains_rect(&tile_rect));
                          callback(tile_rect, tile_offset, tile_flags);
                      },
        );
        assert!(prim_rect.contains_rect(&coverage));
        assert!(coverage.contains_rect(&visible_rect.intersection(&prim_rect).unwrap_or(LayoutRect::zero())));
    }

    #[test]
    fn basic() {
        let mut count = 0;
        checked_for_each_tile(&rect(0., 0., 1000., 1000.),
            &rect(75., 75., 400., 400.),
            &size2(400, 400),
            36,
            &mut |_tile_rect, _tile_offset, _tile_flags| {
                count += 1;
            },
        );
        assert_eq!(count, 36);
    }

    #[test]
    fn empty() {
        let mut count = 0;
        checked_for_each_tile(&rect(0., 0., 74., 74.),
              &rect(75., 75., 400., 400.),
              &size2(400, 400),
              36,
              &mut |_tile_rect, _tile_offset, _tile_flags| {
                count += 1;
              },
        );
        assert_eq!(count, 0);
    }
}<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use poem::{http::StatusCode, web::Accept, Error, FromRequest, Request, RequestBody, Result};

#[derive(PartialEq)]
pub enum AcceptType {
    Json,
    Bcs,
}

// This impl allows us to get the data straight from the arguments to the
// endpoint handler.
#[async_trait::async_trait]
impl<'a> FromRequest<'a> for AcceptType {
    async fn from_request(request: &'a Request, _body: &mut RequestBody) -> Result<Self> {
        let accept = Accept::from_request_without_body(request).await?;
        parse_accept(&accept)
    }
}

// Check that the accept type is one of the allowed variants. If there is no
// accept type and nothing explicitly not allowed, default to JSON.
fn parse_accept(accept: &Accept) -> Result<AcceptType> {
    for mime in &accept.0 {
        match mime.as_ref() {
            "application/json" => return Ok(AcceptType::Json),
            "application/x-bcs" => return Ok(AcceptType::Bcs),
            "*/*" => {}
            wildcard => {
                return Err(Error::from_string(
                    &format!("Unsupported Accept type: {:?}", wildcard),
                    StatusCode::NOT_ACCEPTABLE,
                ));
            }
        }
    }

    // Default to returning content as JSON.
    Ok(AcceptType::Json)
}
<commit_msg>[api] Change accept type handling<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::poem_backend::bcs_payload;
use poem::{web::Accept, FromRequest, Request, RequestBody, Result};

#[derive(PartialEq)]
pub enum AcceptType {
    Json,
    Bcs,
}

// This impl allows us to get the data straight from the arguments to the
// endpoint handler.
#[async_trait::async_trait]
impl<'a> FromRequest<'a> for AcceptType {
    async fn from_request(request: &'a Request, _body: &mut RequestBody) -> Result<Self> {
        let accept = Accept::from_request_without_body(request).await?;
        parse_accept(&accept)
    }
}

/// Check that the accept type is one of the allowed variants. If there is no
/// overriding explicit accept type, default to JSON.
fn parse_accept(accept: &Accept) -> Result<AcceptType> {
    for mime in &accept.0 {
        if bcs_payload::CONTENT_TYPE == mime.as_ref() {
            return Ok(AcceptType::Bcs);
        }
    }

    // Default to returning content as JSON.
    Ok(AcceptType::Json)
}
<|endoftext|>


<commit_before>/// Parser method generator.
///
/// Invoke inside an impl block. Declare a list of signatures of methods callable on `&mut self`.
/// The macro constructs a `parse(&mut self, input: &str) -> Result<(), String>` method that parses
/// input strings like "method_name 4 foo" into calls of `self.method_name(FromStr::from_str("4")?,
/// FromStr::from_str("foo")?)`.
///
///     # #[macro_use] extern crate calx_alg;
///     # fn main() {
///
///     struct Adder {
///         pub num: u32,
///     }
///
///     impl Adder {
///         fn add(&mut self, amount: u32) {
///             self.num += amount;
///         }
///
///         command_parser!{
///             fn add(&mut self, amount: u32);
///         }
///     }
///
///     let mut a = Adder { num: 1 };
///     a.add(2);
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("foobie bletch").is_err());
///     assert!(a.parse("add").is_err());       // Too few arguments
///     assert!(a.parse("add derp").is_err());  // Arguments won't parse to unsigned integer.
///     assert!(a.parse("add -1").is_err());
///     assert!(a.parse("add 1.0").is_err());
///
///     // NB: Due to limits of the macro implementation, trailing arguments
///     // are ignored instead of causing an error.
///     // assert!(a.parse("add 1 2").is_err());   // Too many arguments
///
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("add 3").is_ok());
///     assert_eq!(a.num, 6);
///
///     # }
#[macro_export]
macro_rules! command_parser {
    {
        $(fn $method:ident(&mut self$(, $argname:ident: $argtype:ty)*);)+
    } => {
        fn parse(&mut self, input: &str) -> ::std::result::Result<(), Box<::std::error::Error>> {
            #[derive(Debug)]
            struct ParseError(String);

            impl ::std::fmt::Display for ParseError {
                fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
                    self.0.fmt(fmt)
                }
            }

            impl ::std::error::Error for ParseError {
                fn description(&self) -> &str { &self.0 }
            }

            fn parse_err(s: String) -> ::std::result::Result<(), Box<::std::error::Error>> {
                Err(Box::new(ParseError(s)))
            }

            use ::std::str::FromStr;
            let input = input.trim_right();
            let mut elts = input.split(" ");
            let cmd = elts.next();
            if let Some(cmd) = cmd {
                match cmd {
                    $(
                    stringify!($method) => {
                        self.$method(
                            $({
                                if let Some(arg) = elts.next() {
                                    let param: $argtype = FromStr::from_str(arg)?;
                                    param
                                } else {
                                    return parse_err("Too few arguments".to_string());
                                }
                            }),*
                        );
                        Ok(())
                    }
                    )+
                    x => parse_err(format!("Unknown command {}", x)),
                }
            } else {
                return parse_err("No input".to_string());
            }
        }
    }
}
<commit_msg>Parser supports empty lists, does not emit spurious warnings<commit_after>/// Parser method generator.
///
/// Invoke inside an impl block. Declare a list of signatures of methods callable on `&mut self`.
/// The macro constructs a `parse(&mut self, input: &str) -> Result<(), String>` method that parses
/// input strings like "method_name 4 foo" into calls of `self.method_name(FromStr::from_str("4")?,
/// FromStr::from_str("foo")?)`.
///
///     # #[macro_use] extern crate calx_alg;
///     # fn main() {
///
///     struct Adder {
///         pub num: u32,
///     }
///
///     impl Adder {
///         fn add(&mut self, amount: u32) {
///             self.num += amount;
///         }
///
///         command_parser!{
///             fn add(&mut self, amount: u32);
///         }
///     }
///
///     let mut a = Adder { num: 1 };
///     a.add(2);
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("foobie bletch").is_err());
///     assert!(a.parse("add").is_err());       // Too few arguments
///     assert!(a.parse("add derp").is_err());  // Arguments won't parse to unsigned integer.
///     assert!(a.parse("add -1").is_err());
///     assert!(a.parse("add 1.0").is_err());
///
///     // NB: Due to limits of the macro implementation, trailing arguments
///     // are ignored instead of causing an error.
///     // assert!(a.parse("add 1 2").is_err());   // Too many arguments
///
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("add 3").is_ok());
///     assert_eq!(a.num, 6);
///
///     # }
#[macro_export]
macro_rules! command_parser {
    {
        // TODO: Should support immutable self methods too.
        $(fn $method:ident(&mut self$(, $argname:ident: $argtype:ty)*);)*
    } => {
        #[allow(unused)]
        fn parse(&mut self, input: &str) -> ::std::result::Result<(), Box<::std::error::Error>> {
            #[derive(Debug)]
            struct ParseError(String);

            impl ::std::fmt::Display for ParseError {
                fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
                    self.0.fmt(fmt)
                }
            }

            impl ::std::error::Error for ParseError {
                fn description(&self) -> &str { &self.0 }
            }

            fn parse_err(s: String) -> ::std::result::Result<(), Box<::std::error::Error>> {
                Err(Box::new(ParseError(s)))
            }

            use ::std::str::FromStr;
            let input = input.trim_right();
            let mut elts = input.split(" ");
            let cmd = elts.next();
            if let Some(cmd) = cmd {
                match cmd {
                    $(
                    stringify!($method) => {
                        self.$method(
                            $({
                                if let Some(arg) = elts.next() {
                                    let param: $argtype = FromStr::from_str(arg)?;
                                    param
                                } else {
                                    return parse_err("Too few arguments".to_string());
                                }
                            }),*
                        );
                        Ok(())
                    }
                    )*
                    x => parse_err(format!("Unknown command {}", x)),
                }
            } else {
                return parse_err("No input".to_string());
            }
        }
    }
}
<|endoftext|>


<commit_before>use winapi::shared::minwindef::{DWORD, HKEY};
use winapi::um::winnt::KEY_READ;
use winapi::um::winreg;

use intercom::*;

use std::ffi::OsString;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::path::PathBuf;

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
const CLSID_SetupConfiguration: GUID = GUID {
    data1: 0x177f_0c4a,
    data2: 0x1cd3,
    data3: 0x4de7,
    data4: [0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d],
};

#[repr(C)]
#[derive(Default, ForeignType, ExternOutput, ExternInput, Debug)]
pub struct FILETIME
{
    low_part: u32,
    high_part: u32,
}

#[com_interface(com_iid = "B41463C3-8866-43B5-BC33-2B0676F7F42E")]
pub trait ISetupInstance
{
    fn get_instance_id(&self) -> ComResult<String>;

    fn get_install_date(&self) -> ComResult<FILETIME>;

    fn get_installation_name(&self) -> ComResult<String>;

    fn get_installation_path(&self) -> ComResult<String>;

    fn get_installation_version(&self) -> ComResult<String>;

    fn get_display_name(&self, lcid: u32) -> ComResult<String>;

    fn get_description(&self, lcid: u32) -> ComResult<String>;

    fn resolve_path(&self, path: String) -> ComResult<String>;
}

#[com_interface(com_iid = "6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")]
pub trait IEnumSetupInstances
{
    fn next(&self, celt: u32) -> ComResult<(ComRc<dyn ISetupInstance>, u32)>;

    fn skip(&self, celt: u32) -> ComResult<()>;

    fn reset(&self) -> ComResult<()>;

    fn clone(&self) -> ComResult<ComRc<dyn IEnumSetupInstances>>;
}

#[com_interface(com_iid = "26AAB78C-4A60-49D6-AF3B-3C35BC93365D")]
pub trait ISetupConfiguration2
{
    fn enum_instances(&self) -> ComResult<ComRc<dyn IEnumSetupInstances>>;

    fn get_instance_for_current_process(&self) -> ComResult<ComRc<dyn ISetupInstance>>;

    fn get_instance_for_path(&self, path: String) -> ComResult<ComRc<dyn ISetupInstance>>;

    fn enum_all_instances(&self) -> ComResult<ComRc<dyn IEnumSetupInstances>>;
}

pub struct ToolPaths
{
    pub mt: PathBuf,
    pub rc: PathBuf,
    pub midl: PathBuf,

    pub vs_bin: PathBuf,

    pub libs: Vec<PathBuf>,
    pub incs: Vec<PathBuf>,
}

/// Finds a path for the target within the roots.
///
/// * `roots` - Roots to search the target under.
/// * `target` - Path to send. May contain directories, such as `x86/foo.lib`.
///
/// Returns the full path to the target or None if the target was not found.
fn find_path(roots: &[&PathBuf], path: &str) -> Option<PathBuf>
{
    // Glob options. We'll want case insensitive searching thanks to Windows.
    let options = glob::MatchOptions {
        case_sensitive: false,
        require_literal_separator: true,
        require_literal_leading_dot: true,
    };

    // Go through all the roots one by one.
    for root in roots {
        // Create the glob pattern. Concatenate the root with the target and
        // throw ** in between.
        let root_str = root.to_string_lossy();
        let pattern = format!("{}/**/{}", root_str, path);

        // Go through all entries.
        for entry in glob::glob_with(&pattern, options).unwrap() {
            if let Ok(entry_path) = entry {
                // The first entry we find, we'll return.
                return Some(entry_path);
            }
        }
    }

    // No paths found. Return none as the default.
    None
}

/// Get compiler paths from absolute file paths.
///
/// The compiler takes paths to the directories containing the files we want
/// as LIB and INCLUDE paths. This function strips the file name from the path
/// and deduplicates the resulting directories.
fn get_compiler_paths(paths: &[PathBuf]) -> Vec<PathBuf>
{
    // Get the directory paths from the file paths.
    let mut dir_paths = paths
        .iter()
        .filter_map(|p| p.parent().map(|p| p.to_owned()))
        .collect::<Vec<_>>();

    // De-duplicate the directories.
    dir_paths.sort();
    dir_paths.dedup();

    dir_paths
}

/// Gets the Windows kit path and version.
fn get_kit_path() -> Result<(String, String), String>
{
    unsafe {
        // Turn the various string constants into WCHAR* strings for winapi.
        let key = OsString::from("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots\0")
            .encode_wide()
            .collect::<Vec<_>>();
        let value = OsString::from("KitsRoot10\0")
            .encode_wide()
            .collect::<Vec<_>>();

        // Open the Installed Roots registry key.
        let mut hkey_roots: HKEY = std::ptr::null_mut();
        let mut disp: DWORD = 0;
        winreg::RegCreateKeyExW(
            winreg::HKEY_LOCAL_MACHINE,
            key.as_slice().as_ptr(),
            0,
            ::std::ptr::null_mut(),
            0,
            KEY_READ,
            std::ptr::null_mut(),
            &mut hkey_roots,
            &mut disp,
        );
        if hkey_roots.is_null() {
            return Err("Could not open Windows Kits registry key".to_owned());
        }

        // Get the 'KitsRoot10' value from the above key.
        let mut buf = Vec::with_capacity(250);
        let mut buf_len: DWORD = 250;
        let hr = winreg::RegQueryValueExW(
            hkey_roots,
            value.as_slice().as_ptr(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            buf.as_mut_ptr() as *mut _,
            &mut buf_len,
        );
        if hr != 0 {
            return Err("Could not read KitsRoot10 registry value".to_owned());
        }

        // Turn the value into a rust string.
        buf.set_len((buf_len / 2) as usize - 1);
        let kitsroot_osstring = OsString::from_wide(&buf);
        let kitsroot = kitsroot_osstring.to_string_lossy().to_owned();

        // Get the first sub-key under the Installed Roots. We don't really
        // care which kit version this is as long as it's one that is present
        // on the system.
        let mut buf = Vec::with_capacity(250);
        let mut buf_len: DWORD = 250;
        let hr = winreg::RegEnumKeyExW(
            hkey_roots,
            0,
            buf.as_mut_ptr(),
            &mut buf_len,
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
        );
        if hr != 0 {
            return Err("Could not read Windows Kits versions".to_owned());
        }

        // Turn the installed version to a rust string.
        buf.set_len(buf_len as usize);
        let kitsversion_osstring = OsString::from_wide(&buf);
        let kitsversion = kitsversion_osstring.to_string_lossy().to_owned();

        Ok((kitsroot.into_owned(), kitsversion.into_owned()))
    }
}

/// Gets the VS 2017+ installation path.
fn get_vs_path() -> Result<String, String>
{
    intercom::runtime::initialize().map_err(|hr| format!("Failed to initialize COM: {:?}", hr))?;

    let installation_path = {
        // Get the COM API entry point for the new VS configuration API.
        let setup_conf =
            ComRc::<dyn ISetupConfiguration2>::create(CLSID_SetupConfiguration).unwrap();

        // Get the first instance.
        let instances = setup_conf.enum_instances().unwrap();
        let (next, _) = instances.next(1).unwrap();

        // Read the installation path. We don't care about anything else for now.
        next.get_installation_path().unwrap()
    };

    intercom::runtime::uninitialize();

    Ok(installation_path)
}

pub fn get_tool_paths() -> Result<ToolPaths, String>
{
    // Get the Windows kit base path and version.
    let (kitroot, kitversion) = get_kit_path()?;
    let kitroot = PathBuf::from(&kitroot);

    // Form the kit lib and include paths.
    // let kit_lib_root = kitroot.join( "Lib" ).join( &kitversion );
    let kit_include_root = kitroot.join("Include").join(&kitversion);

    // Get the Visual C++ tools path.
    let vsroot = PathBuf::from(&get_vs_path()?).join(r"VC\Tools\MSVC");

    // Resolve the required libs.
    let libs = get_compiler_paths(&[

            // These paths cover most of the lib dirs. However no idea if we
            // need them so they are commented out until something complains.

            // find_path( &[ &kit_lib_root ], r"x64\ucrt.lib" ).unwrap(),
            // find_path( &[ &kit_lib_root ], r"x64\ole32.lib" ).unwrap(),
            // find_path( &[ &vsroot ], r"lib\x64\vcruntime.lib" ).unwrap(),
        ]);

    // Resolve the required include directories.
    let incs = get_compiler_paths(&[
        find_path(&[&kit_include_root], r"oaidl.idl").unwrap(),
        find_path(&[&kit_include_root], r"wtypes.idl").unwrap(),
    ]);

    // We'll need the C compiler for the preprocessing of the IDL.
    let mut vs_bin = find_path(&[&vsroot], r"Hostx64\x64\cl.exe").unwrap();
    vs_bin.pop();

    Ok(ToolPaths {
        mt: kitroot.join(format!(r"bin\{}\x64\mt.exe", kitversion)),
        midl: kitroot.join(format!(r"bin\{}\x64\midl.exe", kitversion)),
        rc: kitroot.join(format!(r"bin\{}\x64\rc.exe", kitversion)),

        vs_bin,
        libs,
        incs,
    })
}

#[cfg(test)]
mod test
{
    use super::*;
    use std::path::PathBuf;
    use std::process::Command;

    #[test]
    fn get_vs_2017_details()
    {
        intercom::runtime::initialize().unwrap();
        {
            let setup_conf =
                ComRc::<dyn ISetupConfiguration2>::create(CLSID_SetupConfiguration).unwrap();
            let instances = setup_conf.enum_instances().unwrap();

            let (next, _) = instances.next(1).unwrap();
            let installation_name = next.get_installation_name().unwrap();
            let installation_path = next.get_installation_path().unwrap();
            let installation_version = next.get_installation_version().unwrap();

            let installation_name_actual = get_vswhere_property("installationName");
            let installation_path_actual = get_vswhere_property("installationPath");
            let installation_version_actual = get_vswhere_property("installationVersion");

            assert_eq!(installation_name_actual.trim(), installation_name);
            assert_eq!(installation_path_actual.trim(), installation_path);
            assert_eq!(installation_version_actual.trim(), installation_version);
        }
        intercom::runtime::uninitialize();
    }

    fn get_intercom_root() -> PathBuf
    {
        let mut root_path = std::env::current_exe().unwrap();
        loop {
            if root_path.join("intercom-cli").exists() {
                break;
            }
            assert!(root_path.pop());
        }

        root_path
    }

    /// Gets the specified vswhere property.
    fn get_vswhere_property(property: &str) -> String
    {
        // First attempt to get the property without the "BuildTools" product.
        // If we don't get a result then try "BuildTools" explicitly.
        // We do this in two steps to avoid issues when the developer has both the Visual Studio and the BuildTools installed.
        let v = Some("[15, 16)");
        match get_vswhere_property_for_products(property, &[], v) {
            Ok(value) => value,
            Err(_) => get_vswhere_property_for_products(property, &["BuildTools"], v).unwrap(),
        }
    }

    /// Gets the specified vswhere property for the specified products.
    fn get_vswhere_property_for_products(
        property: &str,
        products: &[&str],
        version: Option<&str>,
    ) -> Result<String, String>
    {
        let vswhere_path = get_intercom_root().join("scripts/vswhere.exe");
        let mut cmd = Command::new(&vswhere_path);
        cmd.arg("/nologo").arg("-property").arg(property);
        if products.len() > 0 {
            cmd.arg("-products").args(products);
        }
        if let Some(v) = version {
            cmd.arg("-version").arg(v);
        }
        let property_from_output = cmd.output().unwrap().stdout;

        // Ensure we got exactly one result.
        let property_from_output: String = String::from_utf8_lossy(&property_from_output)
            .to_owned()
            .to_string();
        let mut values: Vec<&str> = property_from_output
            .split("\r\n")
            .filter_map(|s| if s.is_empty() { None } else { Some(s) })
            .collect();

        values.sort();
        values
            .first()
            .map(|l| l.to_string())
            .ok_or_else(|| format!("No VS build tools installed"))
    }

    #[test]
    fn get_tool_paths_returns_valid_paths()
    {
        intercom::runtime::initialize().unwrap();

        // The HOST env variable is set for build.rs, not for tests.
        // We need to fake one here.
        std::env::set_var("HOST", "x86_64-pc-windows-msvc");

        let paths = get_tool_paths().unwrap();
        assert!(paths.mt.exists());
        assert!(paths.rc.exists());
        assert!(paths.midl.exists());

        intercom::runtime::uninitialize();
    }
}
<commit_msg>Fix Windows build<commit_after>use winapi::shared::minwindef::{DWORD, HKEY};
use winapi::um::winnt::KEY_READ;
use winapi::um::winreg;

use intercom::*;

use std::ffi::OsString;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::path::PathBuf;

#[allow(dead_code)]
#[allow(non_upper_case_globals)]
const CLSID_SetupConfiguration: GUID = GUID {
    data1: 0x177f_0c4a,
    data2: 0x1cd3,
    data3: 0x4de7,
    data4: [0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d],
};

#[repr(C)]
#[derive(Default, ForeignType, ExternType, ExternOutput, ExternInput, Debug)]
pub struct FILETIME
{
    low_part: u32,
    high_part: u32,
}

#[com_interface(com_iid = "B41463C3-8866-43B5-BC33-2B0676F7F42E")]
pub trait ISetupInstance
{
    fn get_instance_id(&self) -> ComResult<String>;

    fn get_install_date(&self) -> ComResult<FILETIME>;

    fn get_installation_name(&self) -> ComResult<String>;

    fn get_installation_path(&self) -> ComResult<String>;

    fn get_installation_version(&self) -> ComResult<String>;

    fn get_display_name(&self, lcid: u32) -> ComResult<String>;

    fn get_description(&self, lcid: u32) -> ComResult<String>;

    fn resolve_path(&self, path: String) -> ComResult<String>;
}

#[com_interface(com_iid = "6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")]
pub trait IEnumSetupInstances
{
    fn next(&self, celt: u32) -> ComResult<(ComRc<dyn ISetupInstance>, u32)>;

    fn skip(&self, celt: u32) -> ComResult<()>;

    fn reset(&self) -> ComResult<()>;

    fn clone(&self) -> ComResult<ComRc<dyn IEnumSetupInstances>>;
}

#[com_interface(com_iid = "26AAB78C-4A60-49D6-AF3B-3C35BC93365D")]
pub trait ISetupConfiguration2
{
    fn enum_instances(&self) -> ComResult<ComRc<dyn IEnumSetupInstances>>;

    fn get_instance_for_current_process(&self) -> ComResult<ComRc<dyn ISetupInstance>>;

    fn get_instance_for_path(&self, path: String) -> ComResult<ComRc<dyn ISetupInstance>>;

    fn enum_all_instances(&self) -> ComResult<ComRc<dyn IEnumSetupInstances>>;
}

pub struct ToolPaths
{
    pub mt: PathBuf,
    pub rc: PathBuf,
    pub midl: PathBuf,

    pub vs_bin: PathBuf,

    pub libs: Vec<PathBuf>,
    pub incs: Vec<PathBuf>,
}

/// Finds a path for the target within the roots.
///
/// * `roots` - Roots to search the target under.
/// * `target` - Path to send. May contain directories, such as `x86/foo.lib`.
///
/// Returns the full path to the target or None if the target was not found.
fn find_path(roots: &[&PathBuf], path: &str) -> Option<PathBuf>
{
    // Glob options. We'll want case insensitive searching thanks to Windows.
    let options = glob::MatchOptions {
        case_sensitive: false,
        require_literal_separator: true,
        require_literal_leading_dot: true,
    };

    // Go through all the roots one by one.
    for root in roots {
        // Create the glob pattern. Concatenate the root with the target and
        // throw ** in between.
        let root_str = root.to_string_lossy();
        let pattern = format!("{}/**/{}", root_str, path);

        // Go through all entries.
        for entry in glob::glob_with(&pattern, options).unwrap() {
            if let Ok(entry_path) = entry {
                // The first entry we find, we'll return.
                return Some(entry_path);
            }
        }
    }

    // No paths found. Return none as the default.
    None
}

/// Get compiler paths from absolute file paths.
///
/// The compiler takes paths to the directories containing the files we want
/// as LIB and INCLUDE paths. This function strips the file name from the path
/// and deduplicates the resulting directories.
fn get_compiler_paths(paths: &[PathBuf]) -> Vec<PathBuf>
{
    // Get the directory paths from the file paths.
    let mut dir_paths = paths
        .iter()
        .filter_map(|p| p.parent().map(|p| p.to_owned()))
        .collect::<Vec<_>>();

    // De-duplicate the directories.
    dir_paths.sort();
    dir_paths.dedup();

    dir_paths
}

/// Gets the Windows kit path and version.
fn get_kit_path() -> Result<(String, String), String>
{
    unsafe {
        // Turn the various string constants into WCHAR* strings for winapi.
        let key = OsString::from("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots\0")
            .encode_wide()
            .collect::<Vec<_>>();
        let value = OsString::from("KitsRoot10\0")
            .encode_wide()
            .collect::<Vec<_>>();

        // Open the Installed Roots registry key.
        let mut hkey_roots: HKEY = std::ptr::null_mut();
        let mut disp: DWORD = 0;
        winreg::RegCreateKeyExW(
            winreg::HKEY_LOCAL_MACHINE,
            key.as_slice().as_ptr(),
            0,
            ::std::ptr::null_mut(),
            0,
            KEY_READ,
            std::ptr::null_mut(),
            &mut hkey_roots,
            &mut disp,
        );
        if hkey_roots.is_null() {
            return Err("Could not open Windows Kits registry key".to_owned());
        }

        // Get the 'KitsRoot10' value from the above key.
        let mut buf = Vec::with_capacity(250);
        let mut buf_len: DWORD = 250;
        let hr = winreg::RegQueryValueExW(
            hkey_roots,
            value.as_slice().as_ptr(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            buf.as_mut_ptr() as *mut _,
            &mut buf_len,
        );
        if hr != 0 {
            return Err("Could not read KitsRoot10 registry value".to_owned());
        }

        // Turn the value into a rust string.
        buf.set_len((buf_len / 2) as usize - 1);
        let kitsroot_osstring = OsString::from_wide(&buf);
        let kitsroot = kitsroot_osstring.to_string_lossy().to_owned();

        // Get the first sub-key under the Installed Roots. We don't really
        // care which kit version this is as long as it's one that is present
        // on the system.
        let mut buf = Vec::with_capacity(250);
        let mut buf_len: DWORD = 250;
        let hr = winreg::RegEnumKeyExW(
            hkey_roots,
            0,
            buf.as_mut_ptr(),
            &mut buf_len,
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
            std::ptr::null_mut(),
        );
        if hr != 0 {
            return Err("Could not read Windows Kits versions".to_owned());
        }

        // Turn the installed version to a rust string.
        buf.set_len(buf_len as usize);
        let kitsversion_osstring = OsString::from_wide(&buf);
        let kitsversion = kitsversion_osstring.to_string_lossy().to_owned();

        Ok((kitsroot.into_owned(), kitsversion.into_owned()))
    }
}

/// Gets the VS 2017+ installation path.
fn get_vs_path() -> Result<String, String>
{
    intercom::runtime::initialize().map_err(|hr| format!("Failed to initialize COM: {:?}", hr))?;

    let installation_path = {
        // Get the COM API entry point for the new VS configuration API.
        let setup_conf =
            ComRc::<dyn ISetupConfiguration2>::create(CLSID_SetupConfiguration).unwrap();

        // Get the first instance.
        let instances = setup_conf.enum_instances().unwrap();
        let (next, _) = instances.next(1).unwrap();

        // Read the installation path. We don't care about anything else for now.
        next.get_installation_path().unwrap()
    };

    intercom::runtime::uninitialize();

    Ok(installation_path)
}

pub fn get_tool_paths() -> Result<ToolPaths, String>
{
    // Get the Windows kit base path and version.
    let (kitroot, kitversion) = get_kit_path()?;
    let kitroot = PathBuf::from(&kitroot);

    // Form the kit lib and include paths.
    // let kit_lib_root = kitroot.join( "Lib" ).join( &kitversion );
    let kit_include_root = kitroot.join("Include").join(&kitversion);

    // Get the Visual C++ tools path.
    let vsroot = PathBuf::from(&get_vs_path()?).join(r"VC\Tools\MSVC");

    // Resolve the required libs.
    let libs = get_compiler_paths(&[

            // These paths cover most of the lib dirs. However no idea if we
            // need them so they are commented out until something complains.

            // find_path( &[ &kit_lib_root ], r"x64\ucrt.lib" ).unwrap(),
            // find_path( &[ &kit_lib_root ], r"x64\ole32.lib" ).unwrap(),
            // find_path( &[ &vsroot ], r"lib\x64\vcruntime.lib" ).unwrap(),
        ]);

    // Resolve the required include directories.
    let incs = get_compiler_paths(&[
        find_path(&[&kit_include_root], r"oaidl.idl").unwrap(),
        find_path(&[&kit_include_root], r"wtypes.idl").unwrap(),
    ]);

    // We'll need the C compiler for the preprocessing of the IDL.
    let mut vs_bin = find_path(&[&vsroot], r"Hostx64\x64\cl.exe").unwrap();
    vs_bin.pop();

    Ok(ToolPaths {
        mt: kitroot.join(format!(r"bin\{}\x64\mt.exe", kitversion)),
        midl: kitroot.join(format!(r"bin\{}\x64\midl.exe", kitversion)),
        rc: kitroot.join(format!(r"bin\{}\x64\rc.exe", kitversion)),

        vs_bin,
        libs,
        incs,
    })
}

#[cfg(test)]
mod test
{
    use super::*;
    use std::path::PathBuf;
    use std::process::Command;

    #[test]
    fn get_vs_2017_details()
    {
        intercom::runtime::initialize().unwrap();
        {
            let setup_conf =
                ComRc::<dyn ISetupConfiguration2>::create(CLSID_SetupConfiguration).unwrap();
            let instances = setup_conf.enum_instances().unwrap();

            let (next, _) = instances.next(1).unwrap();
            let installation_name = next.get_installation_name().unwrap();
            let installation_path = next.get_installation_path().unwrap();
            let installation_version = next.get_installation_version().unwrap();

            let installation_name_actual = get_vswhere_property("installationName");
            let installation_path_actual = get_vswhere_property("installationPath");
            let installation_version_actual = get_vswhere_property("installationVersion");

            assert_eq!(installation_name_actual.trim(), installation_name);
            assert_eq!(installation_path_actual.trim(), installation_path);
            assert_eq!(installation_version_actual.trim(), installation_version);
        }
        intercom::runtime::uninitialize();
    }

    fn get_intercom_root() -> PathBuf
    {
        let mut root_path = std::env::current_exe().unwrap();
        loop {
            if root_path.join("intercom-cli").exists() {
                break;
            }
            assert!(root_path.pop());
        }

        root_path
    }

    /// Gets the specified vswhere property.
    fn get_vswhere_property(property: &str) -> String
    {
        // First attempt to get the property without the "BuildTools" product.
        // If we don't get a result then try "BuildTools" explicitly.
        // We do this in two steps to avoid issues when the developer has both the Visual Studio and the BuildTools installed.
        let v = Some("[15, 16)");
        match get_vswhere_property_for_products(property, &[], v) {
            Ok(value) => value,
            Err(_) => get_vswhere_property_for_products(property, &["BuildTools"], v).unwrap(),
        }
    }

    /// Gets the specified vswhere property for the specified products.
    fn get_vswhere_property_for_products(
        property: &str,
        products: &[&str],
        version: Option<&str>,
    ) -> Result<String, String>
    {
        let vswhere_path = get_intercom_root().join("scripts/vswhere.exe");
        let mut cmd = Command::new(&vswhere_path);
        cmd.arg("/nologo").arg("-property").arg(property);
        if products.len() > 0 {
            cmd.arg("-products").args(products);
        }
        if let Some(v) = version {
            cmd.arg("-version").arg(v);
        }
        let property_from_output = cmd.output().unwrap().stdout;

        // Ensure we got exactly one result.
        let property_from_output: String = String::from_utf8_lossy(&property_from_output)
            .to_owned()
            .to_string();
        let mut values: Vec<&str> = property_from_output
            .split("\r\n")
            .filter_map(|s| if s.is_empty() { None } else { Some(s) })
            .collect();

        values.sort();
        values
            .first()
            .map(|l| l.to_string())
            .ok_or_else(|| format!("No VS build tools installed"))
    }

    #[test]
    fn get_tool_paths_returns_valid_paths()
    {
        intercom::runtime::initialize().unwrap();

        // The HOST env variable is set for build.rs, not for tests.
        // We need to fake one here.
        std::env::set_var("HOST", "x86_64-pc-windows-msvc");

        let paths = get_tool_paths().unwrap();
        assert!(paths.mt.exists());
        assert!(paths.rc.exists());
        assert!(paths.midl.exists());

        intercom::runtime::uninitialize();
    }
}
<|endoftext|>


<commit_before>//! This module contains an import search funcionality that is provided to the ra_assists module.
//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.

use crate::{
    db::RootDatabase,
    references::{classify_name, classify_name_ref, NameDefinition, NameKind},
    symbol_index::{self, FileSymbol},
    Query,
};
use ast::NameRef;
use hir::{db::HirDatabase, InFile, ModPath, Module, SourceBinder};
use itertools::Itertools;
use ra_assists::ImportsLocator;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, SyntaxKind::NAME};

pub(crate) struct ImportsLocatorIde<'a> {
    source_binder: SourceBinder<'a, RootDatabase>,
}

impl<'a> ImportsLocatorIde<'a> {
    pub(crate) fn new(db: &'a RootDatabase) -> Self {
        Self { source_binder: SourceBinder::new(db) }
    }

    fn search_for_imports(
        &mut self,
        name_to_import: &ast::NameRef,
        module_with_name_to_import: Module,
    ) -> Vec<ModPath> {
        let _p = profile("search_for_imports");
        let db = self.source_binder.db;
        let name_to_import = name_to_import.text();

        let project_results = {
            let mut query = Query::new(name_to_import.to_string());
            query.exact();
            query.limit(10);
            symbol_index::world_symbols(db, query)
        };
        let lib_results = {
            let mut query = Query::new(name_to_import.to_string());
            query.libs();
            query.exact();
            query.limit(10);
            symbol_index::world_symbols(db, query)
        };

        project_results
            .into_iter()
            .chain(lib_results.into_iter())
            .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate))
            .filter_map(|name_definition_to_import| {
                if let NameKind::Def(module_def) = name_definition_to_import.kind {
                    module_with_name_to_import.find_use_path(db, module_def)
                } else {
                    None
                }
            })
            .filter(|use_path| !use_path.segments.is_empty())
            .unique()
            .collect()
    }

    fn get_name_definition(
        &mut self,
        db: &impl HirDatabase,
        import_candidate: &FileSymbol,
    ) -> Option<NameDefinition> {
        let _p = profile("get_name_definition");
        let file_id = import_candidate.file_id.into();
        let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
        let candidate_name_node = if candidate_node.kind() != NAME {
            candidate_node.children().find(|it| it.kind() == NAME)?
        } else {
            candidate_node
        };
        classify_name(
            &mut self.source_binder,
            hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
        )
    }
}

impl<'a> ImportsLocator for ImportsLocatorIde<'a> {
    fn find_imports(
        &mut self,
        name_to_import: InFile<&NameRef>,
        module_with_name_to_import: Module,
    ) -> Option<Vec<ModPath>> {
        if classify_name_ref(&mut self.source_binder, name_to_import).is_none() {
            Some(self.search_for_imports(name_to_import.value, module_with_name_to_import))
        } else {
            None
        }
    }
}
<commit_msg>Raise the import search query cap<commit_after>//! This module contains an import search funcionality that is provided to the ra_assists module.
//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.

use crate::{
    db::RootDatabase,
    references::{classify_name, classify_name_ref, NameDefinition, NameKind},
    symbol_index::{self, FileSymbol},
    Query,
};
use ast::NameRef;
use hir::{db::HirDatabase, InFile, ModPath, Module, SourceBinder};
use itertools::Itertools;
use ra_assists::ImportsLocator;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, SyntaxKind::NAME};

pub(crate) struct ImportsLocatorIde<'a> {
    source_binder: SourceBinder<'a, RootDatabase>,
}

impl<'a> ImportsLocatorIde<'a> {
    pub(crate) fn new(db: &'a RootDatabase) -> Self {
        Self { source_binder: SourceBinder::new(db) }
    }

    fn search_for_imports(
        &mut self,
        name_to_import: &ast::NameRef,
        module_with_name_to_import: Module,
    ) -> Vec<ModPath> {
        let _p = profile("search_for_imports");
        let db = self.source_binder.db;
        let name_to_import = name_to_import.text();

        let project_results = {
            let mut query = Query::new(name_to_import.to_string());
            query.exact();
            query.limit(40);
            symbol_index::world_symbols(db, query)
        };
        let lib_results = {
            let mut query = Query::new(name_to_import.to_string());
            query.libs();
            query.exact();
            query.limit(40);
            symbol_index::world_symbols(db, query)
        };

        project_results
            .into_iter()
            .chain(lib_results.into_iter())
            .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate))
            .filter_map(|name_definition_to_import| {
                if let NameKind::Def(module_def) = name_definition_to_import.kind {
                    module_with_name_to_import.find_use_path(db, module_def)
                } else {
                    None
                }
            })
            .filter(|use_path| !use_path.segments.is_empty())
            .unique()
            .take(20)
            .collect()
    }

    fn get_name_definition(
        &mut self,
        db: &impl HirDatabase,
        import_candidate: &FileSymbol,
    ) -> Option<NameDefinition> {
        let _p = profile("get_name_definition");
        let file_id = import_candidate.file_id.into();
        let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
        let candidate_name_node = if candidate_node.kind() != NAME {
            candidate_node.children().find(|it| it.kind() == NAME)?
        } else {
            candidate_node
        };
        classify_name(
            &mut self.source_binder,
            hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
        )
    }
}

impl<'a> ImportsLocator for ImportsLocatorIde<'a> {
    fn find_imports(
        &mut self,
        name_to_import: InFile<&NameRef>,
        module_with_name_to_import: Module,
    ) -> Option<Vec<ModPath>> {
        if classify_name_ref(&mut self.source_binder, name_to_import).is_none() {
            Some(self.search_for_imports(name_to_import.value, module_with_name_to_import))
        } else {
            None
        }
    }
}
<|endoftext|>