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

extern crate rustfmt;
extern crate diff;
extern crate regex;
extern crate term;

use std::collections::HashMap;
use std::fs;
use std::io::{self, Read, BufRead, BufReader};
use std::path::{Path, PathBuf};

use rustfmt::*;
use rustfmt::filemap::{write_system_newlines, FileMap};
use rustfmt::config::{Config, ReportTactic};
use rustfmt::rustfmt_diff::*;

const DIFF_CONTEXT_SIZE: usize = 3;

fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
    let path = dir_entry.expect("Couldn't get DirEntry").path();

    path.to_str().expect("Couldn't stringify path").to_owned()
}

// Integration tests. The files in the tests/source are formatted and compared
// to their equivalent in tests/target. The target file and config can be
// overridden by annotations in the source file. The input and output must match
// exactly.
// FIXME(#28) would be good to check for error messages and fail on them, or at
// least report.
#[test]
fn system_tests() {
    // Get all files in the tests/source directory.
    let files = fs::read_dir("tests/source").expect("Couldn't read source dir");
    // Turn a DirEntry into a String that represents the relative path to the
    // file.
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files);

    // Display results.
    println!("Ran {} system tests.", count);
    assert!(fails == 0, "{} system tests failed", fails);
}

// Do the same for tests/coverage-source directory
// the only difference is the coverage mode
#[test]
fn coverage_tests() {
    let files = fs::read_dir("tests/coverage/source").expect("Couldn't read source dir");
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files);

    println!("Ran {} tests in coverage mode.", count);
    assert!(fails == 0, "{} tests failed", fails);
}

#[test]
fn checkstyle_test() {
    let filename = "tests/writemode/source/fn-single-line.rs";
    let expected_filename = "tests/writemode/target/checkstyle.xml";
    assert_output(filename, expected_filename);
}

// Helper function for comparing the results of rustfmt
// to a known output file generated by one of the write modes.
fn assert_output(source: &str, expected_filename: &str) {
    let config = read_config(&source);
    let (file_map, _report) = format_file(source, &config);

    // Populate output by writing to a vec.
    let mut out = vec![];
    let _ = filemap::write_all_files(&file_map, &mut out, &config);
    let output = String::from_utf8(out).unwrap();

    let mut expected_file = fs::File::open(&expected_filename).expect("Couldn't open target");
    let mut expected_text = String::new();
    expected_file
        .read_to_string(&mut expected_text)
        .expect("Failed reading target");

    let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
    if compare.len() > 0 {
        let mut failures = HashMap::new();
        failures.insert(source.to_string(), compare);
        print_mismatches(failures);
        assert!(false, "Text does not match expected output");
    }
}

// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
#[test]
fn idempotence_tests() {
    // Get all files in the tests/target directory.
    let files = fs::read_dir("tests/target")
        .expect("Couldn't read target dir")
        .map(get_path_string);
    let (_reports, count, fails) = check_files(files);

    // Display results.
    println!("Ran {} idempotent tests.", count);
    assert!(fails == 0, "{} idempotent tests failed", fails);
}

// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
#[test]
fn self_tests() {
    let files = fs::read_dir("src/bin")
        .expect("Couldn't read src dir")
        .chain(fs::read_dir("tests").expect("Couldn't read tests dir"))
        .map(get_path_string);
    // Hack because there's no `IntoIterator` impl for `[T; N]`.
    let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());
    let files = files.chain(Some("build.rs".to_owned()).into_iter());

    let (reports, count, fails) = check_files(files);
    let mut warnings = 0;

    // Display results.
    println!("Ran {} self tests.", count);
    assert!(fails == 0, "{} self tests failed", fails);

    for format_report in reports {
        println!("{}", format_report);
        warnings += format_report.warning_count();
    }

    assert!(warnings == 0,
            "Rustfmt's code generated {} warnings",
            warnings);
}

#[test]
fn stdin_formatting_smoke_test() {
    let input = Input::Text("fn main () {}".to_owned());
    let config = Config::default();
    let (error_summary, file_map, _report) = format_input::<io::Stdout>(input, &config, None)
        .unwrap();
    assert!(error_summary.has_no_errors());
    for &(ref file_name, ref text) in &file_map {
        if file_name == "stdin" {
            assert!(text.to_string() == "fn main() {}\n");
            return;
        }
    }
    panic!("no stdin");
}

#[test]
fn format_lines_errors_are_reported() {
    let long_identifier = String::from_utf8(vec![b'a'; 239]).unwrap();
    let input = Input::Text(format!("fn {}() {{}}", long_identifier));
    let config = Config::default();
    let (error_summary, _file_map, _report) = format_input::<io::Stdout>(input, &config, None)
        .unwrap();
    assert!(error_summary.has_formatting_errors());
}

// For each file, run rustfmt and collect the output.
// Returns the number of files checked and the number of failures.
fn check_files<I>(files: I) -> (Vec<FormatReport>, u32, u32)
    where I: Iterator<Item = String>
{
    let mut count = 0;
    let mut fails = 0;
    let mut reports = vec![];

    for file_name in files.filter(|f| f.ends_with(".rs")) {
        println!("Testing '{}'...", file_name);

        match idempotent_check(file_name) {
            Ok(ref report) if report.has_warnings() => {
                print!("{}", report);
                fails += 1;
            }
            Ok(report) => reports.push(report),
            Err(msg) => {
                print_mismatches(msg);
                fails += 1;
            }
        }

        count += 1;
    }

    (reports, count, fails)
}

fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
    let mut t = term::stdout().unwrap();

    for (file_name, diff) in result {
        print_diff(diff,
                   |line_num| format!("\nMismatch at {}:{}:", file_name, line_num));
    }

    t.reset().unwrap();
}

fn read_config(filename: &str) -> Config {
    let sig_comments = read_significant_comments(&filename);
    // Look for a config file... If there is a 'config' property in the significant comments, use
    // that. Otherwise, if there are no significant comments at all, look for a config file with
    // the same name as the test file.
    let mut config = if !sig_comments.is_empty() {
        get_config(sig_comments.get("config").map(|x| &(*x)[..]))
    } else {
        get_config(Path::new(filename)
                       .with_extension("toml")
                       .file_name()
                       .and_then(std::ffi::OsStr::to_str))
    };

    for (key, val) in &sig_comments {
        if key != "target" && key != "config" {
            config.override_value(key, val);
        }
    }

    // Don't generate warnings for to-do items.
    config.report_todo = ReportTactic::Never;

    config
}

fn format_file<P: Into<PathBuf>>(filename: P, config: &Config) -> (FileMap, FormatReport) {
    let input = Input::File(filename.into());
    let (_error_summary, file_map, report) = format_input::<io::Stdout>(input, &config, None)
        .unwrap();
    return (file_map, report);
}

pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
    let sig_comments = read_significant_comments(&filename);
    let config = read_config(&filename);
    let (file_map, format_report) = format_file(filename, &config);

    let mut write_result = HashMap::new();
    for &(ref filename, ref text) in &file_map {
        let mut v = Vec::new();
        // Won't panic, as we're not doing any IO.
        write_system_newlines(&mut v, text, &config).unwrap();
        // Won't panic, we are writing correct utf8.
        let one_result = String::from_utf8(v).unwrap();
        write_result.insert(filename.clone(), one_result);
    }

    let target = sig_comments.get("target").map(|x| &(*x)[..]);

    handle_result(write_result, target).map(|_| format_report)
}

// Reads test config file using the supplied (optional) file name. If there's no file name or the
// file doesn't exist, just return the default config. Otherwise, the file must be read
// successfully.
fn get_config(config_file: Option<&str>) -> Config {
    let config_file_name = match config_file {
        None => return Default::default(),
        Some(file_name) => {
            let mut full_path = "tests/config/".to_owned();
            full_path.push_str(&file_name);
            if !Path::new(&full_path).exists() {
                return Default::default();
            };
            full_path
        }
    };

    let mut def_config_file = fs::File::open(config_file_name).expect("Couldn't open config");
    let mut def_config = String::new();
    def_config_file
        .read_to_string(&mut def_config)
        .expect("Couldn't read config");

    Config::from_toml(&def_config).expect("Invalid toml")
}

// Reads significant comments of the form: // rustfmt-key: value
// into a hash map.
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
    let file = fs::File::open(file_name).expect(&format!("Couldn't read file {}", file_name));
    let reader = BufReader::new(file);
    let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
    let regex = regex::Regex::new(&pattern).expect("Failed creating pattern 1");

    // Matches lines containing significant comments or whitespace.
    let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
        .expect("Failed creating pattern 2");

    reader
        .lines()
        .map(|line| line.expect("Failed getting line"))
        .take_while(|line| line_regex.is_match(&line))
        .filter_map(|line| {
            regex
                .captures_iter(&line)
                .next()
                .map(|capture| {
                    (capture
                         .get(1)
                         .expect("Couldn't unwrap capture")
                         .as_str()
                         .to_owned(),
                     capture
                         .get(2)
                         .expect("Couldn't unwrap capture")
                         .as_str()
                         .to_owned())
                })
        })
        .collect()
}

// Compare output to input.
// TODO: needs a better name, more explanation.
fn handle_result(result: HashMap<String, String>,
                 target: Option<&str>)
                 -> Result<(), HashMap<String, Vec<Mismatch>>> {
    let mut failures = HashMap::new();

    for (file_name, fmt_text) in result {
        // If file is in tests/source, compare to file with same name in tests/target.
        let target = get_target(&file_name, target);
        let mut f = fs::File::open(&target).expect("Couldn't open target");

        let mut text = String::new();
        f.read_to_string(&mut text).expect("Failed reading target");

        if fmt_text != text {
            let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
            assert!(!diff.is_empty(),
                    "Empty diff? Maybe due to a missing a newline at the end of a file?");
            failures.insert(file_name, diff);
        }
    }

    if failures.is_empty() {
        Ok(())
    } else {
        Err(failures)
    }
}

// Map source file paths to their target paths.
fn get_target(file_name: &str, target: Option<&str>) -> String {
    if file_name.contains("source") {
        let target_file_name = file_name.replace("source", "target");
        if let Some(replace_name) = target {
            Path::new(&target_file_name)
                .with_file_name(replace_name)
                .into_os_string()
                .into_string()
                .unwrap()
        } else {
            target_file_name
        }
    } else {
        // This is either and idempotence check or a self check
        file_name.to_owned()
    }
}

#[test]
fn rustfmt_diff_make_diff_tests() {
    let diff = make_diff("a\nb\nc\nd", "a\ne\nc\nd", 3);
    assert_eq!(diff,
               vec![Mismatch {
                        line_number: 1,
                        lines: vec![DiffLine::Context("a".into()),
                                    DiffLine::Resulting("b".into()),
                                    DiffLine::Expected("e".into()),
                                    DiffLine::Context("c".into()),
                                    DiffLine::Context("d".into())],
                    }]);
}

#[test]
fn rustfmt_diff_no_diff_test() {
    let diff = make_diff("a\nb\nc\nd", "a\nb\nc\nd", 3);
    assert_eq!(diff, vec![]);
}
<commit_msg>Improve error message for missing source/target test file<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rustfmt;
extern crate diff;
extern crate regex;
extern crate term;

use std::collections::HashMap;
use std::fs;
use std::io::{self, Read, BufRead, BufReader};
use std::path::{Path, PathBuf};

use rustfmt::*;
use rustfmt::filemap::{write_system_newlines, FileMap};
use rustfmt::config::{Config, ReportTactic};
use rustfmt::rustfmt_diff::*;

const DIFF_CONTEXT_SIZE: usize = 3;

fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
    let path = dir_entry.expect("Couldn't get DirEntry").path();

    path.to_str().expect("Couldn't stringify path").to_owned()
}

// Integration tests. The files in the tests/source are formatted and compared
// to their equivalent in tests/target. The target file and config can be
// overridden by annotations in the source file. The input and output must match
// exactly.
// FIXME(#28) would be good to check for error messages and fail on them, or at
// least report.
#[test]
fn system_tests() {
    // Get all files in the tests/source directory.
    let files = fs::read_dir("tests/source").expect("Couldn't read source dir");
    // Turn a DirEntry into a String that represents the relative path to the
    // file.
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files);

    // Display results.
    println!("Ran {} system tests.", count);
    assert!(fails == 0, "{} system tests failed", fails);
}

// Do the same for tests/coverage-source directory
// the only difference is the coverage mode
#[test]
fn coverage_tests() {
    let files = fs::read_dir("tests/coverage/source").expect("Couldn't read source dir");
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files);

    println!("Ran {} tests in coverage mode.", count);
    assert!(fails == 0, "{} tests failed", fails);
}

#[test]
fn checkstyle_test() {
    let filename = "tests/writemode/source/fn-single-line.rs";
    let expected_filename = "tests/writemode/target/checkstyle.xml";
    assert_output(filename, expected_filename);
}

// Helper function for comparing the results of rustfmt
// to a known output file generated by one of the write modes.
fn assert_output(source: &str, expected_filename: &str) {
    let config = read_config(&source);
    let (file_map, _report) = format_file(source, &config);

    // Populate output by writing to a vec.
    let mut out = vec![];
    let _ = filemap::write_all_files(&file_map, &mut out, &config);
    let output = String::from_utf8(out).unwrap();

    let mut expected_file = fs::File::open(&expected_filename).expect("Couldn't open target");
    let mut expected_text = String::new();
    expected_file
        .read_to_string(&mut expected_text)
        .expect("Failed reading target");

    let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
    if compare.len() > 0 {
        let mut failures = HashMap::new();
        failures.insert(source.to_string(), compare);
        print_mismatches(failures);
        assert!(false, "Text does not match expected output");
    }
}

// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
#[test]
fn idempotence_tests() {
    // Get all files in the tests/target directory.
    let files = fs::read_dir("tests/target")
        .expect("Couldn't read target dir")
        .map(get_path_string);
    let (_reports, count, fails) = check_files(files);

    // Display results.
    println!("Ran {} idempotent tests.", count);
    assert!(fails == 0, "{} idempotent tests failed", fails);
}

// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
#[test]
fn self_tests() {
    let files = fs::read_dir("src/bin")
        .expect("Couldn't read src dir")
        .chain(fs::read_dir("tests").expect("Couldn't read tests dir"))
        .map(get_path_string);
    // Hack because there's no `IntoIterator` impl for `[T; N]`.
    let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());
    let files = files.chain(Some("build.rs".to_owned()).into_iter());

    let (reports, count, fails) = check_files(files);
    let mut warnings = 0;

    // Display results.
    println!("Ran {} self tests.", count);
    assert!(fails == 0, "{} self tests failed", fails);

    for format_report in reports {
        println!("{}", format_report);
        warnings += format_report.warning_count();
    }

    assert!(warnings == 0,
            "Rustfmt's code generated {} warnings",
            warnings);
}

#[test]
fn stdin_formatting_smoke_test() {
    let input = Input::Text("fn main () {}".to_owned());
    let config = Config::default();
    let (error_summary, file_map, _report) = format_input::<io::Stdout>(input, &config, None)
        .unwrap();
    assert!(error_summary.has_no_errors());
    for &(ref file_name, ref text) in &file_map {
        if file_name == "stdin" {
            assert!(text.to_string() == "fn main() {}\n");
            return;
        }
    }
    panic!("no stdin");
}

#[test]
fn format_lines_errors_are_reported() {
    let long_identifier = String::from_utf8(vec![b'a'; 239]).unwrap();
    let input = Input::Text(format!("fn {}() {{}}", long_identifier));
    let config = Config::default();
    let (error_summary, _file_map, _report) = format_input::<io::Stdout>(input, &config, None)
        .unwrap();
    assert!(error_summary.has_formatting_errors());
}

// For each file, run rustfmt and collect the output.
// Returns the number of files checked and the number of failures.
fn check_files<I>(files: I) -> (Vec<FormatReport>, u32, u32)
    where I: Iterator<Item = String>
{
    let mut count = 0;
    let mut fails = 0;
    let mut reports = vec![];

    for file_name in files.filter(|f| f.ends_with(".rs")) {
        println!("Testing '{}'...", file_name);

        match idempotent_check(file_name) {
            Ok(ref report) if report.has_warnings() => {
                print!("{}", report);
                fails += 1;
            }
            Ok(report) => reports.push(report),
            Err(msg) => {
                print_mismatches(msg);
                fails += 1;
            }
        }

        count += 1;
    }

    (reports, count, fails)
}

fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
    let mut t = term::stdout().unwrap();

    for (file_name, diff) in result {
        print_diff(diff,
                   |line_num| format!("\nMismatch at {}:{}:", file_name, line_num));
    }

    t.reset().unwrap();
}

fn read_config(filename: &str) -> Config {
    let sig_comments = read_significant_comments(&filename);
    // Look for a config file... If there is a 'config' property in the significant comments, use
    // that. Otherwise, if there are no significant comments at all, look for a config file with
    // the same name as the test file.
    let mut config = if !sig_comments.is_empty() {
        get_config(sig_comments.get("config").map(|x| &(*x)[..]))
    } else {
        get_config(Path::new(filename)
                       .with_extension("toml")
                       .file_name()
                       .and_then(std::ffi::OsStr::to_str))
    };

    for (key, val) in &sig_comments {
        if key != "target" && key != "config" {
            config.override_value(key, val);
        }
    }

    // Don't generate warnings for to-do items.
    config.report_todo = ReportTactic::Never;

    config
}

fn format_file<P: Into<PathBuf>>(filename: P, config: &Config) -> (FileMap, FormatReport) {
    let input = Input::File(filename.into());
    let (_error_summary, file_map, report) = format_input::<io::Stdout>(input, &config, None)
        .unwrap();
    return (file_map, report);
}

pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
    let sig_comments = read_significant_comments(&filename);
    let config = read_config(&filename);
    let (file_map, format_report) = format_file(filename, &config);

    let mut write_result = HashMap::new();
    for &(ref filename, ref text) in &file_map {
        let mut v = Vec::new();
        // Won't panic, as we're not doing any IO.
        write_system_newlines(&mut v, text, &config).unwrap();
        // Won't panic, we are writing correct utf8.
        let one_result = String::from_utf8(v).unwrap();
        write_result.insert(filename.clone(), one_result);
    }

    let target = sig_comments.get("target").map(|x| &(*x)[..]);

    handle_result(write_result, target).map(|_| format_report)
}

// Reads test config file using the supplied (optional) file name. If there's no file name or the
// file doesn't exist, just return the default config. Otherwise, the file must be read
// successfully.
fn get_config(config_file: Option<&str>) -> Config {
    let config_file_name = match config_file {
        None => return Default::default(),
        Some(file_name) => {
            let mut full_path = "tests/config/".to_owned();
            full_path.push_str(&file_name);
            if !Path::new(&full_path).exists() {
                return Default::default();
            };
            full_path
        }
    };

    let mut def_config_file = fs::File::open(config_file_name).expect("Couldn't open config");
    let mut def_config = String::new();
    def_config_file
        .read_to_string(&mut def_config)
        .expect("Couldn't read config");

    Config::from_toml(&def_config).expect("Invalid toml")
}

// Reads significant comments of the form: // rustfmt-key: value
// into a hash map.
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
    let file = fs::File::open(file_name).expect(&format!("Couldn't read file {}", file_name));
    let reader = BufReader::new(file);
    let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
    let regex = regex::Regex::new(&pattern).expect("Failed creating pattern 1");

    // Matches lines containing significant comments or whitespace.
    let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
        .expect("Failed creating pattern 2");

    reader
        .lines()
        .map(|line| line.expect("Failed getting line"))
        .take_while(|line| line_regex.is_match(&line))
        .filter_map(|line| {
            regex
                .captures_iter(&line)
                .next()
                .map(|capture| {
                    (capture
                         .get(1)
                         .expect("Couldn't unwrap capture")
                         .as_str()
                         .to_owned(),
                     capture
                         .get(2)
                         .expect("Couldn't unwrap capture")
                         .as_str()
                         .to_owned())
                })
        })
        .collect()
}

// Compare output to input.
// TODO: needs a better name, more explanation.
fn handle_result(result: HashMap<String, String>,
                 target: Option<&str>)
                 -> Result<(), HashMap<String, Vec<Mismatch>>> {
    let mut failures = HashMap::new();

    for (file_name, fmt_text) in result {
        // If file is in tests/source, compare to file with same name in tests/target.
        let target = get_target(&file_name, target);
        let open_error = format!("Couldn't open target {:?}", &target);
        let mut f = fs::File::open(&target).expect(&open_error);

        let mut text = String::new();
        let read_error = format!("Failed reading target {:?}", &target);
        f.read_to_string(&mut text).expect(&read_error);

        if fmt_text != text {
            let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
            assert!(!diff.is_empty(),
                    "Empty diff? Maybe due to a missing a newline at the end of a file?");
            failures.insert(file_name, diff);
        }
    }

    if failures.is_empty() {
        Ok(())
    } else {
        Err(failures)
    }
}

// Map source file paths to their target paths.
fn get_target(file_name: &str, target: Option<&str>) -> String {
    if file_name.contains("source") {
        let target_file_name = file_name.replace("source", "target");
        if let Some(replace_name) = target {
            Path::new(&target_file_name)
                .with_file_name(replace_name)
                .into_os_string()
                .into_string()
                .unwrap()
        } else {
            target_file_name
        }
    } else {
        // This is either and idempotence check or a self check
        file_name.to_owned()
    }
}

#[test]
fn rustfmt_diff_make_diff_tests() {
    let diff = make_diff("a\nb\nc\nd", "a\ne\nc\nd", 3);
    assert_eq!(diff,
               vec![Mismatch {
                        line_number: 1,
                        lines: vec![DiffLine::Context("a".into()),
                                    DiffLine::Resulting("b".into()),
                                    DiffLine::Expected("e".into()),
                                    DiffLine::Context("c".into()),
                                    DiffLine::Context("d".into())],
                    }]);
}

#[test]
fn rustfmt_diff_no_diff_test() {
    let diff = make_diff("a\nb\nc\nd", "a\nb\nc\nd", 3);
    assert_eq!(diff, vec![]);
}
<|endoftext|>


<commit_before>use super::methods::{HelloMessage, RPCMethod, RPCRequest, RPCResponse};
use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use ssz::{ssz_encode, Decodable, Encodable, SszStream};
use std::io;
use std::iter;
use tokio::io::{AsyncRead, AsyncWrite};

/// The maximum bytes that can be sent across the RPC.
const MAX_READ_SIZE: usize = 4_194_304; // 4M

/// Implementation of the `ConnectionUpgrade` for the rpc protocol.

#[derive(Debug, Clone)]
pub struct RPCProtocol;

impl UpgradeInfo for RPCProtocol {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

impl Default for RPCProtocol {
    fn default() -> Self {
        RPCProtocol
    }
}

/// The RPC types which are sent/received in this protocol.
#[derive(Debug, Clone)]
pub enum RPCEvent {
    Request {
        id: u64,
        method_id: u16,
        body: RPCRequest,
    },
    Response {
        id: u64,
        method_id: u16, //TODO: Remove and process decoding upstream
        result: RPCResponse,
    },
}

impl UpgradeInfo for RPCEvent {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

impl<TSocket> InboundUpgrade<TSocket> for RPCProtocol
where
    TSocket: AsyncRead + AsyncWrite,
{
    type Output = RPCEvent;
    type Error = DecodeError;
    type Future =
        upgrade::ReadOneThen<TSocket, (), fn(Vec<u8>, ()) -> Result<RPCEvent, DecodeError>>;

    fn upgrade_inbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?))
    }
}

fn decode(packet: Vec<u8>) -> Result<RPCEvent, DecodeError> {
    // decode the header of the rpc
    // request/response
    let (request, index) = bool::ssz_decode(&packet, 0)?;
    let (id, index) = u64::ssz_decode(&packet, index)?;
    let (method_id, index) = u16::ssz_decode(&packet, index)?;

    if request {
        let body = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCRequest::Hello(hello_body)
            }
            RPCMethod::Goodbye => {
                let (goodbye_code, _index) = u64::ssz_decode(&packet, index)?;
                RPCRequest::Goodbye(goodbye_code)
            }
            RPCMethod::Unknown | _ => return Err(DecodeError::UnknownRPCMethod),
        };

        Ok(RPCEvent::Request {
            id,
            method_id,
            body,
        })
    }
    // we have received a response
    else {
        let result = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCResponse::Hello(body)
            }
            RPCMethod::Unknown | _ => return Err(DecodeError::UnknownRPCMethod),
        };
        Ok(RPCEvent::Response {
            id,
            method_id,
            result,
        })
    }
}

impl<TSocket> OutboundUpgrade<TSocket> for RPCEvent
where
    TSocket: AsyncWrite,
{
    type Output = ();
    type Error = io::Error;
    type Future = upgrade::WriteOne<TSocket>;

    #[inline]
    fn upgrade_outbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        let bytes = ssz_encode(&self);
        upgrade::write_one(socket, bytes)
    }
}

impl Encodable for RPCEvent {
    fn ssz_append(&self, s: &mut SszStream) {
        match self {
            RPCEvent::Request {
                id,
                method_id,
                body,
            } => {
                s.append(&true);
                s.append(id);
                s.append(method_id);
                match body {
                    RPCRequest::Hello(body) => {
                        s.append(body);
                    }
                    _ => {}
                }
            }
            RPCEvent::Response {
                id,
                method_id,
                result,
            } => {
                s.append(&false);
                s.append(id);
                s.append(method_id);
                match result {
                    RPCResponse::Hello(response) => {
                        s.append(response);
                    }
                    _ => {}
                }
            }
        }
    }
}

#[derive(Debug)]
pub enum DecodeError {
    ReadError(upgrade::ReadOneError),
    SSZDecodeError(ssz::DecodeError),
    UnknownRPCMethod,
}

impl From<upgrade::ReadOneError> for DecodeError {
    #[inline]
    fn from(err: upgrade::ReadOneError) -> Self {
        DecodeError::ReadError(err)
    }
}

impl From<ssz::DecodeError> for DecodeError {
    #[inline]
    fn from(err: ssz::DecodeError) -> Self {
        DecodeError::SSZDecodeError(err)
    }
}
<commit_msg>Implement BeaconBlockRoots RPC method<commit_after>use super::methods::*;
use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use ssz::{ssz_encode, Decodable, Encodable, SszStream};
use std::io;
use std::iter;
use tokio::io::{AsyncRead, AsyncWrite};

/// The maximum bytes that can be sent across the RPC.
const MAX_READ_SIZE: usize = 4_194_304; // 4M

/// Implementation of the `ConnectionUpgrade` for the rpc protocol.

#[derive(Debug, Clone)]
pub struct RPCProtocol;

impl UpgradeInfo for RPCProtocol {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

impl Default for RPCProtocol {
    fn default() -> Self {
        RPCProtocol
    }
}

/// The RPC types which are sent/received in this protocol.
#[derive(Debug, Clone)]
pub enum RPCEvent {
    Request {
        id: u64,
        method_id: u16,
        body: RPCRequest,
    },
    Response {
        id: u64,
        method_id: u16, //TODO: Remove and process decoding upstream
        result: RPCResponse,
    },
}

impl UpgradeInfo for RPCEvent {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

impl<TSocket> InboundUpgrade<TSocket> for RPCProtocol
where
    TSocket: AsyncRead + AsyncWrite,
{
    type Output = RPCEvent;
    type Error = DecodeError;
    type Future =
        upgrade::ReadOneThen<TSocket, (), fn(Vec<u8>, ()) -> Result<RPCEvent, DecodeError>>;

    fn upgrade_inbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?))
    }
}

fn decode(packet: Vec<u8>) -> Result<RPCEvent, DecodeError> {
    // decode the header of the rpc
    // request/response
    let (request, index) = bool::ssz_decode(&packet, 0)?;
    let (id, index) = u64::ssz_decode(&packet, index)?;
    let (method_id, index) = u16::ssz_decode(&packet, index)?;

    if request {
        let body = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCRequest::Hello(hello_body)
            }
            RPCMethod::Goodbye => {
                let (goodbye_code, _index) = u64::ssz_decode(&packet, index)?;
                RPCRequest::Goodbye(goodbye_code)
            }
            RPCMethod::BeaconBlockRoots => {
                let (block_roots_request, _index) =
                    BeaconBlockRootsRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockRoots(block_roots_request)
            }
            RPCMethod::Unknown | _ => return Err(DecodeError::UnknownRPCMethod),
        };

        Ok(RPCEvent::Request {
            id,
            method_id,
            body,
        })
    }
    // we have received a response
    else {
        let result = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCResponse::Hello(body)
            }
            RPCMethod::Goodbye => unreachable!("Should never receive a goodbye response"),
            RPCMethod::BeaconBlockRoots => {
                let (body, _index) = BeaconBlockRootsResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockRoots(body)
            }
            RPCMethod::Unknown | _ => return Err(DecodeError::UnknownRPCMethod),
        };
        Ok(RPCEvent::Response {
            id,
            method_id,
            result,
        })
    }
}

impl<TSocket> OutboundUpgrade<TSocket> for RPCEvent
where
    TSocket: AsyncWrite,
{
    type Output = ();
    type Error = io::Error;
    type Future = upgrade::WriteOne<TSocket>;

    #[inline]
    fn upgrade_outbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        let bytes = ssz_encode(&self);
        upgrade::write_one(socket, bytes)
    }
}

impl Encodable for RPCEvent {
    fn ssz_append(&self, s: &mut SszStream) {
        match self {
            RPCEvent::Request {
                id,
                method_id,
                body,
            } => {
                s.append(&true);
                s.append(id);
                s.append(method_id);
                match body {
                    RPCRequest::Hello(body) => {
                        s.append(body);
                    }
                    _ => {}
                }
            }
            RPCEvent::Response {
                id,
                method_id,
                result,
            } => {
                s.append(&false);
                s.append(id);
                s.append(method_id);
                match result {
                    RPCResponse::Hello(response) => {
                        s.append(response);
                    }
                    _ => {}
                }
            }
        }
    }
}

#[derive(Debug)]
pub enum DecodeError {
    ReadError(upgrade::ReadOneError),
    SSZDecodeError(ssz::DecodeError),
    UnknownRPCMethod,
}

impl From<upgrade::ReadOneError> for DecodeError {
    #[inline]
    fn from(err: upgrade::ReadOneError) -> Self {
        DecodeError::ReadError(err)
    }
}

impl From<ssz::DecodeError> for DecodeError {
    #[inline]
    fn from(err: ssz::DecodeError) -> Self {
        DecodeError::SSZDecodeError(err)
    }
}
<|endoftext|>


<commit_before>const ARRAY_MAX: usize = 25_000;
const LUDIC_MAX: usize = 2100;

#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
fn main() {
    // Vector that will hold all the ludic numbers
    let mut result: Vec<usize> = vec![];

    // Array that will hold the first array with 25.000 numbers starting with number 2
    let mut array = (2..(ARRAY_MAX + 2)).collect::<Vec<_>>();

    // Calculate LUDIC_MAX Ludic numbers
    // First Ludic numbers is '1'
    result.push(1);

    for _ in 0..LUDIC_MAX {
        let next_ludic = array[0];
        result.push(next_ludic);
        let mut counter = 0;
        for i in 0..array.len() {
            // modulo operation:
            // ((a % b) + b) % b
            let modulo = ((i as usize % next_ludic) + next_ludic) % next_ludic;

            if modulo != 0 {
                array[counter] = array[i];
                counter += 1;
            }
        }
    }

    print!("First 25: ");
    print_n_ludics(&result, 25);
    println!();
    print!("Number of Ludics below 1000: ");
    print_num_ludics_upto(&result, 1000);
    println!();
    print!("Ludics from 2000 to 2005: ");
    print_ludics_from_to(&result, 2000, 2005);
    println!();
    println!("Triplets below 250: ");
    print_tiples_until(&result, 250);
}

/// Prints the first `n` Ludic numbers
fn print_n_ludics(x: &[usize], n: usize) {
    for i in x.iter().take(n) {
        print!("{} ", i);
    }
    println!();
}

/// Calculates how many Ludic numbers are below `max_num`
fn print_num_ludics_upto(x: &[usize], max_num: usize) {
    let mut num: i32 = 0;
    for i in x.iter() {
        if *i < max_num {
            num += 1;
        }
    }
    println!("{}", num);
}

/// Prints Ludic numbers between two numbers
fn print_ludics_from_to(x: &[usize], from: usize, to: usize) {
    for i in x.iter().take(to - 1).skip(from - 1) {
        print!("{} ", i);
    }
    println!();
}

/// Calculates triplets until a certain Ludic number
fn print_tiples_until(x: &[usize], limit: usize) {
    let mut counter: usize = 0;

    while x[counter] < limit {
        let triplet2 = x[counter] + 2;
        let triplet3 = x[counter] + 6;

        let res_triplet2 = x.binary_search(&triplet2);
        let res_triplet3 = x.binary_search(&triplet3);

        if res_triplet2.is_ok() && res_triplet3.is_ok() {
            println!("{} {} {}", x[counter], triplet2, triplet3);
        }
        counter += 1;
    }
}
<commit_msg>refactor Ludic Numbers<commit_after>#![feature(iterator_step_by)] // for `step_by`

const ARRAY_MAX: usize = 25_000;
const LUDIC_MAX: usize = 2100;

/// Calculates and returns the first `LUDIC_MAX` Ludic numbers.
///
/// Needs a sufficiently large `ARRAY_MAX`.
fn ludic_numbers() -> Vec<usize> {
    // The first two Ludic numbers
    let mut numbers = vec![1, 2];
    // We start the array with an immediate first removal to reduce memory usage by collecting
    // only odd numbers.
    numbers.extend((3..ARRAY_MAX).step_by(2));

    // We keep the correct Ludic numbers in place, removing the incorrect ones.
    for ludic_idx in 2..LUDIC_MAX {
        let next_ludic = numbers[ludic_idx];

        // We remove incorrect numbers by counting the indices after the correct numbers.  We
        // start from zero and keep until we reach the potentially incorrect numbers.  Then we
        // keep only those not divisible by the `next_ludic`.
        let mut idx = 0;
        numbers.retain(|_| {
            let keep = idx <= ludic_idx || (idx - ludic_idx) % next_ludic != 0;
            idx += 1;
            keep
        });
    }

    numbers
}

fn main() {
    let ludic_numbers = ludic_numbers();

    print!("First 25: ");
    print_n_ludics(&ludic_numbers, 25);
    println!();
    print!("Number of Ludics below 1000: ");
    print_num_ludics_upto(&ludic_numbers, 1000);
    println!();
    print!("Ludics from 2000 to 2005: ");
    print_ludics_from_to(&ludic_numbers, 2000, 2005);
    println!();
    println!("Triplets below 250: ");
    print_triplets_until(&ludic_numbers, 250);
}

/// Prints the first `n` Ludic numbers.
fn print_n_ludics(x: &[usize], n: usize) {
    println!("{:?}", &x[..n]);
}

/// Calculates how many Ludic numbers are below `max_num`.
fn print_num_ludics_upto(x: &[usize], max_num: usize) {
    let num = x.iter().take_while(|&&i| i < max_num).count();
    println!("{}", num);
}

/// Prints Ludic numbers between two numbers.
fn print_ludics_from_to(x: &[usize], from: usize, to: usize) {
    println!("{:?}", &x[from - 1..to - 1]);
}

/// Calculates the triplet of a Ludic number.
fn triplets_below(ludics: &[usize], limit: usize) -> Vec<(usize, usize, usize)> {
    ludics
        .iter()
        .enumerate()
        .take_while(|&(_, &num)| num < limit)
        .filter_map(|(idx, &number)| {
            let triplet_2 = number + 2;
            let triplet_3 = number + 6;

            // Search for the other two triplet numbers.  We know they are larger than `number` so
            // we can give the searches lower bounds of `idx + 1` and `idx + 2`.  We also know that
            // the `n + 2` number can only ever be two numbers away from the previous and the `n + 6`
            // number can only be four away (because we removed some in between).  Short circuiting
            // and doing the check more likely to fail first are also useful.
            let is_triplet = ludics[idx + 1..idx + 3].binary_search(&triplet_2).is_ok()
                && ludics[idx + 2..idx + 5].binary_search(&triplet_3).is_ok();

            if is_triplet {
                Some((number, triplet_2, triplet_3))
            } else {
                None
            }
        })
        .collect()
}

/// Prints triplets until a certain Ludic number.
fn print_triplets_until(ludics: &[usize], limit: usize) {
    for (number, triplet_2, triplet_3) in triplets_below(ludics, limit) {
        println!("{} {} {}", number, triplet_2, triplet_3);
    }
}

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

    #[test]
    fn solutions() {
        let ludics = ludic_numbers();

        // First 25
        let first_25 = [
            1, 2, 3, 5, 7, 11, 13, 17, 23, 25, 29, 37, 41, 43, 47, 53, 61, 67, 71, 77, 83, 89, 91,
            97, 107,
        ];
        assert_eq!(ludics[..25], first_25);

        // Count below 1000
        assert_eq!(ludics.iter().take_while(|&&i| i < 1000).count(), 142);

        // 2000th to 2005th numbers
        let expected_range = [21475, 21481, 21487, 21493, 21503];
        assert_eq!(ludics[2000 - 1..2005 - 1], expected_range);

        // Triplets
        let expected_triplets = [
            (1, 3, 7),
            (5, 7, 11),
            (11, 13, 17),
            (23, 25, 29),
            (41, 43, 47),
            (173, 175, 179),
            (221, 223, 227),
            (233, 235, 239),
        ];
        let tested_triplets = triplets_below(&ludics, 250);
        assert_eq!(expected_triplets, tested_triplets.as_slice());
    }
}
<|endoftext|>


<commit_before><commit_msg>fix(cli): Improve error messages on config.json loading, closes #1227<commit_after><|endoftext|>


<commit_before>use std::error::Error;
use std::path::{Path, PathBuf};
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};

/// List of directories containing files to expand. The first tuple element is the source
/// directory, while the second tuple element is the destination directory.
#[rustfmt::skip]
static TO_EXPAND: &[(&str, &str)] = &[
    ("src/ci/github-actions", ".github/workflows"),
];

/// Name of a special key that will be removed from all the maps in expanded configuration files.
/// This key can then be used to contain shared anchors.
static REMOVE_MAP_KEY: &str = "x--expand-yaml-anchors--remove";

/// Message that will be included at the top of all the expanded files. {source} will be replaced
/// with the source filename relative to the base path.
static HEADER_MESSAGE: &str = "\
#############################################################
#   WARNING: automatically generated file, DO NOT CHANGE!   #
#############################################################

# This file was automatically generated by the expand-yaml-anchors tool. The
# source file that generated this one is:
#
#   {source}
#
# Once you make changes to that file you need to run:
#
#   ./x.py run src/tools/expand-yaml-anchors/
#
# The CI build will fail if the tool is not run after changes to this file.

";

enum Mode {
    Check,
    Generate,
}

struct App {
    mode: Mode,
    base: PathBuf,
}

impl App {
    fn from_args() -> Result<Self, Box<dyn Error>> {
        // Parse CLI arguments
        let args = std::env::args().skip(1).collect::<Vec<_>>();
        let (mode, base) = match args.iter().map(|s| s.as_str()).collect::<Vec<_>>().as_slice() {
            ["generate", ref base] => (Mode::Generate, PathBuf::from(base)),
            ["check", ref base] => (Mode::Check, PathBuf::from(base)),
            _ => {
                eprintln!("usage: expand-yaml-anchors <source-dir> <dest-dir>");
                std::process::exit(1);
            }
        };

        Ok(App { mode, base })
    }

    fn run(&self) -> Result<(), Box<dyn Error>> {
        for (source, dest) in TO_EXPAND {
            let source = self.base.join(source);
            let dest = self.base.join(dest);
            for entry in std::fs::read_dir(&source)? {
                let path = entry?.path();
                if !path.is_file() || path.extension().and_then(|e| e.to_str()) != Some("yml") {
                    continue;
                }

                let dest_path = dest.join(path.file_name().unwrap());
                self.expand(&path, &dest_path).with_context(|| match self.mode {
                    Mode::Generate => format!(
                        "failed to expand {} into {}",
                        self.path(&path),
                        self.path(&dest_path)
                    ),
                    Mode::Check => format!("{} is not up to date", self.path(&dest_path)),
                })?;
            }
        }
        Ok(())
    }

    fn expand(&self, source: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
        let content = std::fs::read_to_string(source)
            .with_context(|| format!("failed to read {}", self.path(source)))?;

        let mut buf =
            HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/"));

        let documents = YamlLoader::load_from_str(&content)
            .with_context(|| format!("failed to parse {}", self.path(source)))?;
        for mut document in documents.into_iter() {
            document = yaml_merge_keys::merge_keys(document)
                .with_context(|| format!("failed to expand {}", self.path(source)))?;
            document = filter_document(document);

            YamlEmitter::new(&mut buf).dump(&document).map_err(|err| WithContext {
                context: "failed to serialize the expanded yaml".into(),
                source: Box::new(err),
            })?;
            buf.push('\n');
        }

        match self.mode {
            Mode::Check => {
                let old = std::fs::read_to_string(dest)
                    .with_context(|| format!("failed to read {}", self.path(dest)))?;
                if old != buf {
                    return Err(Box::new(StrError(format!(
                        "{} and {} are different",
                        self.path(source),
                        self.path(dest),
                    ))));
                }
            }
            Mode::Generate => {
                std::fs::write(dest, buf.as_bytes())
                    .with_context(|| format!("failed to write to {}", self.path(dest)))?;
            }
        }
        Ok(())
    }

    fn path<'a>(&self, path: &'a Path) -> impl std::fmt::Display + 'a {
        path.strip_prefix(&self.base).unwrap_or(path).display()
    }
}

fn filter_document(document: Yaml) -> Yaml {
    match document {
        Yaml::Hash(map) => Yaml::Hash(
            map.into_iter()
                .filter(|(key, _)| {
                    if let Yaml::String(string) = &key { string != REMOVE_MAP_KEY } else { true }
                })
                .map(|(key, value)| (filter_document(key), filter_document(value)))
                .collect(),
        ),
        Yaml::Array(vec) => Yaml::Array(vec.into_iter().map(filter_document).collect()),
        other => other,
    }
}

fn main() {
    if let Err(err) = App::from_args().and_then(|app| app.run()) {
        eprintln!("error: {}", err);

        let mut source = err.as_ref() as &dyn Error;
        while let Some(err) = source.source() {
            eprintln!("caused by: {}", err);
            source = err;
        }

        std::process::exit(1);
    }
}

#[derive(Debug)]
struct StrError(String);

impl Error for StrError {}

impl std::fmt::Display for StrError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&self.0, f)
    }
}

#[derive(Debug)]
struct WithContext {
    context: String,
    source: Box<dyn Error>,
}

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

impl Error for WithContext {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(self.source.as_ref())
    }
}

pub(crate) trait ResultExt<T> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>>;
}

impl<T, E: Into<Box<dyn Error>>> ResultExt<T> for Result<T, E> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>> {
        match self {
            Ok(ok) => Ok(ok),
            Err(err) => Err(WithContext { source: err.into(), context: f() }.into()),
        }
    }
}
<commit_msg>Rollup merge of #82013 - Mark-Simulacrum:better-ci-error, r=jyn514<commit_after>use std::error::Error;
use std::path::{Path, PathBuf};
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};

/// List of directories containing files to expand. The first tuple element is the source
/// directory, while the second tuple element is the destination directory.
#[rustfmt::skip]
static TO_EXPAND: &[(&str, &str)] = &[
    ("src/ci/github-actions", ".github/workflows"),
];

/// Name of a special key that will be removed from all the maps in expanded configuration files.
/// This key can then be used to contain shared anchors.
static REMOVE_MAP_KEY: &str = "x--expand-yaml-anchors--remove";

/// Message that will be included at the top of all the expanded files. {source} will be replaced
/// with the source filename relative to the base path.
static HEADER_MESSAGE: &str = "\
#############################################################
#   WARNING: automatically generated file, DO NOT CHANGE!   #
#############################################################

# This file was automatically generated by the expand-yaml-anchors tool. The
# source file that generated this one is:
#
#   {source}
#
# Once you make changes to that file you need to run:
#
#   ./x.py run src/tools/expand-yaml-anchors/
#
# The CI build will fail if the tool is not run after changes to this file.

";

enum Mode {
    Check,
    Generate,
}

struct App {
    mode: Mode,
    base: PathBuf,
}

impl App {
    fn from_args() -> Result<Self, Box<dyn Error>> {
        // Parse CLI arguments
        let args = std::env::args().skip(1).collect::<Vec<_>>();
        let (mode, base) = match args.iter().map(|s| s.as_str()).collect::<Vec<_>>().as_slice() {
            ["generate", ref base] => (Mode::Generate, PathBuf::from(base)),
            ["check", ref base] => (Mode::Check, PathBuf::from(base)),
            _ => {
                eprintln!("usage: expand-yaml-anchors <source-dir> <dest-dir>");
                std::process::exit(1);
            }
        };

        Ok(App { mode, base })
    }

    fn run(&self) -> Result<(), Box<dyn Error>> {
        for (source, dest) in TO_EXPAND {
            let source = self.base.join(source);
            let dest = self.base.join(dest);
            for entry in std::fs::read_dir(&source)? {
                let path = entry?.path();
                if !path.is_file() || path.extension().and_then(|e| e.to_str()) != Some("yml") {
                    continue;
                }

                let dest_path = dest.join(path.file_name().unwrap());
                self.expand(&path, &dest_path).with_context(|| match self.mode {
                    Mode::Generate => format!(
                        "failed to expand {} into {}",
                        self.path(&path),
                        self.path(&dest_path)
                    ),
                    Mode::Check => format!(
                        "{} is not up to date; please run \
                        `x.py run src/tools/expand-yaml-anchors`.",
                        self.path(&dest_path)
                    ),
                })?;
            }
        }
        Ok(())
    }

    fn expand(&self, source: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
        let content = std::fs::read_to_string(source)
            .with_context(|| format!("failed to read {}", self.path(source)))?;

        let mut buf =
            HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/"));

        let documents = YamlLoader::load_from_str(&content)
            .with_context(|| format!("failed to parse {}", self.path(source)))?;
        for mut document in documents.into_iter() {
            document = yaml_merge_keys::merge_keys(document)
                .with_context(|| format!("failed to expand {}", self.path(source)))?;
            document = filter_document(document);

            YamlEmitter::new(&mut buf).dump(&document).map_err(|err| WithContext {
                context: "failed to serialize the expanded yaml".into(),
                source: Box::new(err),
            })?;
            buf.push('\n');
        }

        match self.mode {
            Mode::Check => {
                let old = std::fs::read_to_string(dest)
                    .with_context(|| format!("failed to read {}", self.path(dest)))?;
                if old != buf {
                    return Err(Box::new(StrError(format!(
                        "{} and {} are different",
                        self.path(source),
                        self.path(dest),
                    ))));
                }
            }
            Mode::Generate => {
                std::fs::write(dest, buf.as_bytes())
                    .with_context(|| format!("failed to write to {}", self.path(dest)))?;
            }
        }
        Ok(())
    }

    fn path<'a>(&self, path: &'a Path) -> impl std::fmt::Display + 'a {
        path.strip_prefix(&self.base).unwrap_or(path).display()
    }
}

fn filter_document(document: Yaml) -> Yaml {
    match document {
        Yaml::Hash(map) => Yaml::Hash(
            map.into_iter()
                .filter(|(key, _)| {
                    if let Yaml::String(string) = &key { string != REMOVE_MAP_KEY } else { true }
                })
                .map(|(key, value)| (filter_document(key), filter_document(value)))
                .collect(),
        ),
        Yaml::Array(vec) => Yaml::Array(vec.into_iter().map(filter_document).collect()),
        other => other,
    }
}

fn main() {
    if let Err(err) = App::from_args().and_then(|app| app.run()) {
        eprintln!("error: {}", err);

        let mut source = err.as_ref() as &dyn Error;
        while let Some(err) = source.source() {
            eprintln!("caused by: {}", err);
            source = err;
        }

        std::process::exit(1);
    }
}

#[derive(Debug)]
struct StrError(String);

impl Error for StrError {}

impl std::fmt::Display for StrError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&self.0, f)
    }
}

#[derive(Debug)]
struct WithContext {
    context: String,
    source: Box<dyn Error>,
}

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

impl Error for WithContext {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        Some(self.source.as_ref())
    }
}

pub(crate) trait ResultExt<T> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>>;
}

impl<T, E: Into<Box<dyn Error>>> ResultExt<T> for Result<T, E> {
    fn with_context<F: FnOnce() -> String>(self, f: F) -> Result<T, Box<dyn Error>> {
        match self {
            Ok(ok) => Ok(ok),
            Err(err) => Err(WithContext { source: err.into(), context: f() }.into()),
        }
    }
}
<|endoftext|>


<commit_before>use bytes::{Buf, BufMut};
use futures::{Future, Poll};
use std::error::Error;
use std::io::{self, Read, Write};
use tokio_io::{AsyncRead, AsyncWrite};

use proto;

pub struct Socket(pub(crate) proto::Socket);

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl AsyncRead for Socket {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        self.0.prepare_uninitialized_buffer(buf)
    }

    fn read_buf<B>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
    where
        B: BufMut,
    {
        self.0.read_buf(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.0.shutdown()
    }

    fn write_buf<B>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
    where
        B: Buf,
    {
        self.0.write_buf(buf)
    }
}

pub trait TlsConnect {
    fn connect(
        &self,
        domain: &str,
        socket: Socket,
    ) -> Box<Future<Item = Box<TlsStream>, Error = Box<Error + Sync + Send>> + Sync + Send>;
}

pub trait TlsStream: 'static + Sync + Send + AsyncRead + AsyncWrite {
    /// Returns the data associated with the `tls-unique` channel binding type as described in
    /// [RFC 5929], if supported.
    ///
    /// An implementation only needs to support one of this or `tls_server_end_point`.
    ///
    /// [RFC 5929]: https://tools.ietf.org/html/rfc5929
    fn tls_unique(&self) -> Option<Vec<u8>> {
        None
    }

    /// Returns the data associated with the `tls-server-end-point` channel binding type as
    /// described in [RFC 5929], if supported.
    ///
    /// An implementation only needs to support one of this or `tls_unique`.
    ///
    /// [RFC 5929]: https://tools.ietf.org/html/rfc5929
    fn tls_server_end_point(&self) -> Option<Vec<u8>> {
        None
    }
}

impl TlsStream for proto::Socket {}
<commit_msg>Tweak docs<commit_after>use bytes::{Buf, BufMut};
use futures::{Future, Poll};
use std::error::Error;
use std::io::{self, Read, Write};
use tokio_io::{AsyncRead, AsyncWrite};

use proto;

pub struct Socket(pub(crate) proto::Socket);

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl AsyncRead for Socket {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        self.0.prepare_uninitialized_buffer(buf)
    }

    fn read_buf<B>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
    where
        B: BufMut,
    {
        self.0.read_buf(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.0.shutdown()
    }

    fn write_buf<B>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
    where
        B: Buf,
    {
        self.0.write_buf(buf)
    }
}

pub trait TlsConnect {
    fn connect(
        &self,
        domain: &str,
        socket: Socket,
    ) -> Box<Future<Item = Box<TlsStream>, Error = Box<Error + Sync + Send>> + Sync + Send>;
}

pub trait TlsStream: 'static + Sync + Send + AsyncRead + AsyncWrite {
    /// Returns the data associated with the `tls-unique` channel binding type as described in
    /// [RFC 5929], if supported.
    ///
    /// An implementation only needs to support at most one of this or `tls_server_end_point`.
    ///
    /// [RFC 5929]: https://tools.ietf.org/html/rfc5929
    fn tls_unique(&self) -> Option<Vec<u8>> {
        None
    }

    /// Returns the data associated with the `tls-server-end-point` channel binding type as
    /// described in [RFC 5929], if supported.
    ///
    /// An implementation only needs to support at most one of this or `tls_unique`.
    ///
    /// [RFC 5929]: https://tools.ietf.org/html/rfc5929
    fn tls_server_end_point(&self) -> Option<Vec<u8>> {
        None
    }
}

impl TlsStream for proto::Socket {}
<|endoftext|>


<commit_before>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[feature(globs)];
#[feature(macro_rules)];

extern mod glfw;
extern mod gl;

use std::cast;
use std::ptr;
use std::str;
use std::sys;
use std::vec;

use gl::types::*;

// Vertex data
static VERTEX_DATA: [GLfloat, ..6] = [
     0.0,  0.5,
     0.5, -0.5,
    -0.5, -0.5
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 position;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

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

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    program
}

fn main() {
    do glfw::set_error_callback |_, description| {
        println!("GLFW Error: {}", description);
    }

    do glfw::start {
        // Choose a GL profile that is compatible with OS X 10.7+
        glfw::window_hint::context_version(3, 2);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::opengl_forward_compat(true);

        let window = glfw::Window::create(800, 600, "OpenGL", glfw::Windowed).unwrap();
        window.make_context_current();

        // Load the OpenGL function pointers
        gl::load_with(glfw::get_proc_address);

        // Create GLSL shaders
        let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
        let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
        let program = link_program(vs, fs);

        let mut vao = 0;
        let mut vbo = 0;

        unsafe {
            // Create Vertex Array Object
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl::GenBuffers(1, &mut vbo);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(gl::ARRAY_BUFFER,
                           (VERTEX_DATA.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                           cast::transmute(&VERTEX_DATA[0]),
                           gl::STATIC_DRAW);

            // Use shader program
            gl::UseProgram(program);
            "out_color".with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));

            // Specify the layout of the vertex data
            let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(pos_attr as GLuint);
            gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());
        }

        while !window.should_close() {
            // Poll events
            glfw::poll_events();

            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices
            gl::DrawArrays(gl::TRIANGLES, 0, 3);

            // Swap buffers
            window.swap_buffers();
        }

        // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        unsafe {
            gl::DeleteBuffers(1, &vbo);
            gl::DeleteVertexArrays(1, &vao);
        }
    }
}
<commit_msg>size_of was moved to std::mem from std::sys<commit_after>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[feature(globs)];
#[feature(macro_rules)];

extern mod glfw;
extern mod gl;

use std::cast;
use std::ptr;
use std::str;
use std::mem;
use std::vec;

use gl::types::*;

// Vertex data
static VERTEX_DATA: [GLfloat, ..6] = [
     0.0,  0.5,
     0.5, -0.5,
    -0.5, -0.5
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 position;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

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

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    program
}

fn main() {
    do glfw::set_error_callback |_, description| {
        println!("GLFW Error: {}", description);
    }

    do glfw::start {
        // Choose a GL profile that is compatible with OS X 10.7+
        glfw::window_hint::context_version(3, 2);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::opengl_forward_compat(true);

        let window = glfw::Window::create(800, 600, "OpenGL", glfw::Windowed).unwrap();
        window.make_context_current();

        // Load the OpenGL function pointers
        gl::load_with(glfw::get_proc_address);

        // Create GLSL shaders
        let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
        let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
        let program = link_program(vs, fs);

        let mut vao = 0;
        let mut vbo = 0;

        unsafe {
            // Create Vertex Array Object
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl::GenBuffers(1, &mut vbo);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(gl::ARRAY_BUFFER,
                           (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                           cast::transmute(&VERTEX_DATA[0]),
                           gl::STATIC_DRAW);

            // Use shader program
            gl::UseProgram(program);
            "out_color".with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));

            // Specify the layout of the vertex data
            let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(pos_attr as GLuint);
            gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());
        }

        while !window.should_close() {
            // Poll events
            glfw::poll_events();

            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices
            gl::DrawArrays(gl::TRIANGLES, 0, 3);

            // Swap buffers
            window.swap_buffers();
        }

        // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        unsafe {
            gl::DeleteBuffers(1, &vbo);
            gl::DeleteVertexArrays(1, &vao);
        }
    }
}
<|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/. */

#![allow(unsafe_blocks)]

use construct::ConstructionResult;
use incremental::RestyleDamage;
use parallel::DomParallelInfo;
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};

use gfx::display_list::OpaqueNode;
use gfx;
use libc::{c_void, uintptr_t};
use script::dom::bindings::js::LayoutJS;
use script::dom::node::{Node, SharedLayoutData};
use script::layout_interface::{LayoutChan, TrustedNodeAddress};
use script_traits::UntrustedNodeAddress;
use std::mem;
use std::cell::{Ref, RefMut};
use style::properties::ComputedValues;
use style;
use std::sync::Arc;

/// Data that layout associates with a node.
pub struct PrivateLayoutData {
    /// The results of CSS styling for this node's `before` pseudo-element, if any.
    pub before_style: Option<Arc<ComputedValues>>,

    /// The results of CSS styling for this node's `after` pseudo-element, if any.
    pub after_style: Option<Arc<ComputedValues>>,

    /// Description of how to account for recent style changes.
    pub restyle_damage: RestyleDamage,

    /// The current results of flow construction for this node. This is either a flow or a
    /// `ConstructionItem`. See comments in `construct.rs` for more details.
    pub flow_construction_result: ConstructionResult,

    pub before_flow_construction_result: ConstructionResult,

    pub after_flow_construction_result: ConstructionResult,

    /// Information needed during parallel traversals.
    pub parallel: DomParallelInfo,

    /// Various flags.
    pub flags: LayoutDataFlags,
}

impl PrivateLayoutData {
    /// Creates new layout data.
    pub fn new() -> PrivateLayoutData {
        PrivateLayoutData {
            before_style: None,
            after_style: None,
            restyle_damage: RestyleDamage::empty(),
            flow_construction_result: ConstructionResult::None,
            before_flow_construction_result: ConstructionResult::None,
            after_flow_construction_result: ConstructionResult::None,
            parallel: DomParallelInfo::new(),
            flags: LayoutDataFlags::empty(),
        }
    }
}

bitflags! {
    flags LayoutDataFlags: u8 {
        #[doc="Whether a flow has been newly constructed."]
        const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01
    }
}

pub struct LayoutDataWrapper {
    pub chan: Option<LayoutChan>,
    pub shared_data: SharedLayoutData,
    pub data: Box<PrivateLayoutData>,
}

#[allow(dead_code)]
fn static_assertion(x: Option<LayoutDataWrapper>) {
    unsafe {
        let _: Option<::script::dom::node::LayoutData> =
            ::std::intrinsics::transmute(x);
    }
}

/// A trait that allows access to the layout data of a DOM node.
pub trait LayoutDataAccess {
    /// Borrows the layout data without checks.
    unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper>;
    /// Borrows the layout data immutably. Fails on a conflicting borrow.
    fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>>;
    /// Borrows the layout data mutably. Fails on a conflicting borrow.
    fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>>;
}

impl<'ln> LayoutDataAccess for LayoutNode<'ln> {
    #[inline(always)]
    unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
        mem::transmute(self.get().layout_data_unchecked())
    }

    #[inline(always)]
    fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
        unsafe {
            mem::transmute(self.get().layout_data())
        }
    }

    #[inline(always)]
    fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
        unsafe {
            mem::transmute(self.get().layout_data_mut())
        }
    }
}

pub trait OpaqueNodeMethods {
    /// Converts a DOM node (layout view) to an `OpaqueNode`.
    fn from_layout_node(node: &LayoutNode) -> Self;

    /// Converts a thread-safe DOM node (layout view) to an `OpaqueNode`.
    fn from_thread_safe_layout_node(node: &ThreadSafeLayoutNode) -> Self;

    /// Converts a DOM node (script view) to an `OpaqueNode`.
    fn from_script_node(node: TrustedNodeAddress) -> Self;

    /// Converts a DOM node to an `OpaqueNode'.
    fn from_jsmanaged(node: &LayoutJS<Node>) -> Self;

    /// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type
    /// of node that script expects to receive in a hit test.
    fn to_untrusted_node_address(&self) -> UntrustedNodeAddress;
}

impl OpaqueNodeMethods for OpaqueNode {
    fn from_layout_node(node: &LayoutNode) -> OpaqueNode {
        unsafe {
            OpaqueNodeMethods::from_jsmanaged(node.get_jsmanaged())
        }
    }

    fn from_thread_safe_layout_node(node: &ThreadSafeLayoutNode) -> OpaqueNode {
        unsafe {
            let abstract_node = node.get_jsmanaged();
            let ptr: uintptr_t = abstract_node.get_jsobject() as uintptr_t;
            OpaqueNode(ptr)
        }
    }

    fn from_script_node(node: TrustedNodeAddress) -> OpaqueNode {
        unsafe {
            OpaqueNodeMethods::from_jsmanaged(&LayoutJS::from_trusted_node_address(node))
        }
    }

    fn from_jsmanaged(node: &LayoutJS<Node>) -> OpaqueNode {
        unsafe {
            let ptr: uintptr_t = node.get_jsobject() as uintptr_t;
            OpaqueNode(ptr)
        }
    }

    fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
        let OpaqueNode(addr) = *self;
        UntrustedNodeAddress(addr as *const c_void)
    }
}

/// Allows a CSS color to be converted into a graphics color.
pub trait ToGfxColor {
    /// Converts a CSS color to a graphics color.
    fn to_gfx_color(&self) -> gfx::color::Color;
}

impl ToGfxColor for style::values::RGBA {
    fn to_gfx_color(&self) -> gfx::color::Color {
        gfx::color::rgba(self.red, self.green, self.blue, self.alpha)
    }
}
<commit_msg>Reduce duplicated code in from_thread_safe_layout_node.<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/. */

#![allow(unsafe_blocks)]

use construct::ConstructionResult;
use incremental::RestyleDamage;
use parallel::DomParallelInfo;
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};

use gfx::display_list::OpaqueNode;
use gfx;
use libc::{c_void, uintptr_t};
use script::dom::bindings::js::LayoutJS;
use script::dom::node::{Node, SharedLayoutData};
use script::layout_interface::{LayoutChan, TrustedNodeAddress};
use script_traits::UntrustedNodeAddress;
use std::mem;
use std::cell::{Ref, RefMut};
use style::properties::ComputedValues;
use style;
use std::sync::Arc;

/// Data that layout associates with a node.
pub struct PrivateLayoutData {
    /// The results of CSS styling for this node's `before` pseudo-element, if any.
    pub before_style: Option<Arc<ComputedValues>>,

    /// The results of CSS styling for this node's `after` pseudo-element, if any.
    pub after_style: Option<Arc<ComputedValues>>,

    /// Description of how to account for recent style changes.
    pub restyle_damage: RestyleDamage,

    /// The current results of flow construction for this node. This is either a flow or a
    /// `ConstructionItem`. See comments in `construct.rs` for more details.
    pub flow_construction_result: ConstructionResult,

    pub before_flow_construction_result: ConstructionResult,

    pub after_flow_construction_result: ConstructionResult,

    /// Information needed during parallel traversals.
    pub parallel: DomParallelInfo,

    /// Various flags.
    pub flags: LayoutDataFlags,
}

impl PrivateLayoutData {
    /// Creates new layout data.
    pub fn new() -> PrivateLayoutData {
        PrivateLayoutData {
            before_style: None,
            after_style: None,
            restyle_damage: RestyleDamage::empty(),
            flow_construction_result: ConstructionResult::None,
            before_flow_construction_result: ConstructionResult::None,
            after_flow_construction_result: ConstructionResult::None,
            parallel: DomParallelInfo::new(),
            flags: LayoutDataFlags::empty(),
        }
    }
}

bitflags! {
    flags LayoutDataFlags: u8 {
        #[doc="Whether a flow has been newly constructed."]
        const HAS_NEWLY_CONSTRUCTED_FLOW = 0x01
    }
}

pub struct LayoutDataWrapper {
    pub chan: Option<LayoutChan>,
    pub shared_data: SharedLayoutData,
    pub data: Box<PrivateLayoutData>,
}

#[allow(dead_code)]
fn static_assertion(x: Option<LayoutDataWrapper>) {
    unsafe {
        let _: Option<::script::dom::node::LayoutData> =
            ::std::intrinsics::transmute(x);
    }
}

/// A trait that allows access to the layout data of a DOM node.
pub trait LayoutDataAccess {
    /// Borrows the layout data without checks.
    unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper>;
    /// Borrows the layout data immutably. Fails on a conflicting borrow.
    fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>>;
    /// Borrows the layout data mutably. Fails on a conflicting borrow.
    fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>>;
}

impl<'ln> LayoutDataAccess for LayoutNode<'ln> {
    #[inline(always)]
    unsafe fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
        mem::transmute(self.get().layout_data_unchecked())
    }

    #[inline(always)]
    fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> {
        unsafe {
            mem::transmute(self.get().layout_data())
        }
    }

    #[inline(always)]
    fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> {
        unsafe {
            mem::transmute(self.get().layout_data_mut())
        }
    }
}

pub trait OpaqueNodeMethods {
    /// Converts a DOM node (layout view) to an `OpaqueNode`.
    fn from_layout_node(node: &LayoutNode) -> Self;

    /// Converts a thread-safe DOM node (layout view) to an `OpaqueNode`.
    fn from_thread_safe_layout_node(node: &ThreadSafeLayoutNode) -> Self;

    /// Converts a DOM node (script view) to an `OpaqueNode`.
    fn from_script_node(node: TrustedNodeAddress) -> Self;

    /// Converts a DOM node to an `OpaqueNode'.
    fn from_jsmanaged(node: &LayoutJS<Node>) -> Self;

    /// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type
    /// of node that script expects to receive in a hit test.
    fn to_untrusted_node_address(&self) -> UntrustedNodeAddress;
}

impl OpaqueNodeMethods for OpaqueNode {
    fn from_layout_node(node: &LayoutNode) -> OpaqueNode {
        unsafe {
            OpaqueNodeMethods::from_jsmanaged(node.get_jsmanaged())
        }
    }

    fn from_thread_safe_layout_node(node: &ThreadSafeLayoutNode) -> OpaqueNode {
        unsafe {
            OpaqueNodeMethods::from_jsmanaged(node.get_jsmanaged())
        }
    }

    fn from_script_node(node: TrustedNodeAddress) -> OpaqueNode {
        unsafe {
            OpaqueNodeMethods::from_jsmanaged(&LayoutJS::from_trusted_node_address(node))
        }
    }

    fn from_jsmanaged(node: &LayoutJS<Node>) -> OpaqueNode {
        unsafe {
            let ptr: uintptr_t = node.get_jsobject() as uintptr_t;
            OpaqueNode(ptr)
        }
    }

    fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
        let OpaqueNode(addr) = *self;
        UntrustedNodeAddress(addr as *const c_void)
    }
}

/// Allows a CSS color to be converted into a graphics color.
pub trait ToGfxColor {
    /// Converts a CSS color to a graphics color.
    fn to_gfx_color(&self) -> gfx::color::Color;
}

impl ToGfxColor for style::values::RGBA {
    fn to_gfx_color(&self) -> gfx::color::Color {
        gfx::color::rgba(self.red, self.green, self.blue, self.alpha)
    }
}
<|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 dom::bindings::cell::DOMRefCell;
use dom::bindings::js::{JS, Root};
use dom::document::Document;
use dom::window::Window;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
use std::rc::Rc;

/// Encapsulates a handle to a frame in a frame tree.
#[derive(JSTraceable, HeapSizeOf)]
#[allow(unrooted_must_root)] // FIXME(#6687) this is wrong
pub struct Page {
    /// Pipeline id associated with this page.
    id: PipelineId,

    /// The outermost frame containing the document and window.
    frame: DOMRefCell<Option<Frame>>,

    /// Indicates if reflow is required when reloading.
    needs_reflow: Cell<bool>,

    // Child Pages.
    pub children: DOMRefCell<Vec<Rc<Page>>>,
}

pub struct PageIterator {
    stack: Vec<Rc<Page>>,
}

pub trait IterablePage {
    fn iter(&self) -> PageIterator;
    fn find(&self, id: PipelineId) -> Option<Rc<Page>>;
}

impl IterablePage for Rc<Page> {
    fn iter(&self) -> PageIterator {
        PageIterator {
            stack: vec!(self.clone()),
        }
    }
    fn find(&self, id: PipelineId) -> Option<Rc<Page>> {
        if self.id == id { return Some(self.clone()); }
        for page in &*self.children.borrow() {
            let found = page.find(id);
            if found.is_some() { return found; }
        }
        None
    }

}

impl Page {
    pub fn new(id: PipelineId) -> Page {
        Page {
            id: id,
            frame: DOMRefCell::new(None),
            needs_reflow: Cell::new(true),
            children: DOMRefCell::new(vec!()),
        }
    }

    pub fn pipeline(&self) -> PipelineId {
        self.id
    }

    pub fn window(&self) -> Root<Window> {
        Root::from_ref(&*self.frame.borrow().as_ref().unwrap().window)
    }

    pub fn document(&self) -> Root<Document> {
        Root::from_ref(&*self.frame.borrow().as_ref().unwrap().document)
    }

    // must handle root case separately
    pub fn remove(&self, id: PipelineId) -> Option<Rc<Page>> {
        let remove_idx = {
            self.children
                .borrow_mut()
                .iter_mut()
                .position(|page_tree| page_tree.id == id)
        };
        match remove_idx {
            Some(idx) => Some(self.children.borrow_mut().remove(idx)),
            None => {
                self.children
                    .borrow_mut()
                    .iter_mut()
                    .filter_map(|page_tree| page_tree.remove(id))
                    .next()
            }
        }
    }
}

impl Iterator for PageIterator {
    type Item = Rc<Page>;

    fn next(&mut self) -> Option<Rc<Page>> {
        let popped = self.stack.pop();
        if let Some(ref page) = popped {
            self.stack.extend(page.children.borrow().iter().cloned());
        }
        popped
    }
}

impl Page {
    pub fn set_reflow_status(&self, status: bool) -> bool {
        let old = self.needs_reflow.get();
        self.needs_reflow.set(status);
        old
    }

    #[allow(unrooted_must_root)]
    pub fn set_frame(&self, frame: Option<Frame>) {
        *self.frame.borrow_mut() = frame;
    }
}

/// Information for one frame in the browsing context.
#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct Frame {
    /// The document for this frame.
    pub document: JS<Document>,
    /// The window object for this frame.
    pub window: JS<Window>,
}
<commit_msg>Auto merge of #8482 - frewsxcv:no-mut, r=Ms2ger<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 dom::bindings::cell::DOMRefCell;
use dom::bindings::js::{JS, Root};
use dom::document::Document;
use dom::window::Window;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
use std::rc::Rc;

/// Encapsulates a handle to a frame in a frame tree.
#[derive(JSTraceable, HeapSizeOf)]
#[allow(unrooted_must_root)] // FIXME(#6687) this is wrong
pub struct Page {
    /// Pipeline id associated with this page.
    id: PipelineId,

    /// The outermost frame containing the document and window.
    frame: DOMRefCell<Option<Frame>>,

    /// Indicates if reflow is required when reloading.
    needs_reflow: Cell<bool>,

    // Child Pages.
    pub children: DOMRefCell<Vec<Rc<Page>>>,
}

pub struct PageIterator {
    stack: Vec<Rc<Page>>,
}

pub trait IterablePage {
    fn iter(&self) -> PageIterator;
    fn find(&self, id: PipelineId) -> Option<Rc<Page>>;
}

impl IterablePage for Rc<Page> {
    fn iter(&self) -> PageIterator {
        PageIterator {
            stack: vec!(self.clone()),
        }
    }
    fn find(&self, id: PipelineId) -> Option<Rc<Page>> {
        if self.id == id { return Some(self.clone()); }
        for page in &*self.children.borrow() {
            let found = page.find(id);
            if found.is_some() { return found; }
        }
        None
    }

}

impl Page {
    pub fn new(id: PipelineId) -> Page {
        Page {
            id: id,
            frame: DOMRefCell::new(None),
            needs_reflow: Cell::new(true),
            children: DOMRefCell::new(vec!()),
        }
    }

    pub fn pipeline(&self) -> PipelineId {
        self.id
    }

    pub fn window(&self) -> Root<Window> {
        Root::from_ref(&*self.frame.borrow().as_ref().unwrap().window)
    }

    pub fn document(&self) -> Root<Document> {
        Root::from_ref(&*self.frame.borrow().as_ref().unwrap().document)
    }

    // must handle root case separately
    pub fn remove(&self, id: PipelineId) -> Option<Rc<Page>> {
        let remove_idx = {
            self.children
                .borrow()
                .iter()
                .position(|page_tree| page_tree.id == id)
        };
        match remove_idx {
            Some(idx) => Some(self.children.borrow_mut().remove(idx)),
            None => {
                self.children
                    .borrow_mut()
                    .iter_mut()
                    .filter_map(|page_tree| page_tree.remove(id))
                    .next()
            }
        }
    }
}

impl Iterator for PageIterator {
    type Item = Rc<Page>;

    fn next(&mut self) -> Option<Rc<Page>> {
        let popped = self.stack.pop();
        if let Some(ref page) = popped {
            self.stack.extend(page.children.borrow().iter().cloned());
        }
        popped
    }
}

impl Page {
    pub fn set_reflow_status(&self, status: bool) -> bool {
        let old = self.needs_reflow.get();
        self.needs_reflow.set(status);
        old
    }

    #[allow(unrooted_must_root)]
    pub fn set_frame(&self, frame: Option<Frame>) {
        *self.frame.borrow_mut() = frame;
    }
}

/// Information for one frame in the browsing context.
#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct Frame {
    /// The document for this frame.
    pub document: JS<Document>,
    /// The window object for this frame.
    pub window: JS<Window>,
}
<|endoftext|>