<commit_before>use regex::Regex;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;
use tempfile::NamedTempFile;

use protobuf::descriptor::field_descriptor_proto;
use protobuf::descriptor::DescriptorProto;
use protobuf::descriptor::EnumDescriptorProto;
use protobuf::descriptor::FieldDescriptorProto;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::descriptor::FileDescriptorSet;
use protobuf::descriptor::MethodDescriptorProto;
use protobuf::descriptor::OneofDescriptorProto;
use protobuf::descriptor::ServiceDescriptorProto;
use protobuf::text_format::lexer::float::parse_protobuf_float;
use protobuf::Message;
use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // sanity check
    let mut a_full = dir.to_path_buf();
    a_full.push(a);
    assert!(a_full.exists());
    let mut b_full = dir.to_path_buf();
    b_full.push(b);
    assert!(b_full.exists());

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn protoc_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut temp_file = NamedTempFile::new().unwrap();
    protoc::Protoc::from_path(protoc_bin_vendored::protoc_bin_path().unwrap())
        .descriptor_set_out_args()
        .out(temp_file.path())
        .includes(includes)
        .inputs(inputs)
        .write_descriptor_set()
        .unwrap();
    FileDescriptorSet::parse_from_reader(&mut temp_file).unwrap()
}

// TODO: expose this utility from protobuf-codegen-pure crate.
fn pure_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut codegen = protobuf_codegen_pure::parse_and_typecheck(includes, inputs).unwrap();
    let relative_paths: HashSet<_> = codegen
        .relative_paths
        .iter()
        .map(|path| path.to_string_lossy())
        .collect();
    codegen
        .file_descriptors
        .retain(|fd| relative_paths.contains(fd.get_name()));
    let mut fds = FileDescriptorSet::new();
    fds.file = codegen.file_descriptors;
    fds
}

fn normalize_descriptor_set(fds: &mut FileDescriptorSet) {
    for desc in &mut fds.file {
        normalize_file_descriptor(desc)
    }
}

fn normalize_file_descriptor(desc: &mut FileDescriptorProto) {
    if !desc.has_syntax() {
        desc.set_syntax("proto2".into())
    }
    for desc in &mut *desc.message_type {
        normalize_descriptor(desc)
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc)
    }

    for desc in &mut desc.extension {
        desc.options.mut_or_default();
    }
    desc.options.mut_or_default();

    for service in &mut desc.service {
        normalize_service(service);
    }

    // for unittest_custom_options.proto where a custom option
    // is an extension. Probably nobody outside of Google uses it.
    desc.options
        .mut_or_default()
        .unknown_fields
        .remove(15478479);
}

fn normalize_enum_descriptor(desc: &mut EnumDescriptorProto) {
    desc.options.mut_or_default();

    for value in &mut desc.value {
        value.options.mut_or_default();
    }
}

fn normalize_oneof_descriptor(desc: &mut OneofDescriptorProto) {
    desc.options.mut_or_default();
}

fn normalize_descriptor(desc: &mut DescriptorProto) {
    for desc in &mut desc.nested_type {
        normalize_descriptor(desc);
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc);
    }
    for desc in &mut desc.oneof_decl {
        normalize_oneof_descriptor(desc);
    }

    desc.options.mut_or_default();

    // group are not supported
    desc.options.mut_or_default().unknown_fields.remove(7636463);

    for field in &mut desc.field {
        normalize_field(field);
    }

    for ext in &mut desc.extension {
        ext.options.mut_or_default();
    }

    for ext in &mut desc.extension_range {
        // If ext range end exceeds max field number,
        // the actual upper limit does not matter.
        // protoc is not consistent in behavior thus flush
        // the value to some arbitrary compatible value.
        if ext.has_end() && ext.get_end() >= 0x20000000 {
            ext.set_end(0x20000000);
        }
    }
}

fn normalize_method(method: &mut MethodDescriptorProto) {
    // TODO: do not clear
    method.clear_input_type();
    method.clear_output_type();

    method.options.clear();
}

fn normalize_service(service: &mut ServiceDescriptorProto) {
    for m in &mut service.method {
        normalize_method(m);
    }

    service.options.mut_or_default();
}

fn normalize_field(field: &mut FieldDescriptorProto) {
    field.options.mut_or_default();

    if field.has_default_value() {
        if field.get_field_type() == field_descriptor_proto::Type::TYPE_FLOAT {
            field.set_default_value(format!(
                "{}",
                parse_protobuf_float(field.get_default_value()).unwrap()
            ));
        }
    }
}

fn pretty_message<M: protobuf::Message>(message: &M) -> String {
    // TODO: pull this handy utility into the protobuf crate.
    struct FormatMessage<'a, M>(&'a M);

    impl<M: protobuf::Message> fmt::Display for FormatMessage<'_, M> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            protobuf::text_format::fmt(self.0, f)
        }
    }

    format!("{:#}", FormatMessage(message))
}

fn descriptor_for_file<'a>(fds: &'a FileDescriptorSet, file_name: &str) -> &'a FileDescriptorProto {
    for file in &fds.file {
        if Path::new(file.get_name()).file_name().unwrap()
            == Path::new(file_name).file_name().unwrap()
        {
            return file;
        }
    }
    panic!(
        "file not found: {}; all files: {}",
        file_name,
        fds.file
            .iter()
            .map(|f| f.get_name())
            .collect::<Vec<_>>()
            .join(", ")
    );
}

fn test_diff_in<F>(root: &str, sources_dir: &str, include: &str, should_skip: F)
where
    F: Fn(&str) -> bool,
{
    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };

    let mut include_root = Path::new(root).to_path_buf();
    include_root.push(include);

    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, sources_dir);

    let inputs_glob = format!("{}/*.proto*", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .protoc_path(protoc_bin_vendored::protoc_bin_path().unwrap())
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    let mut protoc_descriptors = protoc_descriptor_set(&includes, &inputs);
    let mut pure_descriptors = pure_descriptor_set(&includes, &inputs);
    normalize_descriptor_set(&mut protoc_descriptors);
    normalize_descriptor_set(&mut pure_descriptors);

    for input in &inputs {
        let label = input.strip_prefix(root).unwrap().to_str().unwrap();
        let proto_file_name = input.strip_prefix(&include_root).unwrap().to_str().unwrap();
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));

        let protoc_descriptor_for_file = descriptor_for_file(&protoc_descriptors, &proto_file_name);
        let pure_descriptor_for_file = descriptor_for_file(&pure_descriptors, &proto_file_name);

        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents
            && protoc_descriptor_for_file == pure_descriptor_for_file
        {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(
                temp_dir.path(),
                Path::new(&protoc_rs).strip_prefix(temp_dir.path()).unwrap(),
                Path::new(&pure_rs).strip_prefix(temp_dir.path()).unwrap(),
            );

            fs::write(
                format!("{}/{}.descriptors", protoc_dir, proto_name),
                pretty_message(protoc_descriptor_for_file),
            )
            .unwrap();
            fs::write(
                format!("{}/{}.descriptors", pure_dir, proto_name),
                pretty_message(pure_descriptor_for_file),
            )
            .unwrap();
            print_diff(
                temp_dir.path(),
                Path::new(&format!("protoc/{}.descriptors", proto_name)),
                Path::new(&format!("pure/{}.descriptors", proto_name)),
            );
        }
    }

    println!("{:?}", stats);
    assert!(stats.failed == 0, "at least one test failed");
}

fn should_skip_with_marker(path: &str) -> bool {
    fs::read_to_string(path)
        .unwrap()
        .contains("@skip-codegen-identical-test")
}

#[test]
fn common_v2() {
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip_with_marker,
    );
}

#[test]
fn common_v3() {
    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip_with_marker,
    );
}

#[test]
fn v2() {
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip_with_marker,
    );
}

#[test]
fn v3() {
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip_with_marker,
    );
}

#[test]
fn interop() {
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip_with_marker,
    );
}

#[test]
fn google() {
    test_diff_in("../protobuf-test", "src/google/protobuf", "src", |_| false);
}
<commit_msg>Do not clean service options in diff test<commit_after>use regex::Regex;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write as _;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::path::MAIN_SEPARATOR;
use std::str;
use tempfile::NamedTempFile;

use protobuf::descriptor::field_descriptor_proto;
use protobuf::descriptor::DescriptorProto;
use protobuf::descriptor::EnumDescriptorProto;
use protobuf::descriptor::FieldDescriptorProto;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::descriptor::FileDescriptorSet;
use protobuf::descriptor::MethodDescriptorProto;
use protobuf::descriptor::OneofDescriptorProto;
use protobuf::descriptor::ServiceDescriptorProto;
use protobuf::text_format::lexer::float::parse_protobuf_float;
use protobuf::Message;
use protobuf_test_common::build::copy_tests_v2_v3;
use protobuf_test_common::build::glob_simple;
use std::process::Command;
use std::process::Stdio;

fn to_paths(iter: impl IntoIterator<Item = impl Into<String>>) -> Vec<PathBuf> {
    iter.into_iter()
        .map(|item| item.into().replace(MAIN_SEPARATOR, "/").into())
        .collect()
}

#[derive(Default, Debug)]
struct TestStats {
    passed: u32,
    passed_marked_skip: u32,
    skipped: u32,
    failed: u32,
}

fn normalize_generated_file(contents: &str) -> String {
    let parsed_by = Regex::new("^// \\.proto file is parsed by.*").unwrap();

    let mut r = String::new();
    let mut inside_descriptor_data = false;
    for line in contents.lines() {
        let line = if inside_descriptor_data {
            if line == "\";" {
                inside_descriptor_data = false;
                line.to_owned()
            } else {
                continue;
            }
        } else if line.starts_with("static file_descriptor_proto_data") {
            inside_descriptor_data = true;
            line.to_owned()
        } else {
            parsed_by.replace(line, "").into_owned()
        };

        writeln!(&mut r, "{}", line).unwrap();
    }

    // sanity check
    assert!(!inside_descriptor_data);

    r
}

fn normalize_generated_file_in_place(path: &Path) {
    let contents = fs::read_to_string(path).unwrap();
    let contents = normalize_generated_file(&contents);
    fs::write(path, &contents).unwrap();
}

fn print_diff(dir: &Path, a: &Path, b: &Path) {
    if cfg!(windows) {
        // likely we don't have `diff` command on Windows
        return;
    }

    // sanity check
    let mut a_full = dir.to_path_buf();
    a_full.push(a);
    assert!(a_full.exists());
    let mut b_full = dir.to_path_buf();
    b_full.push(b);
    assert!(b_full.exists());

    // Not using difference crate because it's slow for large files
    let output = Command::new("diff")
        .current_dir(dir)
        .arg("-u")
        .arg(a)
        .arg(b)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .unwrap();

    print!("{}", str::from_utf8(&output.stdout).unwrap());
    print!("{}", str::from_utf8(&output.stderr).unwrap());
}

fn protoc_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut temp_file = NamedTempFile::new().unwrap();
    protoc::Protoc::from_path(protoc_bin_vendored::protoc_bin_path().unwrap())
        .descriptor_set_out_args()
        .out(temp_file.path())
        .includes(includes)
        .inputs(inputs)
        .write_descriptor_set()
        .unwrap();
    FileDescriptorSet::parse_from_reader(&mut temp_file).unwrap()
}

// TODO: expose this utility from protobuf-codegen-pure crate.
fn pure_descriptor_set(includes: &[PathBuf], inputs: &[PathBuf]) -> FileDescriptorSet {
    let mut codegen = protobuf_codegen_pure::parse_and_typecheck(includes, inputs).unwrap();
    let relative_paths: HashSet<_> = codegen
        .relative_paths
        .iter()
        .map(|path| path.to_string_lossy())
        .collect();
    codegen
        .file_descriptors
        .retain(|fd| relative_paths.contains(fd.get_name()));
    let mut fds = FileDescriptorSet::new();
    fds.file = codegen.file_descriptors;
    fds
}

fn normalize_descriptor_set(fds: &mut FileDescriptorSet) {
    for desc in &mut fds.file {
        normalize_file_descriptor(desc)
    }
}

fn normalize_file_descriptor(desc: &mut FileDescriptorProto) {
    if !desc.has_syntax() {
        desc.set_syntax("proto2".into())
    }
    for desc in &mut *desc.message_type {
        normalize_descriptor(desc)
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc)
    }

    for desc in &mut desc.extension {
        desc.options.mut_or_default();
    }
    desc.options.mut_or_default();

    for service in &mut desc.service {
        normalize_service(service);
    }

    // for unittest_custom_options.proto where a custom option
    // is an extension. Probably nobody outside of Google uses it.
    desc.options
        .mut_or_default()
        .unknown_fields
        .remove(15478479);
}

fn normalize_enum_descriptor(desc: &mut EnumDescriptorProto) {
    desc.options.mut_or_default();

    for value in &mut desc.value {
        value.options.mut_or_default();
    }
}

fn normalize_oneof_descriptor(desc: &mut OneofDescriptorProto) {
    desc.options.mut_or_default();
}

fn normalize_descriptor(desc: &mut DescriptorProto) {
    for desc in &mut desc.nested_type {
        normalize_descriptor(desc);
    }
    for desc in &mut desc.enum_type {
        normalize_enum_descriptor(desc);
    }
    for desc in &mut desc.oneof_decl {
        normalize_oneof_descriptor(desc);
    }

    desc.options.mut_or_default();

    // group are not supported
    desc.options.mut_or_default().unknown_fields.remove(7636463);

    for field in &mut desc.field {
        normalize_field(field);
    }

    for ext in &mut desc.extension {
        ext.options.mut_or_default();
    }

    for ext in &mut desc.extension_range {
        // If ext range end exceeds max field number,
        // the actual upper limit does not matter.
        // protoc is not consistent in behavior thus flush
        // the value to some arbitrary compatible value.
        if ext.has_end() && ext.get_end() >= 0x20000000 {
            ext.set_end(0x20000000);
        }
    }
}

fn normalize_method(method: &mut MethodDescriptorProto) {
    // TODO: do not clear
    method.clear_input_type();
    method.clear_output_type();

    method.options.mut_or_default();
}

fn normalize_service(service: &mut ServiceDescriptorProto) {
    for m in &mut service.method {
        normalize_method(m);
    }

    service.options.mut_or_default();
}

fn normalize_field(field: &mut FieldDescriptorProto) {
    field.options.mut_or_default();

    if field.has_default_value() {
        if field.get_field_type() == field_descriptor_proto::Type::TYPE_FLOAT {
            field.set_default_value(format!(
                "{}",
                parse_protobuf_float(field.get_default_value()).unwrap()
            ));
        }
    }
}

fn pretty_message<M: protobuf::Message>(message: &M) -> String {
    // TODO: pull this handy utility into the protobuf crate.
    struct FormatMessage<'a, M>(&'a M);

    impl<M: protobuf::Message> fmt::Display for FormatMessage<'_, M> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            protobuf::text_format::fmt(self.0, f)
        }
    }

    format!("{:#}", FormatMessage(message))
}

fn descriptor_for_file<'a>(fds: &'a FileDescriptorSet, file_name: &str) -> &'a FileDescriptorProto {
    for file in &fds.file {
        if Path::new(file.get_name()).file_name().unwrap()
            == Path::new(file_name).file_name().unwrap()
        {
            return file;
        }
    }
    panic!(
        "file not found: {}; all files: {}",
        file_name,
        fds.file
            .iter()
            .map(|f| f.get_name())
            .collect::<Vec<_>>()
            .join(", ")
    );
}

fn test_diff_in<F>(root: &str, sources_dir: &str, include: &str, should_skip: F)
where
    F: Fn(&str) -> bool,
{
    let mut stats = TestStats {
        passed: 0,
        passed_marked_skip: 0,
        skipped: 0,
        failed: 0,
    };

    let mut include_root = Path::new(root).to_path_buf();
    include_root.push(include);

    let include_full = format!("{}/{}", root, include);
    let s_full = format!("{}/{}", root, sources_dir);

    let inputs_glob = format!("{}/*.proto*", s_full);
    let inputs = to_paths(glob_simple(&inputs_glob));
    assert!(!inputs.is_empty(), "glob is empty: {}", inputs_glob);
    let includes = to_paths(vec![include_full.as_str(), "../proto"]);

    let temp_dir = tempfile::Builder::new()
        .prefix("protobuf-codegen-identical-test")
        .tempdir()
        .unwrap();

    let protoc_dir = format!("{}/protoc", temp_dir.path().to_str().unwrap());
    let pure_dir = format!("{}/pure", temp_dir.path().to_str().unwrap());

    fs::create_dir(&protoc_dir).unwrap();
    fs::create_dir(&pure_dir).unwrap();

    protoc_rust::Codegen::new()
        .protoc_path(protoc_bin_vendored::protoc_bin_path().unwrap())
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&protoc_dir)
        .run()
        .unwrap();

    protobuf_codegen_pure::Codegen::new()
        .inputs(&inputs)
        .includes(&includes)
        .out_dir(&pure_dir)
        .run()
        .unwrap();

    let mut protoc_descriptors = protoc_descriptor_set(&includes, &inputs);
    let mut pure_descriptors = pure_descriptor_set(&includes, &inputs);
    normalize_descriptor_set(&mut protoc_descriptors);
    normalize_descriptor_set(&mut pure_descriptors);

    for input in &inputs {
        let label = input.strip_prefix(root).unwrap().to_str().unwrap();
        let proto_file_name = input.strip_prefix(&include_root).unwrap().to_str().unwrap();
        let proto_name = input.file_name().unwrap().to_str().unwrap();
        let rs_name = protobuf_codegen::proto_name_to_rs(proto_name);
        let protoc_rs = format!("{}/{}", protoc_dir, rs_name);
        let pure_rs = format!("{}/{}", pure_dir, rs_name);

        normalize_generated_file_in_place(Path::new(&protoc_rs));
        normalize_generated_file_in_place(Path::new(&pure_rs));

        let protoc_rs_contents =
            fs::read_to_string(&protoc_rs).expect(&format!("while reading {}", protoc_rs));
        let pure_rs_contents =
            fs::read_to_string(&pure_rs).expect(&format!("while reading {}", pure_rs));

        let protoc_descriptor_for_file = descriptor_for_file(&protoc_descriptors, &proto_file_name);
        let pure_descriptor_for_file = descriptor_for_file(&pure_descriptors, &proto_file_name);

        let skip = should_skip(input.to_str().unwrap());
        if protoc_rs_contents == pure_rs_contents
            && protoc_descriptor_for_file == pure_descriptor_for_file
        {
            if !skip {
                stats.passed += 1;
                println!("{}: PASSED", label);
            } else {
                stats.passed_marked_skip += 1;
                println!("{}: PASSED BUT MARKED SKIP", label);
            }
        } else {
            if skip {
                stats.skipped += 1;
                println!("{} SKIPPED", label);
            } else {
                stats.failed += 1;
                println!("{} FAILED", label);
            }

            print_diff(
                temp_dir.path(),
                Path::new(&protoc_rs).strip_prefix(temp_dir.path()).unwrap(),
                Path::new(&pure_rs).strip_prefix(temp_dir.path()).unwrap(),
            );

            fs::write(
                format!("{}/{}.descriptors", protoc_dir, proto_name),
                pretty_message(protoc_descriptor_for_file),
            )
            .unwrap();
            fs::write(
                format!("{}/{}.descriptors", pure_dir, proto_name),
                pretty_message(pure_descriptor_for_file),
            )
            .unwrap();
            print_diff(
                temp_dir.path(),
                Path::new(&format!("protoc/{}.descriptors", proto_name)),
                Path::new(&format!("pure/{}.descriptors", proto_name)),
            );
        }
    }

    println!("{:?}", stats);
    assert!(stats.failed == 0, "at least one test failed");
}

fn should_skip_with_marker(path: &str) -> bool {
    fs::read_to_string(path)
        .unwrap()
        .contains("@skip-codegen-identical-test")
}

#[test]
fn common_v2() {
    test_diff_in(
        "../protobuf-test",
        "src/common/v2",
        "src/common/v2",
        should_skip_with_marker,
    );
}

#[test]
fn common_v3() {
    let common_v3_root = tempfile::Builder::new()
        .prefix("common-v3")
        .tempdir()
        .unwrap();
    fs::create_dir_all(format!(
        "{}/src/common/v3",
        common_v3_root.path().to_str().unwrap()
    ))
    .unwrap();

    copy_tests_v2_v3(
        "../protobuf-test/src/common/v2",
        &format!("{}/src/common/v3", common_v3_root.path().to_str().unwrap()),
    );

    test_diff_in(
        common_v3_root.path().to_str().unwrap(),
        "src/common/v3",
        "src/common/v3",
        should_skip_with_marker,
    );
}

#[test]
fn v2() {
    test_diff_in(
        "../protobuf-test",
        "src/v2",
        "src/v2",
        should_skip_with_marker,
    );
}

#[test]
fn v3() {
    test_diff_in(
        "../protobuf-test",
        "src/v3",
        "src/v3",
        should_skip_with_marker,
    );
}

#[test]
fn interop() {
    test_diff_in(
        "../protobuf-test",
        "../interop/cxx",
        "../interop/cxx",
        should_skip_with_marker,
    );
}

#[test]
fn google() {
    test_diff_in("../protobuf-test", "src/google/protobuf", "src", |_| false);
}
<|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::conversions::{ToJSValConvertible, root_from_handleobject};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::utils::WindowProxyHandler;
use dom::bindings::utils::get_array_index_from_id;
use dom::document::Document;
use dom::element::Element;
use dom::window::Window;
use js::JSCLASS_IS_GLOBAL;
use js::glue::{CreateWrapperProxyHandler, ProxyTraps, NewWindowProxy};
use js::glue::{GetProxyPrivate, SetProxyExtra};
use js::jsapi::{Handle, HandleId, HandleObject, HandleValue, JSAutoCompartment, JSAutoRequest};
use js::jsapi::{JSContext, JSPROP_READONLY, JSErrNum, JSObject, PropertyDescriptor, JS_DefinePropertyById};
use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass};
use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle};
use js::jsapi::{MutableHandleValue, ObjectOpResult, RootedObject, RootedValue};
use js::jsval::{UndefinedValue, PrivateValue};

#[dom_struct]
pub struct BrowsingContext {
    reflector: Reflector,
    history: DOMRefCell<Vec<SessionHistoryEntry>>,
    active_index: usize,
    frame_element: Option<JS<Element>>,
}

impl BrowsingContext {
    pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
        BrowsingContext {
            reflector: Reflector::new(),
            history: DOMRefCell::new(vec![]),
            active_index: 0,
            frame_element: frame_element.map(JS::from_ref),
        }
    }

    #[allow(unsafe_code)]
    pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
        unsafe {
            let WindowProxyHandler(handler) = window.windowproxy_handler();
            assert!(!handler.is_null());

            let cx = window.get_cx();
            let _ar = JSAutoRequest::new(cx);
            let parent = window.reflector().get_jsobject();
            assert!(!parent.get().is_null());
            assert!(((*JS_GetClass(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
            let _ac = JSAutoCompartment::new(cx, parent.get());
            let window_proxy = RootedObject::new(cx,
                NewWindowProxy(cx, parent, handler));
            assert!(!window_proxy.ptr.is_null());

            let object = box BrowsingContext::new_inherited(frame_element);

            let raw = Box::into_raw(object);
            SetProxyExtra(window_proxy.ptr, 0, &PrivateValue(raw as *const _));

            (*raw).init_reflector(window_proxy.ptr);

            Root::from_ref(&*raw)
        }
    }

    pub fn init(&self, document: &Document) {
        assert!(self.history.borrow().is_empty());
        assert_eq!(self.active_index, 0);
        self.history.borrow_mut().push(SessionHistoryEntry::new(document));
    }

    pub fn active_document(&self) -> Root<Document> {
        Root::from_ref(&*self.history.borrow()[self.active_index].document)
    }

    pub fn active_window(&self) -> Root<Window> {
        Root::from_ref(self.active_document().window())
    }

    pub fn frame_element(&self) -> Option<&Element> {
        self.frame_element.r()
    }

    pub fn window_proxy(&self) -> *mut JSObject {
        let window_proxy = self.reflector.get_jsobject();
        assert!(!window_proxy.get().is_null());
        window_proxy.get()
    }
}

// This isn't a DOM struct, just a convenience struct
// without a reflector, so we don't mark this as #[dom_struct]
#[must_root]
#[privatize]
#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
    document: JS<Document>,
    children: Vec<JS<BrowsingContext>>,
}

impl SessionHistoryEntry {
    fn new(document: &Document) -> SessionHistoryEntry {
        SessionHistoryEntry {
            document: JS::from_ref(document),
            children: vec![],
        }
    }
}

#[allow(unsafe_code)]
unsafe fn GetSubframeWindow(cx: *mut JSContext,
                            proxy: HandleObject,
                            id: HandleId)
                            -> Option<Root<Window>> {
    let index = get_array_index_from_id(cx, id);
    if let Some(index) = index {
        let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
        let win = root_from_handleobject::<Window>(target.handle()).unwrap();
        let mut found = false;
        return win.IndexedGetter(index, &mut found);
    }

    None
}

#[allow(unsafe_code)]
unsafe extern "C" fn getOwnPropertyDescriptor(cx: *mut JSContext,
                                              proxy: HandleObject,
                                              id: HandleId,
                                              desc: MutableHandle<PropertyDescriptor>)
                                              -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        let mut val = RootedValue::new(cx, UndefinedValue());
        window.to_jsval(cx, val.handle_mut());
        (*desc.ptr).value = val.ptr;
        fill_property_descriptor(&mut *desc.ptr, *proxy.ptr, JSPROP_READONLY);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    if !JS_GetOwnPropertyDescriptorById(cx, target.handle(), id, desc) {
        return false;
    }

    assert!(desc.get().obj.is_null() || desc.get().obj == target.ptr);
    if desc.get().obj == target.ptr {
        desc.get().obj = *proxy.ptr;
    }

    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn defineProperty(cx: *mut JSContext,
                                    proxy: HandleObject,
                                    id: HandleId,
                                    desc: Handle<PropertyDescriptor>,
                                    res: *mut ObjectOpResult)
                                    -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Spec says to Reject whether this is a supported index or not,
        // since we have no indexed setter or indexed creator.  That means
        // throwing in strict mode (FIXME: Bug 828137), doing nothing in
        // non-strict mode.
        (*res).code_ = JSErrNum::JSMSG_CANT_DEFINE_WINDOW_ELEMENT as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_DefinePropertyById(cx, target.handle(), id, desc, res)
}

#[allow(unsafe_code)]
unsafe extern "C" fn has(cx: *mut JSContext,
                         proxy: HandleObject,
                         id: HandleId,
                         bp: *mut bool)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if window.is_some() {
        *bp = true;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    let mut found = false;
    if !JS_HasPropertyById(cx, target.handle(), id, &mut found) {
        return false;
    }

    *bp = found;
    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn get(cx: *mut JSContext,
                         proxy: HandleObject,
                         receiver: HandleValue,
                         id: HandleId,
                         vp: MutableHandleValue)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        window.to_jsval(cx, vp);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_ForwardGetPropertyTo(cx, target.handle(), id, receiver, vp)
}

#[allow(unsafe_code)]
unsafe extern "C" fn set(cx: *mut JSContext,
                         proxy: HandleObject,
                         id: HandleId,
                         v: HandleValue,
                         receiver: HandleValue,
                         res: *mut ObjectOpResult)
                         -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Reject (which means throw if and only if strict) the set.
        (*res).code_ = JSErrNum::JSMSG_READ_ONLY as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_ForwardSetPropertyTo(cx,
                            target.handle(),
                            id,
                            v,
                            receiver,
                            res)
}

static PROXY_HANDLER: ProxyTraps = ProxyTraps {
    enter: None,
    getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
    defineProperty: Some(defineProperty),
    ownPropertyKeys: None,
    delete_: None,
    enumerate: None,
    preventExtensions: None,
    isExtensible: None,
    has: Some(has),
    get: Some(get),
    set: Some(set),
    call: None,
    construct: None,
    getPropertyDescriptor: Some(get_property_descriptor),
    hasOwn: None,
    getOwnEnumerablePropertyKeys: None,
    nativeCall: None,
    hasInstance: None,
    objectClassIs: None,
    className: None,
    fun_toString: None,
    boxedValue_unbox: None,
    defaultValue: None,
    trace: None,
    finalize: None,
    objectMoved: None,
    isCallable: None,
    isConstructor: None,
};

#[allow(unsafe_code)]
pub fn new_window_proxy_handler() -> WindowProxyHandler {
    unsafe {
        WindowProxyHandler(CreateWrapperProxyHandler(&PROXY_HANDLER))
    }
}
<commit_msg>Ensure that the fields of BrowsingContext are traced and the Rust object is freed when the reflector is finalized.<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::conversions::{ToJSValConvertible, root_from_handleobject};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::WindowProxyHandler;
use dom::bindings::utils::get_array_index_from_id;
use dom::document::Document;
use dom::element::Element;
use dom::window::Window;
use js::JSCLASS_IS_GLOBAL;
use js::glue::{CreateWrapperProxyHandler, ProxyTraps, NewWindowProxy};
use js::glue::{GetProxyPrivate, SetProxyExtra, GetProxyExtra};
use js::jsapi::{Handle, HandleId, HandleObject, HandleValue, JSAutoCompartment, JSAutoRequest};
use js::jsapi::{JSContext, JSPROP_READONLY, JSErrNum, JSObject, PropertyDescriptor, JS_DefinePropertyById};
use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass, JSTracer, FreeOp};
use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle};
use js::jsapi::{MutableHandleValue, ObjectOpResult, RootedObject, RootedValue};
use js::jsval::{UndefinedValue, PrivateValue};

#[dom_struct]
pub struct BrowsingContext {
    reflector: Reflector,
    history: DOMRefCell<Vec<SessionHistoryEntry>>,
    active_index: usize,
    frame_element: Option<JS<Element>>,
}

impl BrowsingContext {
    pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
        BrowsingContext {
            reflector: Reflector::new(),
            history: DOMRefCell::new(vec![]),
            active_index: 0,
            frame_element: frame_element.map(JS::from_ref),
        }
    }

    #[allow(unsafe_code)]
    pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
        unsafe {
            let WindowProxyHandler(handler) = window.windowproxy_handler();
            assert!(!handler.is_null());

            let cx = window.get_cx();
            let _ar = JSAutoRequest::new(cx);
            let parent = window.reflector().get_jsobject();
            assert!(!parent.get().is_null());
            assert!(((*JS_GetClass(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
            let _ac = JSAutoCompartment::new(cx, parent.get());
            let window_proxy = RootedObject::new(cx,
                NewWindowProxy(cx, parent, handler));
            assert!(!window_proxy.ptr.is_null());

            let object = box BrowsingContext::new_inherited(frame_element);

            let raw = Box::into_raw(object);
            SetProxyExtra(window_proxy.ptr, 0, &PrivateValue(raw as *const _));

            (*raw).init_reflector(window_proxy.ptr);

            Root::from_ref(&*raw)
        }
    }

    pub fn init(&self, document: &Document) {
        assert!(self.history.borrow().is_empty());
        assert_eq!(self.active_index, 0);
        self.history.borrow_mut().push(SessionHistoryEntry::new(document));
    }

    pub fn active_document(&self) -> Root<Document> {
        Root::from_ref(&*self.history.borrow()[self.active_index].document)
    }

    pub fn active_window(&self) -> Root<Window> {
        Root::from_ref(self.active_document().window())
    }

    pub fn frame_element(&self) -> Option<&Element> {
        self.frame_element.r()
    }

    pub fn window_proxy(&self) -> *mut JSObject {
        let window_proxy = self.reflector.get_jsobject();
        assert!(!window_proxy.get().is_null());
        window_proxy.get()
    }
}

// This isn't a DOM struct, just a convenience struct
// without a reflector, so we don't mark this as #[dom_struct]
#[must_root]
#[privatize]
#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
    document: JS<Document>,
    children: Vec<JS<BrowsingContext>>,
}

impl SessionHistoryEntry {
    fn new(document: &Document) -> SessionHistoryEntry {
        SessionHistoryEntry {
            document: JS::from_ref(document),
            children: vec![],
        }
    }
}

#[allow(unsafe_code)]
unsafe fn GetSubframeWindow(cx: *mut JSContext,
                            proxy: HandleObject,
                            id: HandleId)
                            -> Option<Root<Window>> {
    let index = get_array_index_from_id(cx, id);
    if let Some(index) = index {
        let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
        let win = root_from_handleobject::<Window>(target.handle()).unwrap();
        let mut found = false;
        return win.IndexedGetter(index, &mut found);
    }

    None
}

#[allow(unsafe_code)]
unsafe extern "C" fn getOwnPropertyDescriptor(cx: *mut JSContext,
                                              proxy: HandleObject,
                                              id: HandleId,
                                              desc: MutableHandle<PropertyDescriptor>)
                                              -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        let mut val = RootedValue::new(cx, UndefinedValue());
        window.to_jsval(cx, val.handle_mut());
        (*desc.ptr).value = val.ptr;
        fill_property_descriptor(&mut *desc.ptr, *proxy.ptr, JSPROP_READONLY);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    if !JS_GetOwnPropertyDescriptorById(cx, target.handle(), id, desc) {
        return false;
    }

    assert!(desc.get().obj.is_null() || desc.get().obj == target.ptr);
    if desc.get().obj == target.ptr {
        desc.get().obj = *proxy.ptr;
    }

    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn defineProperty(cx: *mut JSContext,
                                    proxy: HandleObject,
                                    id: HandleId,
                                    desc: Handle<PropertyDescriptor>,
                                    res: *mut ObjectOpResult)
                                    -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Spec says to Reject whether this is a supported index or not,
        // since we have no indexed setter or indexed creator.  That means
        // throwing in strict mode (FIXME: Bug 828137), doing nothing in
        // non-strict mode.
        (*res).code_ = JSErrNum::JSMSG_CANT_DEFINE_WINDOW_ELEMENT as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_DefinePropertyById(cx, target.handle(), id, desc, res)
}

#[allow(unsafe_code)]
unsafe extern "C" fn has(cx: *mut JSContext,
                         proxy: HandleObject,
                         id: HandleId,
                         bp: *mut bool)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if window.is_some() {
        *bp = true;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    let mut found = false;
    if !JS_HasPropertyById(cx, target.handle(), id, &mut found) {
        return false;
    }

    *bp = found;
    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn get(cx: *mut JSContext,
                         proxy: HandleObject,
                         receiver: HandleValue,
                         id: HandleId,
                         vp: MutableHandleValue)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        window.to_jsval(cx, vp);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_ForwardGetPropertyTo(cx, target.handle(), id, receiver, vp)
}

#[allow(unsafe_code)]
unsafe extern "C" fn set(cx: *mut JSContext,
                         proxy: HandleObject,
                         id: HandleId,
                         v: HandleValue,
                         receiver: HandleValue,
                         res: *mut ObjectOpResult)
                         -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Reject (which means throw if and only if strict) the set.
        (*res).code_ = JSErrNum::JSMSG_READ_ONLY as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_ForwardSetPropertyTo(cx,
                            target.handle(),
                            id,
                            v,
                            receiver,
                            res)
}

static PROXY_HANDLER: ProxyTraps = ProxyTraps {
    enter: None,
    getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
    defineProperty: Some(defineProperty),
    ownPropertyKeys: None,
    delete_: None,
    enumerate: None,
    preventExtensions: None,
    isExtensible: None,
    has: Some(has),
    get: Some(get),
    set: Some(set),
    call: None,
    construct: None,
    getPropertyDescriptor: Some(get_property_descriptor),
    hasOwn: None,
    getOwnEnumerablePropertyKeys: None,
    nativeCall: None,
    hasInstance: None,
    objectClassIs: None,
    className: None,
    fun_toString: None,
    boxedValue_unbox: None,
    defaultValue: None,
    trace: Some(trace),
    finalize: Some(finalize),
    objectMoved: None,
    isCallable: None,
    isConstructor: None,
};

#[allow(unsafe_code)]
unsafe extern fn finalize(_fop: *mut FreeOp, obj: *mut JSObject) {
    let this = GetProxyExtra(obj, 0).to_private() as *mut BrowsingContext;
    assert!(!this.is_null());
    let _ = Box::from_raw(this);
    debug!("BrowsingContext finalize: {:p}", this);
}

#[allow(unsafe_code)]
unsafe extern fn trace(trc: *mut JSTracer, obj: *mut JSObject) {
    let this = GetProxyExtra(obj, 0).to_private() as *const BrowsingContext;
    if this.is_null() {
        // GC during obj creation
        return;
    }
    (*this).trace(trc);
}

#[allow(unsafe_code)]
pub fn new_window_proxy_handler() -> WindowProxyHandler {
    unsafe {
        WindowProxyHandler(CreateWrapperProxyHandler(&PROXY_HANDLER))
    }
}
<|endoftext|>


<commit_before>use event::{Action, MouseButton, WindowEvent};
use na::{self, Matrix3, Point2, Translation2, Vector2};
use num::Pow;
use planar_camera::PlanarCamera;
use resource::ShaderUniform;
use std::f32;
use window::Canvas;

/// A 2D camera that can be zoomed and panned.
#[derive(Clone, Debug)]
pub struct Sidescroll {
    at: Point2<f32>,
    /// Distance from the camera to the `at` focus point.
    zoom: f32,

    /// Increment of the zoomance per unit scrolling. The default value is 40.0.
    zoom_step: f32,
    drag_button: Option<MouseButton>,

    view: Matrix3<f32>,
    proj: Matrix3<f32>,
    scaled_proj: Matrix3<f32>,
    inv_scaled_proj: Matrix3<f32>,
    last_cursor_pos: Vector2<f32>,
}

impl Sidescroll {
    /// Create a new arc-ball camera.
    pub fn new() -> Sidescroll {
        let mut res = Sidescroll {
            at: Point2::origin(),
            zoom: 1.0,
            zoom_step: 0.9,
            drag_button: Some(MouseButton::Button2),
            view: na::one(),
            proj: na::one(),
            scaled_proj: na::one(),
            inv_scaled_proj: na::one(),
            last_cursor_pos: na::zero(),
        };

        res.update_projviews();

        res
    }

    /// The point the arc-ball is looking at.
    pub fn at(&self) -> Point2<f32> {
        self.at
    }

    /// Get a mutable reference to the point the camera is looking at.
    pub fn set_at(&mut self, at: Point2<f32>) {
        self.at = at;
        self.update_projviews();
    }

    /// Gets the zoom of the camera.
    pub fn zoom(&self) -> f32 {
        self.zoom
    }

    /// Sets the zoom of the camera.
    pub fn set_zoom(&mut self, zoom: f32) {
        self.zoom = zoom;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Move the camera such that it is centered on a specific point.
    pub fn look_at(&mut self, at: Point2<f32>, zoom: f32) {
        self.at = at;
        self.zoom = zoom;
        self.update_projviews();
    }

    /// Transformation applied by the camera without perspective.
    fn update_restrictions(&mut self) {
        if self.zoom < 0.00001 {
            self.zoom = 0.00001
        }
    }

    /// The button used to drag the Sidescroll camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the Sidescroll camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.at.x += dpos.x / self.zoom;
        self.at.y -= dpos.y / self.zoom;
        self.update_projviews();
    }

    fn handle_scroll(&mut self, off: f32) {
        self.zoom = self.zoom / self.zoom_step.pow(off / 120.0);
        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        self.view = Translation2::new(self.at.x, self.at.y).to_homogeneous();
        self.scaled_proj = self.proj;
        self.scaled_proj.m11 *= self.zoom;
        self.scaled_proj.m22 *= self.zoom;

        self.inv_scaled_proj.m11 = 1.0 / self.scaled_proj.m11;
        self.inv_scaled_proj.m22 = 1.0 / self.scaled_proj.m22;
    }
}

impl PlanarCamera for Sidescroll {
    fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
        let hidpi = 1.0; // canvas.hidpi_factor();

        match *event {
            WindowEvent::CursorPos(x, y, _) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(drag_button) = self.drag_button {
                    if canvas.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            }
            WindowEvent::Scroll(_, off, _) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.proj = Matrix3::new(
                    2.0 * (hidpi as f32) / (w as f32),
                    0.0,
                    0.0,
                    0.0,
                    2.0 * (hidpi as f32) / (h as f32),
                    0.0,
                    0.0,
                    0.0,
                    1.0,
                );
                self.update_projviews();
            }
            _ => {}
        }
    }

    #[inline]
    fn upload(
        &self,
        proj: &mut ShaderUniform<Matrix3<f32>>,
        view: &mut ShaderUniform<Matrix3<f32>>,
    ) {
        proj.upload(&self.scaled_proj);
        view.upload(&self.view);
    }

    fn update(&mut self, _: &Canvas) {}

    fn unproject(&self, window_coord: &Point2<f32>, size: &Vector2<f32>) -> Point2<f32> {
        let normalized_coords = Point2::new(
            2.0 * window_coord.x / size.x - 1.0,
            2.0 * -window_coord.y / size.y + 1.0,
        );

        let unprojected_hom = self.inv_scaled_proj * normalized_coords.to_homogeneous();
        Point2::from_homogeneous(unprojected_hom).unwrap() - self.at.coords
    }
}
<commit_msg>Updated view matrix to negate look at positions<commit_after>use event::{Action, MouseButton, WindowEvent};
use na::{self, Matrix3, Point2, Translation2, Vector2};
use num::Pow;
use planar_camera::PlanarCamera;
use resource::ShaderUniform;
use std::f32;
use window::Canvas;

/// A 2D camera that can be zoomed and panned.
#[derive(Clone, Debug)]
pub struct Sidescroll {
    at: Point2<f32>,
    /// Distance from the camera to the `at` focus point.
    zoom: f32,

    /// Increment of the zoomance per unit scrolling. The default value is 40.0.
    zoom_step: f32,
    drag_button: Option<MouseButton>,

    view: Matrix3<f32>,
    proj: Matrix3<f32>,
    scaled_proj: Matrix3<f32>,
    inv_scaled_proj: Matrix3<f32>,
    last_cursor_pos: Vector2<f32>,
}

impl Sidescroll {
    /// Create a new arc-ball camera.
    pub fn new() -> Sidescroll {
        let mut res = Sidescroll {
            at: Point2::origin(),
            zoom: 1.0,
            zoom_step: 0.9,
            drag_button: Some(MouseButton::Button2),
            view: na::one(),
            proj: na::one(),
            scaled_proj: na::one(),
            inv_scaled_proj: na::one(),
            last_cursor_pos: na::zero(),
        };

        res.update_projviews();

        res
    }

    /// The point the arc-ball is looking at.
    pub fn at(&self) -> Point2<f32> {
        self.at
    }

    /// Get a mutable reference to the point the camera is looking at.
    pub fn set_at(&mut self, at: Point2<f32>) {
        self.at = at;
        self.update_projviews();
    }

    /// Gets the zoom of the camera.
    pub fn zoom(&self) -> f32 {
        self.zoom
    }

    /// Sets the zoom of the camera.
    pub fn set_zoom(&mut self, zoom: f32) {
        self.zoom = zoom;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Move the camera such that it is centered on a specific point.
    pub fn look_at(&mut self, at: Point2<f32>, zoom: f32) {
        self.at = at;
        self.zoom = zoom;
        self.update_projviews();
    }

    /// Transformation applied by the camera without perspective.
    fn update_restrictions(&mut self) {
        if self.zoom < 0.00001 {
            self.zoom = 0.00001
        }
    }

    /// The button used to drag the Sidescroll camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the Sidescroll camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// Move the camera based on drag from right mouse button
    /// `dpos` is assumed to be in window space so the y-axis is flipped
    fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.at.x -= dpos.x / self.zoom;
        self.at.y += dpos.y / self.zoom;
        self.update_projviews();
    }

    fn handle_scroll(&mut self, off: f32) {
        self.zoom = self.zoom / self.zoom_step.pow(off / 120.0);
        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        self.view = Translation2::new(-self.at.x, -self.at.y).to_homogeneous();
        self.scaled_proj = self.proj;
        self.scaled_proj.m11 *= self.zoom;
        self.scaled_proj.m22 *= self.zoom;

        self.inv_scaled_proj.m11 = 1.0 / self.scaled_proj.m11;
        self.inv_scaled_proj.m22 = 1.0 / self.scaled_proj.m22;
    }
}

impl PlanarCamera for Sidescroll {
    fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
        let hidpi = 1.0; // canvas.hidpi_factor();

        match *event {
            WindowEvent::CursorPos(x, y, _) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(drag_button) = self.drag_button {
                    if canvas.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            }
            WindowEvent::Scroll(_, off, _) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.proj = Matrix3::new(
                    2.0 * (hidpi as f32) / (w as f32),
                    0.0,
                    0.0,
                    0.0,
                    2.0 * (hidpi as f32) / (h as f32),
                    0.0,
                    0.0,
                    0.0,
                    1.0,
                );
                self.update_projviews();
            }
            _ => {}
        }
    }

    #[inline]
    fn upload(
        &self,
        proj: &mut ShaderUniform<Matrix3<f32>>,
        view: &mut ShaderUniform<Matrix3<f32>>,
    ) {
        proj.upload(&self.scaled_proj);
        view.upload(&self.view);
    }

    fn update(&mut self, _: &Canvas) {}

    /// Calculate the global position of the given window coordinate
    fn unproject(&self, window_coord: &Point2<f32>, size: &Vector2<f32>) -> Point2<f32> {
        // Convert window coordinates (origin at top left) to normalized screen coordinates
        // (origin at the center of the screen)
        let normalized_coords = Point2::new(
            2.0 * window_coord.x / size.x - 1.0,
            2.0 * -window_coord.y / size.y + 1.0,
        );

        // Project normalized screen coordinate to screen space
        let unprojected_hom = self.inv_scaled_proj * normalized_coords.to_homogeneous();

        // Convert from screen space to global space
        Point2::from_homogeneous(unprojected_hom).unwrap() + self.at.coords
    }
}
<|endoftext|>


<commit_before>use basetypes::*;

// "CastlingRights" holds information about which player (white or
// black) is allowed to castle on which side (queen-side or
// king-side).
//
// The lowest 4 bits of the value contain the whole needed
// information. It is laid out the following way:
//
//  usize                                             4           0
//  +-----------------------------------------------+---+---+---+---+
//  |                                               |   |   |   |   |
//  |                   Unused                      | Castling mask |
//  |                                               |   |   |   |   |
//  +-----------------------------------------------+---+---+---+---+
//
//  bit 0 -- if set, white can castle on queen-side;
//  bit 1 -- if set, white can castle on king-side;
//  bit 2 -- if set, black can castle on queen-side;
//  bit 3 -- if set, black can castle on king-side.
#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct CastlingRights(usize);

impl CastlingRights {
    // Create a new instance.
    #[inline(always)]
    pub fn new() -> CastlingRights {
        CastlingRights(0)
    }

    // Get the contained raw value.
    #[inline(always)]
    pub fn get_value(&self) -> usize {
        self.0
    }

    // Grant castling rights according to a given 4-bit mask (bit-wise
    // OR-ing the previous value with "mask").
    //
    // Returns which bits were zero before, and were turned to one.
    pub fn grant(&mut self, mask: usize) -> usize {
        if mask > 0b1111 {
            panic!("invalid mask");
        }
        let before = self.0;
        self.0 |= mask;
        !before & mask
    }

    // Update the castling rights with a 4-bit mask (bit-wise AND-ing
    // the previous value with "mask").
    #[inline(always)]
    pub fn update_with_mask(&mut self, mask: usize) {
        self.0 &= mask;
    }

    // Return if the player "color" can castle on the given "side".
    #[inline(always)]
    pub fn can_castle(&self, color: Color, side: CastlingSide) -> bool {
        assert!(color <= 1);
        assert!(side <= 1);
        (1 << (color << 1) << side) & self.0 != 0
    }

    // Return a bitboard with the set of squares that should be vacant
    // in order for the specified ("color", "side") castling move to
    // be possible.
    #[inline(always)]
    pub fn obstacles(&self, color: Color, side: CastlingSide) -> u64 {
        const OBSTACLES: [[u64; 2]; 2] = [[1 << B1 | 1 << C1 | 1 << D1, 1 << F1 | 1 << G1],
                                          [1 << B8 | 1 << C8 | 1 << D8, 1 << F8 | 1 << G8]];
        if self.can_castle(color, side) {
            OBSTACLES[color][side]
        } else {
            // Castling is not allowed, therefore every piece on every
            // square on the board can be considered an obstacle.
            UNIVERSAL_SET
        }
    }

    // Return a 2-bit value representing the castling rights for the
    // player "color".
    #[inline(always)]
    pub fn get_for(&self, color: Color) -> usize {
        assert!(color <= 1);
        if color == WHITE {
            self.0 & 0b0011
        } else {
            self.0 >> 2
        }
    }

    // Set the castling rights for the player "color" with a 2-bit
    // value ("rights").
    #[inline(always)]
    pub fn set_for(&mut self, color: Color, rights: usize) {
        assert!(color <= 1);
        assert!(rights <= 0b11);

        // Since the raw value of "CastlingRights" frequently is used
        // as an array index without boundary checking, we guarantee
        // that the raw value is always less than 16 by sanitizing the
        // passed "rights".
        self.0 = if color == WHITE {
            self.0 & 0b1100 | rights & 0b0011
        } else {
            self.0 & 0b0011 | (rights & 0b0011) << 2
        }
    }
}

// Castling flags
pub const CASTLE_WHITE_QUEENSIDE: usize = 1 << 0;
pub const CASTLE_WHITE_KINGSIDE: usize = 1 << 1;
pub const CASTLE_BLACK_QUEENSIDE: usize = 1 << 2;
pub const CASTLE_BLACK_KINGSIDE: usize = 1 << 3;
<commit_msg>minor beautification<commit_after>use basetypes::*;

// "CastlingRights" holds information about which player (white or
// black) is allowed to castle on which side (queen-side or
// king-side).
//
// The lowest 4 bits of the value contain the whole needed
// information. It is laid out the following way:
//
//  usize                                             4           0
//  +-----------------------------------------------+---+---+---+---+
//  |                                               |   |   |   |   |
//  |                   Unused                      | Castling mask |
//  |                                               |   |   |   |   |
//  +-----------------------------------------------+---+---+---+---+
//
//  bit 0 -- if set, white can castle on queen-side;
//  bit 1 -- if set, white can castle on king-side;
//  bit 2 -- if set, black can castle on queen-side;
//  bit 3 -- if set, black can castle on king-side.
#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct CastlingRights(usize);

impl CastlingRights {
    // Create a new instance.
    #[inline(always)]
    pub fn new() -> CastlingRights {
        CastlingRights(0)
    }

    // Get the contained raw value.
    #[inline(always)]
    pub fn get_value(&self) -> usize {
        self.0
    }

    // Grant castling rights according to a given 4-bit mask (bit-wise
    // OR-ing the previous value with "mask").
    //
    // Returns which bits were zero before, and were turned to one.
    pub fn grant(&mut self, mask: usize) -> usize {
        if mask > 0b1111 {
            panic!("invalid mask");
        }
        let before = self.0;
        self.0 |= mask;
        !before & mask
    }

    // Update the castling rights with a 4-bit mask (bit-wise AND-ing
    // the previous value with "mask").
    #[inline(always)]
    pub fn update_with_mask(&mut self, mask: usize) {
        self.0 &= mask;
    }

    // Return if the player "color" can castle on the given "side".
    #[inline(always)]
    pub fn can_castle(&self, color: Color, side: CastlingSide) -> bool {
        assert!(color <= 1);
        assert!(side <= 1);
        (1 << (color << 1) << side) & self.0 != 0
    }

    // Return a bitboard with the set of squares that should be vacant
    // in order for the specified ("color", "side") castling move to
    // be possible.
    #[inline(always)]
    pub fn obstacles(&self, color: Color, side: CastlingSide) -> u64 {
        const OBSTACLES: [[u64; 2]; 2] = [[1 << B1 | 1 << C1 | 1 << D1, 1 << F1 | 1 << G1],
                                          [1 << B8 | 1 << C8 | 1 << D8, 1 << F8 | 1 << G8]];
        if self.can_castle(color, side) {
            OBSTACLES[color][side]
        } else {
            // Castling is not allowed, therefore every piece on every
            // square on the board can be considered an obstacle.
            UNIVERSAL_SET
        }
    }

    // Return a 2-bit value representing the castling rights for the
    // player "color".
    #[inline(always)]
    pub fn get_for(&self, color: Color) -> usize {
        assert!(color <= 1);
        if color == WHITE {
            self.0 & 0b0011
        } else {
            self.0 >> 2
        }
    }

    // Set the castling rights for the player "color" with a 2-bit
    // value ("rights").
    #[inline(always)]
    pub fn set_for(&mut self, color: Color, rights: usize) {
        assert!(color <= 1);
        if rights > 0b11 {
            // Since the raw value of "CastlingRights" frequently is used
            // as an array index without boundary checking, we guarantee
            // that the raw value is always less than 16 by sanitizing the
            // passed "rights".
            panic!("invalid castling rights");
        }
        self.0 = if color == WHITE {
            self.0 & 0b1100 | rights
        } else {
            self.0 & 0b0011 | rights << 2
        }
    }
}

// Castling flags
pub const CASTLE_WHITE_QUEENSIDE: usize = 1 << 0;
pub const CASTLE_WHITE_KINGSIDE: usize = 1 << 1;
pub const CASTLE_BLACK_QUEENSIDE: usize = 1 << 2;
pub const CASTLE_BLACK_KINGSIDE: usize = 1 << 3;
<|endoftext|>


<commit_before>use super::Renderer;
use super::shaders::make_program_from_shaders;
use rendering::primitives::rectangle::{Rectangle, RectangleVertex};
use rendering::primitives::circle_part::{CirclePart, CircleVertex};
use rendering::primitives::polygon::{Polygon, PolygonVertex};
use rendering::primitives::text::{RenderText, TextBuffer, PlainText};
use rendering::primitives::polar_pixel::{PolarBuffer, PolarPixel, PolarPixelVertex};
use rendering::primitives::{Primitive, TextureRect};
use rendering::renderables::Renderable;
use rendering::DisplaySettings;
use super::glium_buffer::{GliumBuffer, BasicBuffer};
use super::render_by_shaders::GliumPrimitive;
use super::{BezierRect, BezierSubrect};
use glium;
use glium::Frame;
use glium::{Display, Surface, DrawParameters, Depth, DepthTest, Program};
use glium::texture;
use glium::glutin::EventsLoop;
use std::io::Cursor;
use na;
use na::Matrix4;
use num::One;
use rusttype;
use games::view_details;
use utils::transforms_2d;
use debug::*;
use image;

pub struct GliumRenderer<'a> {
    display: Box<Display>,
    events_loop: Box<EventsLoop>,
    draw_params: DrawParameters<'a>,
    rect_buffer: BasicBuffer<Rectangle>,
    texture_rect_buffer: BasicBuffer<TextureRect>,
    circ_buffer: BasicBuffer<CirclePart>,
    polygon_buffer: BasicBuffer<Polygon>,
    bezier_rect_buffer: BasicBuffer<BezierRect>,
    bezier_subrect_buffer: BasicBuffer<BezierSubrect>,
    polar_buffer: PolarBuffer,
    text_processor: TextBuffer<'a, PlainText>,
    view_details: view_details::ViewDetails,
    display_settings: DisplaySettings,
    texture_array: texture::texture2d_array::Texture2dArray
}

impl<'a> GliumRenderer<'a> {
    pub fn new(settings: DisplaySettings) -> GliumRenderer<'a> {
        let (display, events_loop) = Self::build_display_and_events_loop(settings);

        let draw_params = DrawParameters {
            depth: Depth {
                test: DepthTest::IfLessOrEqual,
                write: true,..Default::default()
            },
            ..Default::default()
        };

        GliumRenderer {
            display: Box::new(display.clone()),
            events_loop: Box::new(events_loop),
            draw_params: draw_params,
            rect_buffer: BasicBuffer::<Rectangle>::new(&display),
            texture_rect_buffer: BasicBuffer::<TextureRect>::new(&display),
            circ_buffer: BasicBuffer::<CirclePart>::new(&display),
            polygon_buffer: BasicBuffer::<Polygon>::new(&display),
            bezier_rect_buffer: BasicBuffer::<BezierRect>::new(&display),
            bezier_subrect_buffer: BasicBuffer::<BezierSubrect>::new(&display),
            polar_buffer: PolarBuffer::new(&display),
            text_processor: TextBuffer::new(&display, settings),
            view_details: view_details::ViewDetails::TwoDim(view_details::ViewDetails2D::default()),
            display_settings: settings,
            texture_array: texture::texture2d_array::Texture2dArray::empty(&display, 1024, 1024, 1).unwrap()
        }
    }

    pub fn reset(&mut self, settings: DisplaySettings) {
        let window = Self::build_window(settings, &self.events_loop);

        let context = Self::build_context(settings);

        self.display.rebuild(window, context, &self.events_loop).unwrap();
    }

    fn reset_buffers(&mut self) {
        let display = &self.display;
        self.rect_buffer = BasicBuffer::<Rectangle>::new(display);
        self.texture_rect_buffer = BasicBuffer::<TextureRect>::new(display);
        self.circ_buffer = BasicBuffer::<CirclePart>::new(display);
        self.polygon_buffer = BasicBuffer::<Polygon>::new(display);
        self.bezier_rect_buffer = BasicBuffer::<BezierRect>::new(display);
        self.bezier_subrect_buffer = BasicBuffer::<BezierSubrect>::new(display);
        self.polar_buffer = PolarBuffer::new(display);
        self.text_processor = TextBuffer::new(display, self.display_settings);
    }

    fn build_display_and_events_loop(settings: DisplaySettings) -> (Display, EventsLoop) {
        let events_loop = glium::glutin::EventsLoop::new();

        let window = Self::build_window(settings, &events_loop);

        let context = Self::build_context(settings);
        let display = glium::Display::new(window, context, &events_loop).unwrap();

        (display, events_loop)
    }

    fn build_window(settings: DisplaySettings, events_loop: &glium::glutin::EventsLoop) -> glium::glutin::WindowBuilder {
        let mut window = glium::glutin::WindowBuilder::new()
            .with_dimensions(settings.res.0, settings.res.1);

        if settings.fullscreen {
            window = window.with_fullscreen(Some(events_loop.get_primary_monitor()));
        }

        window
    }

    fn build_context(settings: DisplaySettings) -> glium::glutin::ContextBuilder<'a> {
        glium::glutin::ContextBuilder::new().with_multisampling(settings.multisample_level)
    }

    fn flush_buffers(&mut self) {
        self.rect_buffer.flush_buffer();
        self.texture_rect_buffer.flush_buffer();
        self.circ_buffer.flush_buffer();
        self.polar_buffer.flush_buffer();
        self.polygon_buffer.flush_buffer();
        self.bezier_rect_buffer.flush_buffer();
        self.bezier_subrect_buffer.flush_buffer();
        self.text_processor.flush_buffer();
    }

    pub fn create_worldview_mat(view_details: view_details::ViewDetails, aspect_ratio: f64) ->  [[f32;4]; 4] {
        let view_mat = match
            view_details {
                view_details::ViewDetails::TwoDim(ref view) =>
                transforms_2d::build_worldview_mat(
                    view.camera_pos,
                    view.viewport_height,
                    aspect_ratio,
                    view.up_vector,
                    view.use_aspect_ratio),
                view_details::ViewDetails::ThreeDim(_) => panic!("3D mode not supported!"),
                _ => Matrix4::one()
            };
        let single_mat: Matrix4<f32> = na::convert(view_mat);
        *single_mat.as_ref()
    }
}

impl<'a> Renderer for GliumRenderer<'a> {
    fn load_renderables(&mut self, renderables: Vec<Box<Renderable>>) {
        debug_clock_start("Render::glium_load");
        for mut renderable in renderables {
            for primitive in renderable.get_primitives() {
                match primitive {
                        Primitive::Rect(rectangle) => self.rect_buffer.load_renderable(rectangle),
                        Primitive::TextureRect(rect) => self.texture_rect_buffer.load_renderable(rect),
                        Primitive::Circ(circle) => self.circ_buffer.load_renderable(circle),
                        Primitive::Text(text) => self.text_processor.load_renderable(text),
                        Primitive::BezierRect(bezier_rect) => self.bezier_rect_buffer.load_renderable(bezier_rect),
                        Primitive::BezierSubrect(bezier_subrect) => self.bezier_subrect_buffer.load_renderable(bezier_subrect),
                        Primitive::PolarPix(polar) => self.polar_buffer.load_renderable(polar),
                        Primitive::Poly(polygon) => self.polygon_buffer.load_renderable(polygon)
                }
            }
        }
        debug_clock_stop("Render::glium_load");
    }

    fn render(&mut self) {
        debug_clock_start("Render::glium_render");
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        target.clear_depth(1.0);

        let (width, height) = target.get_dimensions();
        let aspect_ratio = width as f64 / height as f64;

        {
            let uniforms = uniform! {
                screen_width: width,
                screen_height: height,
                aspect_ratio: aspect_ratio as f32,
                world_view: GliumRenderer::create_worldview_mat(self.view_details, aspect_ratio),
                tex: &self.texture_array
            };

            self.rect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.texture_rect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.circ_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.polygon_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.bezier_rect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.bezier_subrect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.polar_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.text_processor.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);

            target.finish().unwrap();
        }

        self.flush_buffers();
        debug_clock_stop("Render::glium_render");
    }

    fn set_worldview(&mut self, view_details: view_details::ViewDetails) {
        self.view_details = view_details;
    }

    fn get_events_loop(&mut self) -> Option<&mut EventsLoop> {
        Some(&mut self.events_loop)
    }

    fn get_window_spec(&self) -> super::WindowSpec {
        let (width, height) = self.display.gl_window().get_inner_size().unwrap();

        super::WindowSpec {
            aspect_ratio: width as f64 / height as f64
        }
    }
}

pub fn build_renderer_with_textures<T: glium::texture::PixelValue>(settings: DisplaySettings, texture_array: Vec<texture::RawImage2d<T>>) -> GliumRenderer {
    let mut renderer = GliumRenderer::new(settings);

    let texture = glium::texture::texture2d_array::Texture2dArray::new(renderer.display.as_ref(), texture_array).unwrap();

    renderer.texture_array = texture;

    renderer
}<commit_msg>Switch to SRGB texture array<commit_after>use super::Renderer;
use super::shaders::make_program_from_shaders;
use rendering::primitives::rectangle::{Rectangle, RectangleVertex};
use rendering::primitives::circle_part::{CirclePart, CircleVertex};
use rendering::primitives::polygon::{Polygon, PolygonVertex};
use rendering::primitives::text::{RenderText, TextBuffer, PlainText};
use rendering::primitives::polar_pixel::{PolarBuffer, PolarPixel, PolarPixelVertex};
use rendering::primitives::{Primitive, TextureRect};
use rendering::renderables::Renderable;
use rendering::DisplaySettings;
use super::glium_buffer::{GliumBuffer, BasicBuffer};
use super::render_by_shaders::GliumPrimitive;
use super::{BezierRect, BezierSubrect};
use glium;
use glium::Frame;
use glium::{Display, Surface, DrawParameters, Depth, DepthTest, Program};
use glium::texture;
use glium::glutin::EventsLoop;
use std::io::Cursor;
use na;
use na::Matrix4;
use num::One;
use rusttype;
use games::view_details;
use utils::transforms_2d;
use debug::*;
use image;

pub struct GliumRenderer<'a> {
    display: Box<Display>,
    events_loop: Box<EventsLoop>,
    draw_params: DrawParameters<'a>,
    rect_buffer: BasicBuffer<Rectangle>,
    texture_rect_buffer: BasicBuffer<TextureRect>,
    circ_buffer: BasicBuffer<CirclePart>,
    polygon_buffer: BasicBuffer<Polygon>,
    bezier_rect_buffer: BasicBuffer<BezierRect>,
    bezier_subrect_buffer: BasicBuffer<BezierSubrect>,
    polar_buffer: PolarBuffer,
    text_processor: TextBuffer<'a, PlainText>,
    view_details: view_details::ViewDetails,
    display_settings: DisplaySettings,
    texture_array: texture::srgb_texture2d_array::SrgbTexture2dArray
}

impl<'a> GliumRenderer<'a> {
    pub fn new(settings: DisplaySettings) -> GliumRenderer<'a> {
        let (display, events_loop) = Self::build_display_and_events_loop(settings);

        let draw_params = DrawParameters {
            depth: Depth {
                test: DepthTest::IfLessOrEqual,
                write: true,..Default::default()
            },
            ..Default::default()
        };

        GliumRenderer {
            display: Box::new(display.clone()),
            events_loop: Box::new(events_loop),
            draw_params: draw_params,
            rect_buffer: BasicBuffer::<Rectangle>::new(&display),
            texture_rect_buffer: BasicBuffer::<TextureRect>::new(&display),
            circ_buffer: BasicBuffer::<CirclePart>::new(&display),
            polygon_buffer: BasicBuffer::<Polygon>::new(&display),
            bezier_rect_buffer: BasicBuffer::<BezierRect>::new(&display),
            bezier_subrect_buffer: BasicBuffer::<BezierSubrect>::new(&display),
            polar_buffer: PolarBuffer::new(&display),
            text_processor: TextBuffer::new(&display, settings),
            view_details: view_details::ViewDetails::TwoDim(view_details::ViewDetails2D::default()),
            display_settings: settings,
            texture_array: texture::srgb_texture2d_array::SrgbTexture2dArray::empty(&display, 1024, 1024, 1).unwrap()
        }
    }

    pub fn reset(&mut self, settings: DisplaySettings) {
        let window = Self::build_window(settings, &self.events_loop);

        let context = Self::build_context(settings);

        self.display.rebuild(window, context, &self.events_loop).unwrap();
    }

    fn reset_buffers(&mut self) {
        let display = &self.display;
        self.rect_buffer = BasicBuffer::<Rectangle>::new(display);
        self.texture_rect_buffer = BasicBuffer::<TextureRect>::new(display);
        self.circ_buffer = BasicBuffer::<CirclePart>::new(display);
        self.polygon_buffer = BasicBuffer::<Polygon>::new(display);
        self.bezier_rect_buffer = BasicBuffer::<BezierRect>::new(display);
        self.bezier_subrect_buffer = BasicBuffer::<BezierSubrect>::new(display);
        self.polar_buffer = PolarBuffer::new(display);
        self.text_processor = TextBuffer::new(display, self.display_settings);
    }

    fn build_display_and_events_loop(settings: DisplaySettings) -> (Display, EventsLoop) {
        let events_loop = glium::glutin::EventsLoop::new();

        let window = Self::build_window(settings, &events_loop);

        let context = Self::build_context(settings);
        let display = glium::Display::new(window, context, &events_loop).unwrap();

        (display, events_loop)
    }

    fn build_window(settings: DisplaySettings, events_loop: &glium::glutin::EventsLoop) -> glium::glutin::WindowBuilder {
        let mut window = glium::glutin::WindowBuilder::new()
            .with_dimensions(settings.res.0, settings.res.1);

        if settings.fullscreen {
            window = window.with_fullscreen(Some(events_loop.get_primary_monitor()));
        }

        window
    }

    fn build_context(settings: DisplaySettings) -> glium::glutin::ContextBuilder<'a> {
        glium::glutin::ContextBuilder::new().with_multisampling(settings.multisample_level)
    }

    fn flush_buffers(&mut self) {
        self.rect_buffer.flush_buffer();
        self.texture_rect_buffer.flush_buffer();
        self.circ_buffer.flush_buffer();
        self.polar_buffer.flush_buffer();
        self.polygon_buffer.flush_buffer();
        self.bezier_rect_buffer.flush_buffer();
        self.bezier_subrect_buffer.flush_buffer();
        self.text_processor.flush_buffer();
    }

    pub fn create_worldview_mat(view_details: view_details::ViewDetails, aspect_ratio: f64) ->  [[f32;4]; 4] {
        let view_mat = match
            view_details {
                view_details::ViewDetails::TwoDim(ref view) =>
                transforms_2d::build_worldview_mat(
                    view.camera_pos,
                    view.viewport_height,
                    aspect_ratio,
                    view.up_vector,
                    view.use_aspect_ratio),
                view_details::ViewDetails::ThreeDim(_) => panic!("3D mode not supported!"),
                _ => Matrix4::one()
            };
        let single_mat: Matrix4<f32> = na::convert(view_mat);
        *single_mat.as_ref()
    }
}

impl<'a> Renderer for GliumRenderer<'a> {
    fn load_renderables(&mut self, renderables: Vec<Box<Renderable>>) {
        debug_clock_start("Render::glium_load");
        for mut renderable in renderables {
            for primitive in renderable.get_primitives() {
                match primitive {
                        Primitive::Rect(rectangle) => self.rect_buffer.load_renderable(rectangle),
                        Primitive::TextureRect(rect) => self.texture_rect_buffer.load_renderable(rect),
                        Primitive::Circ(circle) => self.circ_buffer.load_renderable(circle),
                        Primitive::Text(text) => self.text_processor.load_renderable(text),
                        Primitive::BezierRect(bezier_rect) => self.bezier_rect_buffer.load_renderable(bezier_rect),
                        Primitive::BezierSubrect(bezier_subrect) => self.bezier_subrect_buffer.load_renderable(bezier_subrect),
                        Primitive::PolarPix(polar) => self.polar_buffer.load_renderable(polar),
                        Primitive::Poly(polygon) => self.polygon_buffer.load_renderable(polygon)
                }
            }
        }
        debug_clock_stop("Render::glium_load");
    }

    fn render(&mut self) {
        debug_clock_start("Render::glium_render");
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        target.clear_depth(1.0);

        let (width, height) = target.get_dimensions();
        let aspect_ratio = width as f64 / height as f64;

        {
            let uniforms = uniform! {
                screen_width: width,
                screen_height: height,
                aspect_ratio: aspect_ratio as f32,
                world_view: GliumRenderer::create_worldview_mat(self.view_details, aspect_ratio),
                tex: &self.texture_array
            };

            self.rect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.texture_rect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.circ_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.polygon_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.bezier_rect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.bezier_subrect_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.polar_buffer.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);
            self.text_processor.draw_at_target(&mut target, &self.display, self.view_details, &self.draw_params, &uniforms);

            target.finish().unwrap();
        }

        self.flush_buffers();
        debug_clock_stop("Render::glium_render");
    }

    fn set_worldview(&mut self, view_details: view_details::ViewDetails) {
        self.view_details = view_details;
    }

    fn get_events_loop(&mut self) -> Option<&mut EventsLoop> {
        Some(&mut self.events_loop)
    }

    fn get_window_spec(&self) -> super::WindowSpec {
        let (width, height) = self.display.gl_window().get_inner_size().unwrap();

        super::WindowSpec {
            aspect_ratio: width as f64 / height as f64
        }
    }
}

pub fn build_renderer_with_textures<T: glium::texture::PixelValue>(settings: DisplaySettings, texture_array: Vec<texture::RawImage2d<T>>) -> GliumRenderer {
    let mut renderer = GliumRenderer::new(settings);

    let texture = glium::texture::srgb_texture2d_array::SrgbTexture2dArray::new(renderer.display.as_ref(), texture_array).unwrap();

    renderer.texture_array = texture;

    renderer
}<|endoftext|>


<commit_before>extern crate futures;
extern crate hyper;
/* extern crate tokio; */
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_process;

use self::futures::future::Future;
use self::futures::Stream;
use self::hyper::header::ContentEncoding;
use self::hyper::header::ContentLength;
use self::hyper::header::ContentType;
use self::hyper::server::{Request, Response};
use cgi::tokio_io::AsyncWrite;
use cgi::tokio_process::CommandExt;
/* use tokio::prelude::*; */
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::process::Command;
use std::process::Stdio;
use std::str::FromStr;

pub fn do_cgi(
    req: Request,
    cmd: Command,
    handle: tokio_core::reactor::Handle,
) -> Box<Future<Item = Response, Error = hyper::Error>> {
    trace_scoped!("do_cgi");
    let mut cmd = cmd;
    cmd.stdout(Stdio::piped());
    cmd.stderr(Stdio::inherit());
    cmd.stdin(Stdio::piped());
    println!("REQUEST_METHOD {:?}", req.method());
    cmd.env("SERVER_SOFTWARE", "hyper")
        .env("SERVER_NAME", "localhost") // TODO
        .env("GATEWAY_INTERFACE", "CGI/1.1")
        .env("SERVER_PROTOCOL", "HTTP/1.1") // TODO
        .env("SERVER_PORT", "80") // TODO
        .env("REQUEST_METHOD", format!("{}", req.method()))
        .env("SCRIPT_NAME", "") // TODO
        .env("QUERY_STRING", req.query().unwrap_or(""))
        .env("REMOTE_ADDR", "") // TODO
        .env("AUTH_TYPE", "") // TODO
        .env("REMOTE_USER", "") // TODO
        .env(
            "CONTENT_TYPE",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentType::plaintext())
            ),
        )
        .env(
            "HTTP_CONTENT_ENCODING",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentEncoding(vec![]))
            ),
        )
        .env(
            "CONTENT_LENGTH",
            &format!("{}", req.headers().get().unwrap_or(&ContentLength(0))),
        );

    let mut child = cmd
        .spawn_async_with_handle(&handle.new_tokio_handle())
        .expect("can't spawn CGI command");
    /* Box::new(req.body().concat2().and_then(move |body| { */
    /*     if !child.stdin().take().unwrap().write_all(&body).is_ok() { */
    /*         debug!("write_all(body) failed"); */
    /*     } */
    let r = req.body().concat2().and_then(move |body| {
        /* if !child.stdin().take().unwrap().poll_write(&body).is_ok() { */
        /*     debug!("write_all(body) failed"); */
        /* } */
        tokio_io::io::write_all(child.stdin().take().unwrap(), body)
            .and_then(move |wa| {
                child
                    .wait_with_output()
                    .map(build_response)
                    .map_err(|e| e.into())
            })
            .map_err(|e| e.into())
    });

    Box::new(r)
}

fn build_response(command_result: std::process::Output) -> Response {
    trace_begin!("build_response");
    let mut stdout = io::BufReader::new(command_result.stdout.as_slice());
    let mut stderr = io::BufReader::new(command_result.stderr.as_slice());

    let mut response = Response::new();

    let mut headers = vec![];
    for line in stdout.by_ref().lines() {
        println!("STDOUT line: {:?}", line);
        if line.as_ref().unwrap().is_empty() {
            break;
        }
        let l: Vec<&str> = line.as_ref().unwrap().as_str().splitn(2, ": ").collect();
        for x in &l {
            headers.push(x.to_string());
        }
        if l[0] == "Status" {
            response.set_status(hyper::StatusCode::Unregistered(
                u16::from_str(l[1].split(" ").next().unwrap()).unwrap(),
            ));
        } else {
            response
                .headers_mut()
                .set_raw(l[0].to_string(), l[1].to_string());
        }
    }

    let mut data = vec![];
    stdout
        .read_to_end(&mut data)
        .expect("can't read command output");

    let mut stderrdata = vec![];
    stderr
        .read_to_end(&mut stderrdata)
        .expect("can't read command output");

    /* let out = String::from_utf8_lossy(&data).to_string(); */
    let err = String::from_utf8_lossy(&stderrdata);

    /* println!("build_response out {:?}", &out); */
    println!("build_response err {:?}", &err);

    trace_end!(
        "build_response",
        /* "stdout": out, */
        "stderr": err,
        "headers": headers
    );
    response.set_body(hyper::Chunk::from(data));

    response
}
<commit_msg>cleanup<commit_after>extern crate futures;
extern crate hyper;
/* extern crate tokio; */
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_process;

use self::futures::future::Future;
use self::futures::Stream;
use self::hyper::header::ContentEncoding;
use self::hyper::header::ContentLength;
use self::hyper::header::ContentType;
use self::hyper::server::{Request, Response};
use cgi::tokio_io::AsyncWrite;
use cgi::tokio_process::CommandExt;
/* use tokio::prelude::*; */
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::process::Command;
use std::process::Stdio;
use std::str::FromStr;

pub fn do_cgi(
    req: Request,
    cmd: Command,
    handle: tokio_core::reactor::Handle,
) -> Box<Future<Item = Response, Error = hyper::Error>> {
    trace_scoped!("do_cgi");
    let mut cmd = cmd;
    cmd.stdout(Stdio::piped());
    cmd.stderr(Stdio::inherit());
    cmd.stdin(Stdio::piped());
    println!("REQUEST_METHOD {:?}", req.method());
    cmd.env("SERVER_SOFTWARE", "hyper")
        .env("SERVER_NAME", "localhost") // TODO
        .env("GATEWAY_INTERFACE", "CGI/1.1")
        .env("SERVER_PROTOCOL", "HTTP/1.1") // TODO
        .env("SERVER_PORT", "80") // TODO
        .env("REQUEST_METHOD", format!("{}", req.method()))
        .env("SCRIPT_NAME", "") // TODO
        .env("QUERY_STRING", req.query().unwrap_or(""))
        .env("REMOTE_ADDR", "") // TODO
        .env("AUTH_TYPE", "") // TODO
        .env("REMOTE_USER", "") // TODO
        .env(
            "CONTENT_TYPE",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentType::plaintext())
            ),
        )
        .env(
            "HTTP_CONTENT_ENCODING",
            &format!(
                "{}",
                req.headers().get().unwrap_or(&ContentEncoding(vec![]))
            ),
        )
        .env(
            "CONTENT_LENGTH",
            &format!("{}", req.headers().get().unwrap_or(&ContentLength(0))),
        );

    let mut child = cmd
        .spawn_async_with_handle(&handle.new_tokio_handle())
        .expect("can't spawn CGI command");

    let r = req.body().concat2().and_then(move |body| {
        tokio_io::io::write_all(child.stdin().take().unwrap(), body)
            .and_then(move |wa| {
                child
                    .wait_with_output()
                    .map(build_response)
                    .map_err(|e| e.into())
            })
            .map_err(|e| e.into())
    });

    Box::new(r)
}

fn build_response(command_result: std::process::Output) -> Response {
    trace_begin!("build_response");
    let mut stdout = io::BufReader::new(command_result.stdout.as_slice());
    let mut stderr = io::BufReader::new(command_result.stderr.as_slice());

    let mut response = Response::new();

    let mut headers = vec![];
    for line in stdout.by_ref().lines() {
        println!("STDOUT line: {:?}", line);
        if line.as_ref().unwrap().is_empty() {
            break;
        }
        let l: Vec<&str> = line.as_ref().unwrap().as_str().splitn(2, ": ").collect();
        for x in &l {
            headers.push(x.to_string());
        }
        if l[0] == "Status" {
            response.set_status(hyper::StatusCode::Unregistered(
                u16::from_str(l[1].split(" ").next().unwrap()).unwrap(),
            ));
        } else {
            response
                .headers_mut()
                .set_raw(l[0].to_string(), l[1].to_string());
        }
    }

    let mut data = vec![];
    stdout
        .read_to_end(&mut data)
        .expect("can't read command output");

    let mut stderrdata = vec![];
    stderr
        .read_to_end(&mut stderrdata)
        .expect("can't read command output");

    let err = String::from_utf8_lossy(&stderrdata);

    println!("build_response err {:?}", &err);

    trace_end!(
        "build_response",
        "stderr": err,
        "headers": headers
    );
    response.set_body(hyper::Chunk::from(data));

    response
}
<|endoftext|>