<commit_before>extern crate serenity;

command!(clear(_context, msg, args) {
	if args.len() == 1 {
		let countdown: u64 = match args[0].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(countdown)) {
				let mut vec_id = Vec::new();
				for message in vec {
					vec_id.push(message.id);
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
	else if args.len() == 2 {
		let countdown: u64 = match args[0].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		let counter: u64 = match args[1].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		let full = countdown + counter;
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(full)) {
				let mut vec_id = Vec::new();
				let mut i = 0;
				for message in vec {
					if i < countdown {
						vec_id.push(message.id);
					}
					i += 1;
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
});
<commit_msg>Fixes for clear<commit_after>extern crate serenity;

command!(clear(_context, msg, args) {
	if args.len() == 1 {
		let countdown: u64 = args.find().unwrap_or_default();
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(countdown)) {
				let mut vec_id = Vec::new();
				for message in vec {
					vec_id.push(message.id);
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
	else if args.len() == 2 {
		let countdown: u64 = args.find().unwrap_or_default();
		let counter: u64 = args.find().unwrap_or_default();
		let full = countdown + counter;
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(full)) {
				let mut vec_id = Vec::new();
				let mut i = 0;
				for message in vec {
					if i < countdown {
						vec_id.push(message.id);
					}
					i += 1;
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::ffi::OsStr;
use std::process::{Command, ExitStatus, Output};

struct Result {
    stdout: String,
    stderr: String,
    status: ExitStatus,
}

impl From<Output> for Result {
    fn from(output: Output) -> Result {
        Result {
            status: output.status,
            stdout: String::from_utf8(output.stdout).expect("Failed to decode stdout"),
            stderr: String::from_utf8(output.stderr).expect("Failed to decode stderr"),
        }
    }
}

fn run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    Command::new("cargo")
        .arg("run")
        .arg("--quiet")
        .arg("--")
        .args(args)
        .output()
        .expect("Failed to run xkpwgen for testing")
        .into()
}

fn assert_run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    let result = run(args);
    assert!(result.status.success(),
            "xkpwgen failed with output:
stdout:
{}
stderr:
{}
",
            result.stdout,
            result.stderr);
    result
}

fn phrases<'a>(s: &'a str, sep: &str) -> Vec<Vec<&'a str>> {
    s.lines().map(|w| w.split(sep).collect()).collect()
}

fn words<'a>(s: &'a str, sep: &str) -> Vec<&'a str> {
    s.lines().flat_map(|w| w.split(sep)).collect()
}

macro_rules! repeat_run {
    ($result:ident, $command:expr, $body:block) => {
        {
            for _ in 0..10 {
                let $result = assert_run($command);
                $body;
            }
        }
    };

    ($result:ident, $body:block) => {
        {
        let command: Vec<String> = Vec::new();
        repeat_run!($result, &command, $body);
        }
    };
}

#[test]
fn it_prints_a_single_phrase_by_default() {
    repeat_run!(result, {
        assert_eq!(phrases(&result.stdout, " ").len(), 1);
    })
}

#[test]
fn it_prints_four_words_per_phrase_by_default() {
    repeat_run!(result, {
        for words in phrases(&result.stdout, " ") {
            assert_eq!(words.len(), 4);
        }
    })
}

#[test]
fn it_prints_no_words_with_whitespace() {
    repeat_run!(result, {
        for word in words(&result.stdout, " ") {
            assert!(!word.contains(|c: char| c.is_whitespace()),
                    "Word {} contained whitespace!",
                    word);
        }
    })
}

#[test]
fn it_prints_no_empty_words() {
    repeat_run!(result, {
        for word in words(&result.stdout, " ") {
            assert!(word.len() > 0, "Got empty word");
        }
    })
}
<commit_msg>Test license and warranty info in --help<commit_after>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::ffi::OsStr;
use std::process::{Command, ExitStatus, Output};

struct Result {
    stdout: String,
    stderr: String,
    status: ExitStatus,
}

impl From<Output> for Result {
    fn from(output: Output) -> Result {
        Result {
            status: output.status,
            stdout: String::from_utf8(output.stdout).expect("Failed to decode stdout"),
            stderr: String::from_utf8(output.stderr).expect("Failed to decode stderr"),
        }
    }
}

fn run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    Command::new("cargo")
        .arg("run")
        .arg("--quiet")
        .arg("--")
        .args(args)
        .output()
        .expect("Failed to run xkpwgen for testing")
        .into()
}

fn assert_run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    let result = run(args);
    assert!(result.status.success(),
            "xkpwgen failed with output:
stdout:
{}
stderr:
{}
",
            result.stdout,
            result.stderr);
    result
}

fn phrases<'a>(s: &'a str, sep: &str) -> Vec<Vec<&'a str>> {
    s.lines().map(|w| w.split(sep).collect()).collect()
}

fn words<'a>(s: &'a str, sep: &str) -> Vec<&'a str> {
    s.lines().flat_map(|w| w.split(sep)).collect()
}

macro_rules! repeat_run {
    ($result:ident, $command:expr, $body:block) => {
        {
            for _ in 0..10 {
                let $result = assert_run($command);
                $body;
            }
        }
    };

    ($result:ident, $body:block) => {
        {
        let command: Vec<String> = Vec::new();
        repeat_run!($result, &command, $body);
        }
    };
}

#[test]
fn it_includes_license_and_warranty_in_help() {
    let result = assert_run(&["--help"]);
    assert!(result.stdout.contains("GNU GPL version 3 or later"),
            "License name missing in output:
{}",
            result.stdout);
    assert!(result.stdout.contains("<http://gnu.org/licenses/gpl.html>"),
            "License URL missing in output:
{}",
            result.stdout);
    assert!(result.stdout.contains("There is NO WARRANTY, to the extent permitted by law."),
            "Warranty disclaimer missing in output:
{}",
            result.stdout);
}

#[test]
fn it_prints_a_single_phrase_by_default() {
    repeat_run!(result, {
        assert_eq!(phrases(&result.stdout, " ").len(), 1);
    })
}

#[test]
fn it_prints_four_words_per_phrase_by_default() {
    repeat_run!(result, {
        for words in phrases(&result.stdout, " ") {
            assert_eq!(words.len(), 4);
        }
    })
}

#[test]
fn it_prints_no_words_with_whitespace() {
    repeat_run!(result, {
        for word in words(&result.stdout, " ") {
            assert!(!word.contains(|c: char| c.is_whitespace()),
                    "Word {} contained whitespace!",
                    word);
        }
    })
}

#[test]
fn it_prints_no_empty_words() {
    repeat_run!(result, {
        for word in words(&result.stdout, " ") {
            assert!(word.len() > 0, "Got empty word");
        }
    })
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate json;
extern crate requests;

// use requests::Codes;
use requests::{delete, get, head, post, put};
use requests::{Codes, Request, Response, StatusCode};

fn assert_response_is_ok(response: &Response, url: &str) {
    assert_eq!(response.url(), url);
    assert_eq!(response.status_code(), StatusCode::Ok);
    assert_eq!(response.reason(), "OK");
}

#[test]
fn simple_get() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    let data = res.json().unwrap();
    println!("{:?}", data);
    assert_eq!(data["url"], URL);
    assert_eq!(data["headers"]["Host"], "httpbin.org");
    assert_eq!(data["headers"]["User-Agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn simple_get_string_url() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = get(String::from(URL)).unwrap();
    assert_response_is_ok(&res, URL);
    let res = get(&String::from(URL)).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_post() {
    const URL: &'static str = "http://httpbin.org/post";
    let res = post(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_put() {
    const URL: &'static str = "http://httpbin.org/put";
    let res = put(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_head() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = head(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_delete() {
    const URL: &'static str = "http://httpbin.org/delete";
    let res = delete(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn user_agent() {
    let useragent = concat!("{\n  \"user-agent\": \"requests-rs/",
                            env!("CARGO_PKG_VERSION"),
                            "\"\n}\n");
    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.text(), Some(useragent));
}

#[test]
fn custom_user_agent() {
    const UA: &'static str = concat!("requests-rs-tests/", env!("CARGO_PKG_VERSION"));
    const URL: &'static str = "http://httpbin.org/user-agent";
    let mut request = Request::new();
    request.user_agent(UA);
    let res = request.get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"], UA);
}

#[test]
fn user_agent_json() {

    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn content() {
    const URL: &'static str = "http://httpbin.org/headers";
    let content = concat!("{\n  \"headers\": {\n    \"Host\": \"httpbin.org\",",
                          " \n    \"User-Agent\": \"requests-rs/",
                          env!("CARGO_PKG_VERSION"),
                          "\"\n  }\n}\n");

    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.content(), &content.as_bytes());
}

#[test]
fn headers() {
    use hyper::header::UserAgent;

    const URL: &'static str = "http://httpbin.org/response-headers?User-Agent=requests-rs-test";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    println!("{:?}", res.text());
    println!("{:?}", res.headers());
    println!("{:?}", res.headers().get::<UserAgent>());
    assert_eq!(res.headers().get::<UserAgent>().unwrap(),
               &UserAgent("requests-rs-test".to_owned()));
}

macro_rules! status_code_test {
    ($($name:ident: $numeric:expr,)+) => {
        $(#[test]
        fn $name() {
            let res = get(&format!("http://httpbin.org/status/{}", $numeric)).unwrap();
            println!("{}", res.text().unwrap());
            assert_eq!(res.status_code(), Codes::from_u16($numeric));
        })+
    }
}

status_code_test! {
    status_code_100: 100,
    status_code_101: 101,
    status_code_102: 102,
    status_code_200: 200,
    status_code_201: 201,
    status_code_202: 202,
    status_code_203: 203,
    status_code_400: 400,
    status_code_401: 401,
    status_code_402: 402,
    status_code_403: 403,
    status_code_404: 404,
    status_code_500: 500,
}
<commit_msg>Add more status code tests<commit_after>extern crate hyper;
extern crate json;
extern crate requests;

// use requests::Codes;
use requests::{delete, get, head, post, put};
use requests::{Codes, Request, Response, StatusCode};

fn assert_response_is_ok(response: &Response, url: &str) {
    assert_eq!(response.url(), url);
    assert_eq!(response.status_code(), StatusCode::Ok);
    assert_eq!(response.reason(), "OK");
}

#[test]
fn simple_get() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    let data = res.json().unwrap();
    println!("{:?}", data);
    assert_eq!(data["url"], URL);
    assert_eq!(data["headers"]["Host"], "httpbin.org");
    assert_eq!(data["headers"]["User-Agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn simple_get_string_url() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = get(String::from(URL)).unwrap();
    assert_response_is_ok(&res, URL);
    let res = get(&String::from(URL)).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_post() {
    const URL: &'static str = "http://httpbin.org/post";
    let res = post(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_put() {
    const URL: &'static str = "http://httpbin.org/put";
    let res = put(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_head() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = head(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_delete() {
    const URL: &'static str = "http://httpbin.org/delete";
    let res = delete(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn user_agent() {
    let useragent = concat!("{\n  \"user-agent\": \"requests-rs/",
                            env!("CARGO_PKG_VERSION"),
                            "\"\n}\n");
    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.text(), Some(useragent));
}

#[test]
fn custom_user_agent() {
    const UA: &'static str = concat!("requests-rs-tests/", env!("CARGO_PKG_VERSION"));
    const URL: &'static str = "http://httpbin.org/user-agent";
    let mut request = Request::new();
    request.user_agent(UA);
    let res = request.get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"], UA);
}

#[test]
fn user_agent_json() {

    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn content() {
    const URL: &'static str = "http://httpbin.org/headers";
    let content = concat!("{\n  \"headers\": {\n    \"Host\": \"httpbin.org\",",
                          " \n    \"User-Agent\": \"requests-rs/",
                          env!("CARGO_PKG_VERSION"),
                          "\"\n  }\n}\n");

    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.content(), &content.as_bytes());
}

#[test]
fn headers() {
    use hyper::header::UserAgent;

    const URL: &'static str = "http://httpbin.org/response-headers?User-Agent=requests-rs-test";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    println!("{:?}", res.text());
    println!("{:?}", res.headers());
    println!("{:?}", res.headers().get::<UserAgent>());
    assert_eq!(res.headers().get::<UserAgent>().unwrap(),
               &UserAgent("requests-rs-test".to_owned()));
}

macro_rules! status_code_test {
    ($($name:ident: $numeric:expr,)+) => {
        $(#[test]
        fn $name() {
            let res = get(&format!("http://httpbin.org/status/{}", $numeric)).unwrap();
            println!("{}", res.text().unwrap());
            assert_eq!(res.status_code(), Codes::from_u16($numeric));
        })+
    }
}

status_code_test! {
    status_code_100: 100,
    status_code_101: 101,
    status_code_102: 102,
    status_code_200: 200,
    status_code_201: 201,
    status_code_202: 202,
    status_code_203: 203,
    status_code_204: 204,
    status_code_205: 205,
    status_code_206: 206,
    status_code_207: 207,
    status_code_208: 208,
    status_code_226: 226,
    status_code_300: 300,
    // status_code_301: 301,
    // status_code_302: 302,
    // status_code_303: 303,
    status_code_304: 304,
    // status_code_305: 305,
    // status_code_307: 307,
    status_code_308: 308,
    status_code_400: 400,
    status_code_401: 401,
    status_code_402: 402,
    status_code_403: 403,
    status_code_404: 404,
    status_code_405: 405,
    status_code_406: 406,
    status_code_407: 407,
    status_code_408: 408,
    status_code_409: 409,
    status_code_410: 410,
    status_code_411: 411,
    status_code_412: 412,
    status_code_413: 413,
    status_code_414: 414,
    status_code_415: 415,
    status_code_416: 416,
    status_code_417: 417,
    status_code_418: 418,
    status_code_419: 419,
    status_code_420: 420,
    status_code_421: 421,
    status_code_422: 422,
    status_code_423: 423,
    status_code_424: 424,
    status_code_426: 426,
    status_code_428: 428,
    status_code_429: 429,
    status_code_431: 431,
    status_code_451: 451,
    status_code_500: 500,
    status_code_501: 501,
    status_code_502: 502,
    status_code_503: 503,
    status_code_504: 504,
    status_code_505: 505,
    status_code_506: 506,
    status_code_507: 507,
    status_code_508: 508,
    status_code_510: 510,
    status_code_511: 511,
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(plugin)]
#![plugin(regex_macros)]

use std::path::PathBuf;
use std::process::Command;
use std::fs;
use std::io::prelude::*;

extern crate binunit;
extern crate regex;

fn read_test_labels() -> Vec<String> {

    let mut file = fs::File::open("./tests/labels.test").unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    let split = s.trim().split("\n");
    split.map(|label| label.to_owned())
        .collect::<Vec<_>>()
}

#[test]
fn testc_no_compile() {

    let binunit = binunit::BinUnit::new(&PathBuf::from("./tests/testc"));

    let output = binunit.run().unwrap()
        .iter()
        .fold(String::new(), |a,b| format!("{}{}", a, b));

    assert_all_labels_match(&output);
    assert_output_does_not_link(&output);
}

fn assert_output_does_not_link(output: &String) {

    let lines = output.trim().split("\n");
    for line in lines {
        assert!(line.contains("failed (could not link)"));
        assert!(!line.contains("ok"));
        assert!(!line.contains("failed (segfault)"));
    }
}

fn assert_all_labels_match(output: &String) {

    println!("output:\n{}", output);

    let labels_from_file = read_test_labels();

    for label in labels_from_file {
        println!(">{}", label);
        let regex = regex::Regex::new(&format!("(?m)^{}:.*$", label)).unwrap();
        assert!(regex.is_match(&output));
        assert_eq!(1, regex.captures_iter(&output).count());
    }
}

#[test]
fn testc_compile() {

    fs::create_dir("./tests/testc-build").unwrap_or(());
    compile("passfail");
    compile("assert");
    compile("assert_string");
    compile("assert_mem");
    compile("segf");

    let binunit = binunit::BinUnit::new(&PathBuf::from("./tests"));
    let output = binunit.run().unwrap()
        .iter()
        .fold(String::new(), |a,b| format!("{}{}", a, b));

    assert_all_labels_match(&output);
    assert_output_satisfies(&output);
    panic!();
}

fn compile(test_name: &str) {

     Command::new("gcc")
        .current_dir("./tests")
        .arg(&format!("testc/{}.c", test_name)[..])
        .arg("-c")
        .arg("-o")
        .arg(&format!("testc-build/{}.o", test_name)[..])
        .status().unwrap();
}

fn assert_output_satisfies(output: &String) {

    let regex = regex!(r"(?m)^(.*):\s*(.*)\s*$");
    for cap in regex.captures_iter(output) {
        let line = cap.at(0).unwrap().clone();
        let label = cap.at(1).unwrap();
        let test_result = cap.at(2).unwrap();

        println!(">{}", line);
        match test_result {
            "ok" => assert!(label.contains("pass")),
            "failed" => assert!(label.contains("fail")),
            "failed (segfault)" => assert!(label.contains("segf")),
            _ => panic!("unrecognized test result at line: {}", line)
        }
    }
}
<commit_msg>remove explicit panic<commit_after>#![deny(warnings)]
#![feature(plugin)]
#![plugin(regex_macros)]

use std::path::PathBuf;
use std::process::Command;
use std::fs;
use std::io::prelude::*;

extern crate binunit;
extern crate regex;

fn read_test_labels() -> Vec<String> {

    let mut file = fs::File::open("./tests/labels.test").unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    let split = s.trim().split("\n");
    split.map(|label| label.to_owned())
        .collect::<Vec<_>>()
}

#[test]
fn testc_no_compile() {

    let binunit = binunit::BinUnit::new(&PathBuf::from("./tests/testc"));

    let output = binunit.run().unwrap()
        .iter()
        .fold(String::new(), |a,b| format!("{}{}", a, b));

    assert_all_labels_match(&output);
    assert_output_does_not_link(&output);
}

fn assert_output_does_not_link(output: &String) {

    let lines = output.trim().split("\n");
    for line in lines {
        assert!(line.contains("failed (could not link)"));
        assert!(!line.contains("ok"));
        assert!(!line.contains("failed (segfault)"));
    }
}

fn assert_all_labels_match(output: &String) {

    println!("output:\n{}", output);

    let labels_from_file = read_test_labels();

    for label in labels_from_file {
        println!(">{}", label);
        let regex = regex::Regex::new(&format!("(?m)^{}:.*$", label)).unwrap();
        assert!(regex.is_match(&output));
        assert_eq!(1, regex.captures_iter(&output).count());
    }
}

#[test]
fn testc_compile() {

    fs::create_dir("./tests/testc-build").unwrap_or(());
    compile("passfail");
    compile("assert");
    compile("assert_string");
    compile("assert_mem");
    compile("segf");

    let binunit = binunit::BinUnit::new(&PathBuf::from("./tests"));
    let output = binunit.run().unwrap()
        .iter()
        .fold(String::new(), |a,b| format!("{}{}", a, b));

    assert_all_labels_match(&output);
    assert_output_satisfies(&output);
}

fn compile(test_name: &str) {

     Command::new("gcc")
        .current_dir("./tests")
        .arg(&format!("testc/{}.c", test_name)[..])
        .arg("-c")
        .arg("-o")
        .arg(&format!("testc-build/{}.o", test_name)[..])
        .status().unwrap();
}

fn assert_output_satisfies(output: &String) {

    let regex = regex!(r"(?m)^(.*):\s*(.*)\s*$");
    for cap in regex.captures_iter(output) {
        let line = cap.at(0).unwrap().clone();
        let label = cap.at(1).unwrap();
        let test_result = cap.at(2).unwrap();

        println!(">{}", line);
        match test_result {
            "ok" => assert!(label.contains("pass")),
            "failed" => assert!(label.contains("fail")),
            "failed (segfault)" => assert!(label.contains("segf")),
            _ => panic!("unrecognized test result at line: {}", line)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate examples;
extern crate cgmath;
extern crate winit;
extern crate time;

#[macro_use]
extern crate vulkano;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;

use std::sync::Arc;
use std::time::Duration;

mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_vs.glsl")} }
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_fs.glsl")} }

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    let extensions = vulkano_win::required_extensions();
    let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let window = winit::WindowBuilder::new().build_vk_surface(&instance).unwrap();

    let queue = physical.queue_families().find(|q| q.supports_graphics() &&
                                                   window.surface().is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
        .. vulkano::device::DeviceExtensions::none()
    };

    let (device, mut queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
                                                            &device_ext, [(queue, 0.5)].iter().cloned())
                               .expect("failed to create device");
    let queue = queues.next().unwrap();

    let (swapchain, images) = {
        let caps = window.surface().get_capabilities(&physical).expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
        let present = caps.present_modes.iter().next().unwrap();
        let usage = caps.supported_usage_flags;
        let format = caps.supported_formats[0].0;

        vulkano::swapchain::Swapchain::new(&device, &window.surface(), 3, format, dimensions, 1,
                                           &usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           vulkano::swapchain::CompositeAlpha::Opaque,
                                           present, true, None).expect("failed to create swapchain")
    };

    let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(&device, images[0].dimensions(), vulkano::format::D16Unorm).unwrap();

    let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
                                .expect("failed to create buffer");

    let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::NORMALS.iter().cloned())
                                .expect("failed to create buffer");

    let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::INDICES.iter().cloned())
                                .expect("failed to create buffer");

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let proj = cgmath::perspective(cgmath::rad(3.141592 / 2.0), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<vs::ty::Data>
                               ::from_data(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()),
                                vs::ty::Data {
                                    world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
                                    view : (view * scale).into(),
                                    proj : proj.into(),
                                })
                               .expect("failed to create buffer");

    let vs = vs::Shader::load(&device).expect("failed to create shader module");
    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    mod renderpass {
        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: ::vulkano::format::Format,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: ::vulkano::format::D16Unorm,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        }
    }

    let renderpass = renderpass::CustomRenderPass::new(&device, &renderpass::Formats {
        color: (images[0].format(), 1),
        depth: (vulkano::format::D16Unorm, 1)
    }).unwrap();

    let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);

    mod pipeline_layout {
        pipeline_layout!{
            set0: {
                uniforms: UniformBuffer<::vs::ty::Data>
            }
        }
    }

    let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();
    let set = pipeline_layout::set0::Set::new(&descriptor_pool, &pipeline_layout, &pipeline_layout::set0::Descriptors {
        uniforms: &uniform_buffer
    });

    let pipeline = vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::GraphicsPipelineParams {
        vertex_input: vulkano::pipeline::vertex::TwoBuffersDefinition::new(),
        vertex_shader: vs.main_entry_point(),
        input_assembly: vulkano::pipeline::input_assembly::InputAssembly::triangle_list(),
        tessellation: None,
        geometry_shader: None,
        viewport: vulkano::pipeline::viewport::ViewportsState::Fixed {
            data: vec![(
                vulkano::pipeline::viewport::Viewport {
                    origin: [0.0, 0.0],
                    depth_range: 0.0 .. 1.0,
                    dimensions: [images[0].dimensions()[0] as f32, images[0].dimensions()[1] as f32],
                },
                vulkano::pipeline::viewport::Scissor::irrelevant()
            )],
        },
        raster: Default::default(),
        multisample: vulkano::pipeline::multisample::Multisample::disabled(),
        fragment_shader: fs.main_entry_point(),
        depth_stencil: vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test(),
        blend: vulkano::pipeline::blend::Blend::pass_through(),
        layout: &pipeline_layout,
        render_pass: vulkano::framebuffer::Subpass::from(&renderpass, 0).unwrap(),
    }).unwrap();

    let framebuffers = images.iter().map(|image| {
        let attachments = renderpass::AList {
            color: &image,
            depth: &depth_buffer,
        };

        vulkano::framebuffer::Framebuffer::new(&renderpass, [image.dimensions()[0], image.dimensions()[1], 1], attachments).unwrap()
    }).collect::<Vec<_>>();

    let command_buffers = framebuffers.iter().map(|framebuffer| {
        vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&device, queue.family())
            .draw_inline(&renderpass, &framebuffer, renderpass::ClearValues {
                 color: [0.0, 0.0, 1.0, 1.0],
                 depth: 1.0,
             })
            .draw_indexed(&pipeline, (&vertex_buffer, &normals_buffer), &index_buffer,
                          &vulkano::command_buffer::DynamicState::none(), &set, &())
            .draw_end()
            .build()
    }).collect::<Vec<_>>();

    let mut submissions: Vec<Arc<vulkano::command_buffer::Submission>> = Vec::new();

    loop {
        submissions.retain(|s| s.destroying_would_block());

        {
            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();

            let rotation = cgmath::Matrix3::from_angle_y(cgmath::rad(time::precise_time_ns() as f32 * 0.000000001));

            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.world = cgmath::Matrix4::from(rotation).into();
        }

        let image_num = swapchain.acquire_next_image(Duration::from_millis(1)).unwrap();
        submissions.push(vulkano::command_buffer::submit(&command_buffers[image_num], &queue).unwrap());
        swapchain.present(&queue, image_num).unwrap();

        for ev in window.window().poll_events() {
            match ev {
                winit::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Some work on teapot example changes<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate examples;
extern crate cgmath;
extern crate winit;
extern crate time;

#[macro_use]
extern crate vulkano;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;
use vulkano::command_buffer::std::StdCommandsList;

use std::sync::Arc;
use std::time::Duration;

mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_vs.glsl")} }
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_fs.glsl")} }

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    let extensions = vulkano_win::required_extensions();
    let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let window = winit::WindowBuilder::new().build_vk_surface(&instance).unwrap();

    let queue = physical.queue_families().find(|q| q.supports_graphics() &&
                                                   window.surface().is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
        .. vulkano::device::DeviceExtensions::none()
    };

    let (device, mut queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
                                                            &device_ext, [(queue, 0.5)].iter().cloned())
                               .expect("failed to create device");
    let queue = queues.next().unwrap();

    let (swapchain, images) = {
        let caps = window.surface().get_capabilities(&physical).expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
        let present = caps.present_modes.iter().next().unwrap();
        let usage = caps.supported_usage_flags;
        let format = caps.supported_formats[0].0;

        vulkano::swapchain::Swapchain::new(&device, &window.surface(), 3, format, dimensions, 1,
                                           &usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           vulkano::swapchain::CompositeAlpha::Opaque,
                                           present, true, None).expect("failed to create swapchain")
    };

    let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(&device, images[0].dimensions(), vulkano::format::D16Unorm).unwrap();

    let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
                                .expect("failed to create buffer");

    let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::NORMALS.iter().cloned())
                                .expect("failed to create buffer");

    let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::INDICES.iter().cloned())
                                .expect("failed to create buffer");

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let proj = cgmath::perspective(cgmath::rad(3.141592 / 2.0), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<vs::ty::Data>
                               ::from_data(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()),
                                vs::ty::Data {
                                    world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
                                    view : (view * scale).into(),
                                    proj : proj.into(),
                                })
                               .expect("failed to create buffer");

    let vs = vs::Shader::load(&device).expect("failed to create shader module");
    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    mod renderpass {
        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: ::vulkano::format::Format,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: ::vulkano::format::D16Unorm,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        }
    }

    let renderpass = renderpass::CustomRenderPass::new(&device, &renderpass::Formats {
        color: (images[0].format(), 1),
        depth: (vulkano::format::D16Unorm, 1)
    }).unwrap();

    let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);

    mod pipeline_layout {
        pipeline_layout!{
            set0: {
                uniforms: UniformBuffer<::vs::ty::Data>
            }
        }
    }

    let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();
    let set = pipeline_layout::set0::Set::new(&descriptor_pool, &pipeline_layout, &pipeline_layout::set0::Descriptors {
        uniforms: &uniform_buffer
    });

    let pipeline = vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::GraphicsPipelineParams {
        vertex_input: vulkano::pipeline::vertex::TwoBuffersDefinition::new(),
        vertex_shader: vs.main_entry_point(),
        input_assembly: vulkano::pipeline::input_assembly::InputAssembly::triangle_list(),
        tessellation: None,
        geometry_shader: None,
        viewport: vulkano::pipeline::viewport::ViewportsState::Fixed {
            data: vec![(
                vulkano::pipeline::viewport::Viewport {
                    origin: [0.0, 0.0],
                    depth_range: 0.0 .. 1.0,
                    dimensions: [images[0].dimensions()[0] as f32, images[0].dimensions()[1] as f32],
                },
                vulkano::pipeline::viewport::Scissor::irrelevant()
            )],
        },
        raster: Default::default(),
        multisample: vulkano::pipeline::multisample::Multisample::disabled(),
        fragment_shader: fs.main_entry_point(),
        depth_stencil: vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test(),
        blend: vulkano::pipeline::blend::Blend::pass_through(),
        layout: &pipeline_layout,
        render_pass: vulkano::framebuffer::Subpass::from(&renderpass, 0).unwrap(),
    }).unwrap();

    let framebuffers = images.iter().map(|image| {
        let attachments = renderpass::AList {
            color: image.clone(),
            depth: depth_buffer.clone(),
        };

        vulkano::framebuffer::StdFramebuffer::new(&renderpass, [image.dimensions()[0], image.dimensions()[1], 1], attachments).unwrap()
    }).collect::<Vec<_>>();

    let command_buffers = framebuffers.iter().map(|framebuffer| {
        vulkano::command_buffer::std::PrimaryCbBuilder::new(&device, queue.family())
            .begin_render_pass(framebuffer.clone(), false, renderpass::ClearValues {
                 color: [0.0, 0.0, 1.0, 1.0],
                 depth: 1.0,
             })
            .draw_indexed(&pipeline, (&vertex_buffer, &normals_buffer), &index_buffer,
                          &vulkano::command_buffer::DynamicState::none(), &set, &())
            .end_render_pass()
            .build()
    }).collect::<Vec<_>>();

    let mut submissions: Vec<vulkano::command_buffer::Submission> = Vec::new();

    loop {
        submissions.retain(|s| s.destroying_would_block());

        {
            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();

            let rotation = cgmath::Matrix3::from_angle_y(cgmath::rad(time::precise_time_ns() as f32 * 0.000000001));

            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.world = cgmath::Matrix4::from(rotation).into();
        }

        let image_num = swapchain.acquire_next_image(Duration::from_millis(1)).unwrap();
        submissions.push(&command_buffers[image_num].submit(&queue).unwrap());
        swapchain.present(&queue, image_num).unwrap();

        for ev in window.window().poll_events() {
            match ev {
                winit::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::cpp_data::CppPath;
use crate::cpp_data::CppPathItem;
use crate::cpp_function::CppFunction;
use crate::cpp_function::CppFunctionArgument;
use crate::cpp_function::CppOperator;
use crate::cpp_type::CppType;
use crate::database::CppItemData;
use crate::database::DatabaseItemSource;
use crate::processor::ProcessingStep;
use crate::processor::ProcessorData;
use log::{trace, warn};
use ritual_common::errors::err_msg;
use ritual_common::errors::{bail, Result};

/// Returns true if `type1` is a known template instantiation.
fn check_template_type(data: &ProcessorData, type1: &CppType) -> Result<()> {
    if let CppType::Class(ref path) = type1 {
        if let Some(ref template_arguments) = path.last().template_arguments {
            let is_available = data
                .all_items()
                .iter()
                .filter_map(|i| i.cpp_data.as_type_ref())
                .any(|inst| {
                    // TODO: fix after CppPath refactoring
                    &inst.path == path
                });
            if !is_available {
                bail!("type not available: {:?}", type1);
            }
            for arg in template_arguments {
                check_template_type(data, arg)?;
            }
        }
    }
    Ok(())
}

/// Tries to apply each of `template_instantiations` to `method`.
/// Only types at the specified `nested_level` are replaced.
/// Returns `Err` if any of `template_instantiations` is incompatible
/// with the method.
fn apply_instantiation_to_method(
    method: &CppFunction,
    nested_level1: usize,
    template_instantiation: &CppPath,
) -> Result<CppFunction> {
    trace!(
        "[DebugTemplateInstantiation] instantiation: {:?}",
        template_instantiation
    );
    let mut new_method = method.clone();

    let inst_args = template_instantiation
        .last()
        .template_arguments
        .as_ref()
        .ok_or_else(|| err_msg("template instantiation must have template arguments"))?;

    new_method.arguments.clear();
    for arg in &method.arguments {
        new_method.arguments.push(CppFunctionArgument {
            name: arg.name.clone(),
            has_default_value: arg.has_default_value,
            argument_type: arg.argument_type.instantiate(nested_level1, inst_args)?,
        });
    }
    new_method.return_type = method.return_type.instantiate(nested_level1, inst_args)?;

    new_method.path = new_method.path.instantiate(nested_level1, inst_args)?;
    let mut conversion_type = None;
    if let Some(ref mut operator) = new_method.operator {
        if let CppOperator::Conversion(ref mut cpp_type) = *operator {
            let r = cpp_type.instantiate(nested_level1, inst_args)?;
            *cpp_type = r.clone();
            conversion_type = Some(r);
        }
    }
    if new_method
        .all_involved_types()
        .iter()
        .any(|t| t.is_or_contains_template_parameter())
    {
        bail!(
            "extra template parameters left: {}",
            new_method.short_text()
        );
    } else {
        if let Some(conversion_type) = conversion_type {
            *new_method.path.last_mut() = CppPathItem::from_str_unchecked(&format!(
                "operator {}",
                conversion_type.to_cpp_code(None)?
            ));
        }
        trace!(
            "[DebugTemplateInstantiation] success: {}",
            new_method.short_text()
        );
        Ok(new_method)
    }
}

pub fn instantiate_templates_step() -> ProcessingStep {
    ProcessingStep::new("instantiate_templates", instantiate_templates)
}

/// Generates methods as template instantiations of
/// methods of existing template classes and existing template methods.
fn instantiate_templates(data: &mut ProcessorData) -> Result<()> {
    let mut new_methods = Vec::new();
    for method in data
        .all_items()
        .iter()
        .filter_map(|item| item.cpp_data.as_function_ref())
    {
        for type1 in method.all_involved_types() {
            let path = match type1 {
                CppType::Class(ref class_type) => class_type,
                CppType::PointerLike { ref target, .. } => match **target {
                    CppType::Class(ref class_type) => class_type,
                    _ => continue,
                },
                _ => continue,
            };
            if let Some(ref template_arguments) = path.last().template_arguments {
                assert!(!template_arguments.is_empty());
                if template_arguments.iter().all(|x| x.is_template_parameter()) {
                    for type1 in data
                        .current_database
                        .cpp_items
                        .iter()
                        .filter_map(|item| item.cpp_data.as_type_ref())
                    {
                        let is_suitable = type1.path.parent().ok() == path.parent().ok()
                            && type1.path.last().name == path.last().name
                            && type1.path.last().template_arguments.as_ref().map_or(
                                false,
                                |args| {
                                    !args
                                        .iter()
                                        .all(|arg| arg.is_or_contains_template_parameter())
                                },
                            );

                        if is_suitable {
                            let nested_level =
                                if let CppType::TemplateParameter { nested_level, .. } =
                                    template_arguments[0]
                                {
                                    nested_level
                                } else {
                                    bail!("only template parameters can be here");
                                };
                            trace!(
                                "[DebugTemplateInstantiation] method: {}",
                                method.short_text()
                            );
                            trace!(
                                "[DebugTemplateInstantiation] found template instantiation: {:?}",
                                type1
                            );
                            match apply_instantiation_to_method(method, nested_level, &type1.path) {
                                Ok(method) => {
                                    let mut ok = true;
                                    for type1 in method.all_involved_types() {
                                        match check_template_type(&data, &type1) {
                                            Ok(_) => {}
                                            Err(msg) => {
                                                ok = false;
                                                trace!("[DebugTemplateInstantiation] method is not accepted: {}",
                                                        method.short_text()
                                                    );
                                                trace!("[DebugTemplateInstantiation]   {}", msg);
                                            }
                                        }
                                    }
                                    if ok {
                                        new_methods.push(method);
                                    }
                                    break;
                                }
                                Err(msg) => trace!("[DebugTemplateInstantiation] failed: {}", msg),
                            }
                            break;
                        }
                    }
                }
            }
        }
    }
    for item in new_methods {
        data.current_database.add_cpp_data(
            DatabaseItemSource::TemplateInstantiation,
            CppItemData::Function(item),
        );
    }
    Ok(())
}

pub fn find_template_instantiations_step() -> ProcessingStep {
    ProcessingStep::new("find_template_instantiations", find_template_instantiations)
}

/// Searches for template instantiations in this library's API,
/// excluding results that were already processed in dependencies.
fn find_template_instantiations(data: &mut ProcessorData) -> Result<()> {
    fn check_type(type1: &CppType, data: &ProcessorData, result: &mut Vec<CppPath>) {
        match type1 {
            CppType::Class(ref path) => {
                if let Some(ref template_arguments) = path.last().template_arguments {
                    if !template_arguments
                        .iter()
                        .any(|x| x.is_or_contains_template_parameter())
                    {
                        let is_in_database = data
                            .all_items()
                            .iter()
                            .filter_map(|item| item.cpp_data.as_type_ref())
                            .any(|i| &i.path == path);
                        if !is_in_database {
                            let is_in_result = result.iter().any(|x| {
                                // TODO: ignore last template args?
                                x == path
                            });
                            if !is_in_result {
                                trace!(
                                    "Found template instantiation: {}",
                                    path.to_cpp_pseudo_code()
                                );
                                result.push(path.clone());
                            }
                        }
                    }
                    for arg in template_arguments {
                        check_type(arg, &data, result);
                    }
                }
            }
            CppType::PointerLike { ref target, .. } => check_type(target, data, result),
            _ => {}
        }
    }
    let mut result = Vec::new();
    for item in &data.current_database.cpp_items {
        for type1 in item.cpp_data.all_involved_types() {
            check_type(&type1, &data, &mut result);
        }
    }
    for item in result {
        let original_type = data
            .all_items()
            .iter()
            .filter_map(|x| x.cpp_data.as_type_ref())
            .find(|t| {
                t.path.parent().ok() == item.parent().ok()
                    && t.path.last().name == item.last().name
                    && t.path
                        .last()
                        .template_arguments
                        .as_ref()
                        .map_or(false, |args| {
                            args.iter().all(|arg| arg.is_template_parameter())
                        })
            });
        if let Some(original_type) = original_type {
            let mut new_type = original_type.clone();
            new_type.path = item;
            data.current_database.add_cpp_data(
                DatabaseItemSource::TemplateInstantiation,
                CppItemData::Type(new_type),
            );
        } else {
            warn!("original type not found for instantiation: {:?}", item);
        }
    }
    Ok(())
}
<commit_msg>fix template instantiation<commit_after>use crate::cpp_data::CppPath;
use crate::cpp_data::CppPathItem;
use crate::cpp_function::CppFunction;
use crate::cpp_function::CppFunctionArgument;
use crate::cpp_function::CppOperator;
use crate::cpp_type::CppType;
use crate::database::CppItemData;
use crate::database::DatabaseItemSource;
use crate::processor::ProcessingStep;
use crate::processor::ProcessorData;
use log::{trace, warn};
use ritual_common::errors::err_msg;
use ritual_common::errors::{bail, Result};

/// Returns true if `type1` is a known template instantiation.
fn check_template_type(data: &ProcessorData, type1: &CppType) -> Result<()> {
    if let CppType::Class(ref path) = type1 {
        if let Some(ref template_arguments) = path.last().template_arguments {
            let is_available = data
                .all_items()
                .iter()
                .filter_map(|i| i.cpp_data.as_type_ref())
                .any(|inst| {
                    // TODO: fix after CppPath refactoring
                    &inst.path == path
                });
            if !is_available {
                bail!("type not available: {:?}", type1);
            }
            for arg in template_arguments {
                check_template_type(data, arg)?;
            }
        }
    }
    Ok(())
}

/// Tries to apply each of `template_instantiations` to `method`.
/// Only types at the specified `nested_level` are replaced.
/// Returns `Err` if any of `template_instantiations` is incompatible
/// with the method.
fn apply_instantiation_to_method(
    method: &CppFunction,
    nested_level1: usize,
    template_instantiation: &CppPath,
) -> Result<CppFunction> {
    trace!(
        "[DebugTemplateInstantiation] instantiation: {:?}",
        template_instantiation
    );
    let mut new_method = method.clone();

    let inst_args = template_instantiation
        .last()
        .template_arguments
        .as_ref()
        .ok_or_else(|| err_msg("template instantiation must have template arguments"))?;

    new_method.arguments.clear();
    for arg in &method.arguments {
        new_method.arguments.push(CppFunctionArgument {
            name: arg.name.clone(),
            has_default_value: arg.has_default_value,
            argument_type: arg.argument_type.instantiate(nested_level1, inst_args)?,
        });
    }
    new_method.return_type = method.return_type.instantiate(nested_level1, inst_args)?;

    new_method.path = new_method.path.instantiate(nested_level1, inst_args)?;
    let mut conversion_type = None;
    if let Some(ref mut operator) = new_method.operator {
        if let CppOperator::Conversion(ref mut cpp_type) = *operator {
            let r = cpp_type.instantiate(nested_level1, inst_args)?;
            *cpp_type = r.clone();
            conversion_type = Some(r);
        }
    }
    if new_method
        .all_involved_types()
        .iter()
        .any(|t| t.is_or_contains_template_parameter())
    {
        bail!(
            "extra template parameters left: {}",
            new_method.short_text()
        );
    } else {
        if let Some(conversion_type) = conversion_type {
            *new_method.path.last_mut() = CppPathItem::from_str_unchecked(&format!(
                "operator {}",
                conversion_type.to_cpp_code(None)?
            ));
        }
        trace!(
            "[DebugTemplateInstantiation] success: {}",
            new_method.short_text()
        );
        Ok(new_method)
    }
}

pub fn instantiate_templates_step() -> ProcessingStep {
    ProcessingStep::new("instantiate_templates", instantiate_templates)
}

/// Generates methods as template instantiations of
/// methods of existing template classes and existing template methods.
fn instantiate_templates(data: &mut ProcessorData) -> Result<()> {
    let mut new_methods = Vec::new();
    for method in data
        .all_items()
        .iter()
        .filter_map(|item| item.cpp_data.as_function_ref())
    {
        for type1 in method.all_involved_types() {
            let path = match type1 {
                CppType::Class(ref class_type) => class_type,
                CppType::PointerLike { ref target, .. } => match **target {
                    CppType::Class(ref class_type) => class_type,
                    _ => continue,
                },
                _ => continue,
            };
            if let Some(ref template_arguments) = path.last().template_arguments {
                assert!(!template_arguments.is_empty());
                if template_arguments.iter().all(|x| x.is_template_parameter()) {
                    for type1 in data
                        .current_database
                        .cpp_items
                        .iter()
                        .filter_map(|item| item.cpp_data.as_type_ref())
                    {
                        let is_suitable = type1.path.parent().ok() == path.parent().ok()
                            && type1.path.last().name == path.last().name
                            && type1.path.last().template_arguments.as_ref().map_or(
                                false,
                                |args| {
                                    !args
                                        .iter()
                                        .all(|arg| arg.is_or_contains_template_parameter())
                                },
                            );

                        if is_suitable {
                            let nested_level =
                                if let CppType::TemplateParameter { nested_level, .. } =
                                    template_arguments[0]
                                {
                                    nested_level
                                } else {
                                    bail!("only template parameters can be here");
                                };
                            trace!(
                                "[DebugTemplateInstantiation] method: {}",
                                method.short_text()
                            );
                            trace!(
                                "[DebugTemplateInstantiation] found template instantiation: {:?}",
                                type1
                            );
                            match apply_instantiation_to_method(method, nested_level, &type1.path) {
                                Ok(method) => {
                                    let mut ok = true;
                                    for type1 in method.all_involved_types() {
                                        match check_template_type(&data, &type1) {
                                            Ok(_) => {}
                                            Err(msg) => {
                                                ok = false;
                                                trace!("[DebugTemplateInstantiation] method is not accepted: {}",
                                                        method.short_text()
                                                    );
                                                trace!("[DebugTemplateInstantiation]   {}", msg);
                                            }
                                        }
                                    }
                                    if ok {
                                        new_methods.push(method);
                                    }
                                }
                                Err(msg) => trace!("[DebugTemplateInstantiation] failed: {}", msg),
                            }
                        }
                    }
                }
            }
        }
    }
    for item in new_methods {
        data.current_database.add_cpp_data(
            DatabaseItemSource::TemplateInstantiation,
            CppItemData::Function(item),
        );
    }
    Ok(())
}

pub fn find_template_instantiations_step() -> ProcessingStep {
    ProcessingStep::new("find_template_instantiations", find_template_instantiations)
}

/// Searches for template instantiations in this library's API,
/// excluding results that were already processed in dependencies.
fn find_template_instantiations(data: &mut ProcessorData) -> Result<()> {
    fn check_type(type1: &CppType, data: &ProcessorData, result: &mut Vec<CppPath>) {
        match type1 {
            CppType::Class(ref path) => {
                if let Some(ref template_arguments) = path.last().template_arguments {
                    if !template_arguments
                        .iter()
                        .any(|x| x.is_or_contains_template_parameter())
                    {
                        let is_in_database = data
                            .all_items()
                            .iter()
                            .filter_map(|item| item.cpp_data.as_type_ref())
                            .any(|i| &i.path == path);
                        if !is_in_database {
                            let is_in_result = result.iter().any(|x| {
                                // TODO: ignore last template args?
                                x == path
                            });
                            if !is_in_result {
                                trace!(
                                    "Found template instantiation: {}",
                                    path.to_cpp_pseudo_code()
                                );
                                result.push(path.clone());
                            }
                        }
                    }
                    for arg in template_arguments {
                        check_type(arg, &data, result);
                    }
                }
            }
            CppType::PointerLike { ref target, .. } => check_type(target, data, result),
            _ => {}
        }
    }
    let mut result = Vec::new();
    for item in &data.current_database.cpp_items {
        for type1 in item.cpp_data.all_involved_types() {
            check_type(&type1, &data, &mut result);
        }
    }
    for item in result {
        let original_type = data
            .all_items()
            .iter()
            .filter_map(|x| x.cpp_data.as_type_ref())
            .find(|t| {
                t.path.parent().ok() == item.parent().ok()
                    && t.path.last().name == item.last().name
                    && t.path
                        .last()
                        .template_arguments
                        .as_ref()
                        .map_or(false, |args| {
                            args.iter().all(|arg| arg.is_template_parameter())
                        })
            });
        if let Some(original_type) = original_type {
            let mut new_type = original_type.clone();
            new_type.path = item;
            data.current_database.add_cpp_data(
                DatabaseItemSource::TemplateInstantiation,
                CppItemData::Type(new_type),
            );
        } else {
            warn!("original type not found for instantiation: {:?}", item);
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>Add accept/reject support and Response type<commit_after><|endoftext|>


<commit_before>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
extern crate objc;
#[macro_use]
extern crate foreign_types;

use std::{
    borrow::{Borrow, ToOwned},
    marker::PhantomData,
    mem,
    ops::Deref,
    os::raw::c_void,
};

use core_graphics_types::{base::CGFloat, geometry::CGSize};
use foreign_types::ForeignType;
use objc::runtime::{Object, NO, YES};

#[cfg(target_pointer_width = "64")]
pub type NSInteger = i64;
#[cfg(not(target_pointer_width = "64"))]
pub type NSInteger = i32;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = u64;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = u32;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct NSRange {
    pub location: NSUInteger,
    pub length: NSUInteger,
}

impl NSRange {
    #[inline]
    pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange {
        NSRange { location, length }
    }
}

fn nsstring_as_str(nsstr: &objc::runtime::Object) -> &str {
    let bytes = unsafe {
        let bytes: *const std::os::raw::c_char = msg_send![nsstr, UTF8String];
        bytes as *const u8
    };
    let len: NSUInteger = unsafe { msg_send![nsstr, length] };
    unsafe {
        let bytes = std::slice::from_raw_parts(bytes, len as usize);
        std::str::from_utf8(bytes).unwrap()
    }
}

fn nsstring_from_str(string: &str) -> *mut objc::runtime::Object {
    const UTF8_ENCODING: usize = 4;

    let cls = class!(NSString);
    let bytes = string.as_ptr() as *const c_void;
    unsafe {
        let obj: *mut objc::runtime::Object = msg_send![cls, alloc];
        let obj: *mut objc::runtime::Object = msg_send![
            obj,
            initWithBytes:bytes
            length:string.len()
            encoding:UTF8_ENCODING
        ];
        let _: *mut c_void = msg_send![obj, autorelease];
        obj
    }
}

macro_rules! foreign_obj_type {
    {type CType = $raw_ident:ident;
    pub struct $owned_ident:ident;
    pub struct $ref_ident:ident;
    type ParentType = $parent_ref:ident;
    } => {
        foreign_obj_type! {
            type CType = $raw_ident;
            pub struct $owned_ident;
            pub struct $ref_ident;
        }

        impl ::std::ops::Deref for $ref_ident {
            type Target = $parent_ref;

            fn deref(&self) -> &$parent_ref {
                unsafe { &*(self as *const $ref_ident as *const $parent_ref)  }
            }
        }
    };
    {type CType = $raw_ident:ident;
    pub struct $owned_ident:ident;
    pub struct $ref_ident:ident;
    } => {
        foreign_type! {
            type CType = $raw_ident;
            fn drop = crate::obj_drop;
            fn clone = crate::obj_clone;
            pub struct $owned_ident;
            pub struct $ref_ident;
        }

        unsafe impl ::objc::Message for $raw_ident {
        }
        unsafe impl ::objc::Message for $ref_ident {
        }

        impl ::std::fmt::Debug for $ref_ident {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                unsafe {
                    let string: *mut ::objc::runtime::Object = msg_send![self, debugDescription];
                    write!(f, "{}", crate::nsstring_as_str(&*string))
                }
            }
        }

        impl ::std::fmt::Debug for $owned_ident {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::ops::Deref::deref(self).fmt(f)
            }
        }
    };
}

macro_rules! try_objc {
    {
        $err_name: ident => $body:expr
    } => {
        {
            let mut $err_name: *mut ::objc::runtime::Object = ::std::ptr::null_mut();
            let value = $body;
            if !$err_name.is_null() {
                let desc: *mut Object = msg_send![$err_name, localizedDescription];
                let compile_error: *const std::os::raw::c_char = msg_send![desc, UTF8String];
                let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
                let () = msg_send![$err_name, release];
                return Err(message);
            }
            value
        }
    };
}

pub struct NSArray<T> {
    _phantom: PhantomData<T>,
}

pub struct Array<T>(*mut NSArray<T>)
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static;
pub struct ArrayRef<T>(foreign_types::Opaque, PhantomData<T>)
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static;

impl<T> Drop for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    fn drop(&mut self) {
        unsafe {
            let () = msg_send![self.0, release];
        }
    }
}

impl<T> Clone for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    fn clone(&self) -> Self {
        unsafe { Array(msg_send![self.0, retain]) }
    }
}

unsafe impl<T> objc::Message for NSArray<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
}
unsafe impl<T> objc::Message for ArrayRef<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
}

impl<T> Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    pub fn from_slice<'a>(s: &[&T::Ref]) -> &'a ArrayRef<T> {
        unsafe {
            let class = class!(NSArray);
            msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
        }
    }

    pub fn from_owned_slice<'a>(s: &[T]) -> &'a ArrayRef<T> {
        unsafe {
            let class = class!(NSArray);
            msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
        }
    }
}

impl<T> foreign_types::ForeignType for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type CType = NSArray<T>;
    type Ref = ArrayRef<T>;

    unsafe fn from_ptr(p: *mut NSArray<T>) -> Self {
        Array(p)
    }

    fn as_ptr(&self) -> *mut NSArray<T> {
        self.0
    }
}

impl<T> foreign_types::ForeignTypeRef for ArrayRef<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type CType = NSArray<T>;
}

impl<T> Deref for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type Target = ArrayRef<T>;

    fn deref(&self) -> &ArrayRef<T> {
        unsafe { mem::transmute(self.as_ptr()) }
    }
}

impl<T> Borrow<ArrayRef<T>> for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    fn borrow(&self) -> &ArrayRef<T> {
        unsafe { mem::transmute(self.as_ptr()) }
    }
}

impl<T> ToOwned for ArrayRef<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type Owned = Array<T>;

    fn to_owned(&self) -> Array<T> {
        unsafe { Array::from_ptr(msg_send![self, retain]) }
    }
}

pub enum CAMetalDrawable {}

foreign_obj_type! {
    type CType = CAMetalDrawable;
    pub struct MetalDrawable;
    pub struct MetalDrawableRef;
    type ParentType = DrawableRef;
}

impl MetalDrawableRef {
    pub fn texture(&self) -> &TextureRef {
        unsafe { msg_send![self, texture] }
    }
}

pub enum CAMetalLayer {}

foreign_obj_type! {
    type CType = CAMetalLayer;
    pub struct MetalLayer;
    pub struct MetalLayerRef;
}

impl MetalLayer {
    pub fn new() -> Self {
        unsafe {
            let class = class!(CAMetalLayer);
            msg_send![class, new]
        }
    }
}

impl MetalLayerRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }

    pub fn set_device(&self, device: &DeviceRef) {
        unsafe { msg_send![self, setDevice: device] }
    }

    pub fn pixel_format(&self) -> MTLPixelFormat {
        unsafe { msg_send![self, pixelFormat] }
    }

    pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) {
        unsafe { msg_send![self, setPixelFormat: pixel_format] }
    }

    pub fn drawable_size(&self) -> CGSize {
        unsafe { msg_send![self, drawableSize] }
    }

    pub fn set_drawable_size(&self, size: CGSize) {
        unsafe { msg_send![self, setDrawableSize: size] }
    }

    pub fn presents_with_transaction(&self) -> bool {
        unsafe {
            match msg_send![self, presentsWithTransaction] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_presents_with_transaction(&self, transaction: bool) {
        unsafe { msg_send![self, setPresentsWithTransaction: transaction] }
    }

    pub fn display_sync_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, displaySyncEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_display_sync_enabled(&self, enabled: bool) {
        unsafe { msg_send![self, setDisplaySyncEnabled: enabled] }
    }

    pub fn maximum_drawable_count(&self) -> NSUInteger {
        unsafe { msg_send![self, maximumDrawableCount] }
    }

    pub fn set_maximum_drawable_count(&self, count: NSUInteger) {
        unsafe { msg_send![self, setMaximumDrawableCount: count] }
    }

    pub fn set_edge_antialiasing_mask(&self, mask: u64) {
        unsafe { msg_send![self, setEdgeAntialiasingMask: mask] }
    }

    pub fn set_masks_to_bounds(&self, masks: bool) {
        unsafe { msg_send![self, setMasksToBounds: masks] }
    }

    pub fn remove_all_animations(&self) {
        unsafe { msg_send![self, removeAllAnimations] }
    }

    pub fn next_drawable(&self) -> Option<&MetalDrawableRef> {
        unsafe { msg_send![self, nextDrawable] }
    }

    pub fn set_contents_scale(&self, scale: CGFloat) {
        unsafe { msg_send![self, setContentsScale: scale] }
    }

    /// [framebufferOnly Apple Docs](https://developer.apple.com/documentation/metal/mtltexture/1515749-framebufferonly?language=objc)
    pub fn framebuffer_only(&self) -> bool {
        unsafe {
            match msg_send![self, framebufferOnly] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_framebuffer_only(&self, framebuffer_only: bool) {
        unsafe { msg_send![self, setFramebufferOnly: framebuffer_only] }
    }

    pub fn is_opaque(&self) -> bool {
        unsafe {
            match msg_send![self, isOpaque] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_opaque(&self, opaque: bool) {
        unsafe { msg_send![self, setOpaque: opaque] }
    }

    pub fn wants_extended_dynamic_range_content(&self) -> bool {
        unsafe {
            match msg_send![self, wantsExtendedDynamicRangeContent] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_wants_extended_dynamic_range_content(
        &self,
        wants_extended_dynamic_range_content: bool,
    ) {
        unsafe {
            msg_send![
                self,
                setWantsExtendedDynamicRangeContent: wants_extended_dynamic_range_content
            ]
        }
    }
}

mod argument;
mod buffer;
mod capturedescriptor;
mod capturemanager;
mod commandbuffer;
mod commandqueue;
mod constants;
mod depthstencil;
mod device;
mod drawable;
mod encoder;
mod heap;
mod indirect_encoder;
mod library;
#[cfg(feature = "mps")]
mod mps;
mod pipeline;
mod renderpass;
mod resource;
mod sampler;
mod sync;
mod texture;
mod types;
mod vertexdescriptor;

#[rustfmt::skip]
pub use {
    argument::*,
    buffer::*,
    capturedescriptor::*,
    capturemanager::*,
    commandbuffer::*,
    commandqueue::*,
    constants::*,
    depthstencil::*,
    device::*,
    drawable::*,
    encoder::*,
    heap::*,
    indirect_encoder::*,
    library::*,
    pipeline::*,
    renderpass::*,
    resource::*,
    sampler::*,
    texture::*,
    types::*,
    vertexdescriptor::*,
    sync::*,
};

#[cfg(feature = "mps")]
pub use mps::*;

#[inline]
unsafe fn obj_drop<T>(p: *mut T) {
    msg_send![(p as *mut Object), release]
}

#[inline]
unsafe fn obj_clone<T: 'static>(p: *mut T) -> *mut T {
    msg_send![(p as *mut Object), retain]
}

#[allow(non_camel_case_types)]
type c_size_t = usize;

// TODO: expand supported interface
pub enum NSURL {}

foreign_obj_type! {
    type CType = NSURL;
    pub struct URL;
    pub struct URLRef;
}

impl URL {
    pub fn new_with_string(string: &str) -> Self {
        unsafe {
            let ns_str = crate::nsstring_from_str(string);
            let class = class!(NSURL);
            msg_send![class, URLWithString: ns_str]
        }
    }
}

impl URLRef {
    pub fn absolute_string(&self) -> &str {
        unsafe {
            let absolute_string = msg_send![self, absoluteString];
            crate::nsstring_as_str(absolute_string)
        }
    }
}
<commit_msg>Add contents_scale method (#231)<commit_after>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
extern crate objc;
#[macro_use]
extern crate foreign_types;

use std::{
    borrow::{Borrow, ToOwned},
    marker::PhantomData,
    mem,
    ops::Deref,
    os::raw::c_void,
};

use core_graphics_types::{base::CGFloat, geometry::CGSize};
use foreign_types::ForeignType;
use objc::runtime::{Object, NO, YES};

#[cfg(target_pointer_width = "64")]
pub type NSInteger = i64;
#[cfg(not(target_pointer_width = "64"))]
pub type NSInteger = i32;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = u64;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = u32;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct NSRange {
    pub location: NSUInteger,
    pub length: NSUInteger,
}

impl NSRange {
    #[inline]
    pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange {
        NSRange { location, length }
    }
}

fn nsstring_as_str(nsstr: &objc::runtime::Object) -> &str {
    let bytes = unsafe {
        let bytes: *const std::os::raw::c_char = msg_send![nsstr, UTF8String];
        bytes as *const u8
    };
    let len: NSUInteger = unsafe { msg_send![nsstr, length] };
    unsafe {
        let bytes = std::slice::from_raw_parts(bytes, len as usize);
        std::str::from_utf8(bytes).unwrap()
    }
}

fn nsstring_from_str(string: &str) -> *mut objc::runtime::Object {
    const UTF8_ENCODING: usize = 4;

    let cls = class!(NSString);
    let bytes = string.as_ptr() as *const c_void;
    unsafe {
        let obj: *mut objc::runtime::Object = msg_send![cls, alloc];
        let obj: *mut objc::runtime::Object = msg_send![
            obj,
            initWithBytes:bytes
            length:string.len()
            encoding:UTF8_ENCODING
        ];
        let _: *mut c_void = msg_send![obj, autorelease];
        obj
    }
}

macro_rules! foreign_obj_type {
    {type CType = $raw_ident:ident;
    pub struct $owned_ident:ident;
    pub struct $ref_ident:ident;
    type ParentType = $parent_ref:ident;
    } => {
        foreign_obj_type! {
            type CType = $raw_ident;
            pub struct $owned_ident;
            pub struct $ref_ident;
        }

        impl ::std::ops::Deref for $ref_ident {
            type Target = $parent_ref;

            fn deref(&self) -> &$parent_ref {
                unsafe { &*(self as *const $ref_ident as *const $parent_ref)  }
            }
        }
    };
    {type CType = $raw_ident:ident;
    pub struct $owned_ident:ident;
    pub struct $ref_ident:ident;
    } => {
        foreign_type! {
            type CType = $raw_ident;
            fn drop = crate::obj_drop;
            fn clone = crate::obj_clone;
            pub struct $owned_ident;
            pub struct $ref_ident;
        }

        unsafe impl ::objc::Message for $raw_ident {
        }
        unsafe impl ::objc::Message for $ref_ident {
        }

        impl ::std::fmt::Debug for $ref_ident {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                unsafe {
                    let string: *mut ::objc::runtime::Object = msg_send![self, debugDescription];
                    write!(f, "{}", crate::nsstring_as_str(&*string))
                }
            }
        }

        impl ::std::fmt::Debug for $owned_ident {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                ::std::ops::Deref::deref(self).fmt(f)
            }
        }
    };
}

macro_rules! try_objc {
    {
        $err_name: ident => $body:expr
    } => {
        {
            let mut $err_name: *mut ::objc::runtime::Object = ::std::ptr::null_mut();
            let value = $body;
            if !$err_name.is_null() {
                let desc: *mut Object = msg_send![$err_name, localizedDescription];
                let compile_error: *const std::os::raw::c_char = msg_send![desc, UTF8String];
                let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
                let () = msg_send![$err_name, release];
                return Err(message);
            }
            value
        }
    };
}

pub struct NSArray<T> {
    _phantom: PhantomData<T>,
}

pub struct Array<T>(*mut NSArray<T>)
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static;
pub struct ArrayRef<T>(foreign_types::Opaque, PhantomData<T>)
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static;

impl<T> Drop for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    fn drop(&mut self) {
        unsafe {
            let () = msg_send![self.0, release];
        }
    }
}

impl<T> Clone for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    fn clone(&self) -> Self {
        unsafe { Array(msg_send![self.0, retain]) }
    }
}

unsafe impl<T> objc::Message for NSArray<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
}
unsafe impl<T> objc::Message for ArrayRef<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
}

impl<T> Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    pub fn from_slice<'a>(s: &[&T::Ref]) -> &'a ArrayRef<T> {
        unsafe {
            let class = class!(NSArray);
            msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
        }
    }

    pub fn from_owned_slice<'a>(s: &[T]) -> &'a ArrayRef<T> {
        unsafe {
            let class = class!(NSArray);
            msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
        }
    }
}

impl<T> foreign_types::ForeignType for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type CType = NSArray<T>;
    type Ref = ArrayRef<T>;

    unsafe fn from_ptr(p: *mut NSArray<T>) -> Self {
        Array(p)
    }

    fn as_ptr(&self) -> *mut NSArray<T> {
        self.0
    }
}

impl<T> foreign_types::ForeignTypeRef for ArrayRef<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type CType = NSArray<T>;
}

impl<T> Deref for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type Target = ArrayRef<T>;

    fn deref(&self) -> &ArrayRef<T> {
        unsafe { mem::transmute(self.as_ptr()) }
    }
}

impl<T> Borrow<ArrayRef<T>> for Array<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    fn borrow(&self) -> &ArrayRef<T> {
        unsafe { mem::transmute(self.as_ptr()) }
    }
}

impl<T> ToOwned for ArrayRef<T>
where
    T: ForeignType + 'static,
    T::Ref: objc::Message + 'static,
{
    type Owned = Array<T>;

    fn to_owned(&self) -> Array<T> {
        unsafe { Array::from_ptr(msg_send![self, retain]) }
    }
}

pub enum CAMetalDrawable {}

foreign_obj_type! {
    type CType = CAMetalDrawable;
    pub struct MetalDrawable;
    pub struct MetalDrawableRef;
    type ParentType = DrawableRef;
}

impl MetalDrawableRef {
    pub fn texture(&self) -> &TextureRef {
        unsafe { msg_send![self, texture] }
    }
}

pub enum CAMetalLayer {}

foreign_obj_type! {
    type CType = CAMetalLayer;
    pub struct MetalLayer;
    pub struct MetalLayerRef;
}

impl MetalLayer {
    pub fn new() -> Self {
        unsafe {
            let class = class!(CAMetalLayer);
            msg_send![class, new]
        }
    }
}

impl MetalLayerRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }

    pub fn set_device(&self, device: &DeviceRef) {
        unsafe { msg_send![self, setDevice: device] }
    }

    pub fn pixel_format(&self) -> MTLPixelFormat {
        unsafe { msg_send![self, pixelFormat] }
    }

    pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) {
        unsafe { msg_send![self, setPixelFormat: pixel_format] }
    }

    pub fn drawable_size(&self) -> CGSize {
        unsafe { msg_send![self, drawableSize] }
    }

    pub fn set_drawable_size(&self, size: CGSize) {
        unsafe { msg_send![self, setDrawableSize: size] }
    }

    pub fn presents_with_transaction(&self) -> bool {
        unsafe {
            match msg_send![self, presentsWithTransaction] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_presents_with_transaction(&self, transaction: bool) {
        unsafe { msg_send![self, setPresentsWithTransaction: transaction] }
    }

    pub fn display_sync_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, displaySyncEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_display_sync_enabled(&self, enabled: bool) {
        unsafe { msg_send![self, setDisplaySyncEnabled: enabled] }
    }

    pub fn maximum_drawable_count(&self) -> NSUInteger {
        unsafe { msg_send![self, maximumDrawableCount] }
    }

    pub fn set_maximum_drawable_count(&self, count: NSUInteger) {
        unsafe { msg_send![self, setMaximumDrawableCount: count] }
    }

    pub fn set_edge_antialiasing_mask(&self, mask: u64) {
        unsafe { msg_send![self, setEdgeAntialiasingMask: mask] }
    }

    pub fn set_masks_to_bounds(&self, masks: bool) {
        unsafe { msg_send![self, setMasksToBounds: masks] }
    }

    pub fn remove_all_animations(&self) {
        unsafe { msg_send![self, removeAllAnimations] }
    }

    pub fn next_drawable(&self) -> Option<&MetalDrawableRef> {
        unsafe { msg_send![self, nextDrawable] }
    }

    pub fn contents_scale(&self) -> CGFloat {
        unsafe { msg_send![self, contentsScale] }
    }

    pub fn set_contents_scale(&self, scale: CGFloat) {
        unsafe { msg_send![self, setContentsScale: scale] }
    }

    /// [framebufferOnly Apple Docs](https://developer.apple.com/documentation/metal/mtltexture/1515749-framebufferonly?language=objc)
    pub fn framebuffer_only(&self) -> bool {
        unsafe {
            match msg_send![self, framebufferOnly] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_framebuffer_only(&self, framebuffer_only: bool) {
        unsafe { msg_send![self, setFramebufferOnly: framebuffer_only] }
    }

    pub fn is_opaque(&self) -> bool {
        unsafe {
            match msg_send![self, isOpaque] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_opaque(&self, opaque: bool) {
        unsafe { msg_send![self, setOpaque: opaque] }
    }

    pub fn wants_extended_dynamic_range_content(&self) -> bool {
        unsafe {
            match msg_send![self, wantsExtendedDynamicRangeContent] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_wants_extended_dynamic_range_content(
        &self,
        wants_extended_dynamic_range_content: bool,
    ) {
        unsafe {
            msg_send![
                self,
                setWantsExtendedDynamicRangeContent: wants_extended_dynamic_range_content
            ]
        }
    }
}

mod argument;
mod buffer;
mod capturedescriptor;
mod capturemanager;
mod commandbuffer;
mod commandqueue;
mod constants;
mod depthstencil;
mod device;
mod drawable;
mod encoder;
mod heap;
mod indirect_encoder;
mod library;
#[cfg(feature = "mps")]
mod mps;
mod pipeline;
mod renderpass;
mod resource;
mod sampler;
mod sync;
mod texture;
mod types;
mod vertexdescriptor;

#[rustfmt::skip]
pub use {
    argument::*,
    buffer::*,
    capturedescriptor::*,
    capturemanager::*,
    commandbuffer::*,
    commandqueue::*,
    constants::*,
    depthstencil::*,
    device::*,
    drawable::*,
    encoder::*,
    heap::*,
    indirect_encoder::*,
    library::*,
    pipeline::*,
    renderpass::*,
    resource::*,
    sampler::*,
    texture::*,
    types::*,
    vertexdescriptor::*,
    sync::*,
};

#[cfg(feature = "mps")]
pub use mps::*;

#[inline]
unsafe fn obj_drop<T>(p: *mut T) {
    msg_send![(p as *mut Object), release]
}

#[inline]
unsafe fn obj_clone<T: 'static>(p: *mut T) -> *mut T {
    msg_send![(p as *mut Object), retain]
}

#[allow(non_camel_case_types)]
type c_size_t = usize;

// TODO: expand supported interface
pub enum NSURL {}

foreign_obj_type! {
    type CType = NSURL;
    pub struct URL;
    pub struct URLRef;
}

impl URL {
    pub fn new_with_string(string: &str) -> Self {
        unsafe {
            let ns_str = crate::nsstring_from_str(string);
            let class = class!(NSURL);
            msg_send![class, URLWithString: ns_str]
        }
    }
}

impl URLRef {
    pub fn absolute_string(&self) -> &str {
        unsafe {
            let absolute_string = msg_send![self, absoluteString];
            crate::nsstring_as_str(absolute_string)
        }
    }
}
<|endoftext|>


<commit_before>//! A toolkit for building command-line programs in Rust.
//!
//! `cli` aims to
//!
//! - reduce boilerplate
//! - canonicalize output formatting
//! - encourage adherence to the conventions of standard streams
//!   (e.g. when to print to stderr vs stdout)
//! - encourage appropriate use of exit statuses
//!
//! `cli` uses [getopts](http://doc.rust-lang.org/getopts/) for
//! command-line argument parsing and thus currently inherits its
//! `experimental` stability level.

#![crate_name = "cli"]
#![crate_type="rlib"]

extern crate getopts;
use getopts::{Matches, OptGroup, getopts, short_usage};
use getopts::usage as getopts_usage;
use std::{io, os};

mod test;

/// Constructs a canonical usage string from a collection of `OptGroup`s.
///
/// Usage strings format:
///
///```ignore
///     Usage: <argv0> [option synopsis]...
///
///     Options:
///         [option description]...
///```
pub fn usage(opts: &[OptGroup]) -> String {
    let argv0 = os::args()[0].clone();
    format!("{}", getopts_usage(short_usage(argv0.as_slice(), opts).as_slice(), opts))
}

/// Parses the command-line arguments with which the program was executed
/// according to a collection of `OptGroup`s.
///
/// Any flag parsing failure results in task panic. The program's usage string
/// is printed to stderr prior to panic. Panic is induced in order to avoid
/// program execution with undefined configuration. In such cases, the presence
/// of unrecognized flags or invalid flag values implies confusion on the part
/// of the executor. While perhaps overbearing, it is preferable to halt
/// execution abruptly than to continue with the risk of unwanted behavior.
pub fn parse_args(opts: &[OptGroup]) -> Matches {
    match getopts(os::args().tail(), opts) {
        Ok(matches) => matches,
        Err(getopts_error) => {
            // Write usage string to stderr, then panic.
            match io::stderr().write_str(usage(opts).as_slice()) {
                Ok(()) => panic!(getopts_error.to_string()),
                Err(write_error) =>
                    // Write to stderr failed -- panic with both error messages.
                    panic!("{}\n{}", getopts_error.to_string(), write_error.to_string())
            }
        }
    }
}
<commit_msg>Add `argv0`, `helpopt`, and `versionopt` 0-arg functions.<commit_after>//! A toolkit for building command-line programs in Rust.
//!
//! `cli` aims to
//!
//! - reduce boilerplate
//! - canonicalize output formatting
//! - encourage adherence to the conventions of standard streams
//!   (e.g. when to print to stderr vs stdout)
//! - encourage appropriate use of exit statuses
//!
//! `cli` uses [getopts](http://doc.rust-lang.org/getopts/) for
//! command-line argument parsing and thus currently inherits its
//! `experimental` stability level.

#![crate_name = "cli"]
#![crate_type="rlib"]

extern crate getopts;
use getopts::{Matches, OptGroup, getopts, optflag, short_usage};
use getopts::usage as getopts_usage;
use std::{io, os};

mod test;

/// The name by which the executed program was called.
///
/// Typically the file name or path of the invoked executable.
pub fn argv0() -> String {
    os::args()[0].clone()
}

/// Construct a canonical usage string from a collection of `OptGroup`s.
///
/// Usage strings format:
///
///```ignore
///     Usage: <argv0> [option synopsis]...
///
///     Options:
///         [option description]...
///```
pub fn usage(opts: &[OptGroup]) -> String {
    format!("{}", getopts_usage(short_usage(argv0().as_slice(), opts).as_slice(), opts))
}

/// Parse the command-line arguments with which the program was executed
/// according to a collection of `OptGroup`s.
///
/// Any flag parsing failure results in task panic. The program's usage string
/// is printed to stderr prior to panic. Panic is induced in order to avoid
/// program execution with undefined configuration. In such cases, the presence
/// of unrecognized flags or invalid flag values implies confusion on the part
/// of the executor. While perhaps overbearing, it is preferable to halt
/// execution abruptly than to continue with the risk of unwanted behavior.
pub fn parse_args(opts: &[OptGroup]) -> Matches {
    match getopts(os::args().tail(), opts) {
        Ok(matches) => matches,
        Err(getopts_error) => {
            // Write usage string to stderr, then panic.
            match io::stderr().write_str(usage(opts).as_slice()) {
                Ok(()) => panic!(getopts_error.to_string()),
                Err(write_error) =>
                    // Write to stderr failed -- panic with both error messages.
                    panic!("{}\n{}", getopts_error.to_string(), write_error.to_string())
            }
        }
    }
}

/// Create a help flag `OptGroup`.
///
/// The returned `OptGroup` is an optional long option for the input `-h`
/// and `--help`.
pub fn helpopt() -> OptGroup {
    optflag("h", "help", "Print this help menu")
}

/// Create a version flag `OptGroup`.
///
/// The returned `OptGroup` is an optional long option for the input
/// `--version`. `-v` and `-V` are avoided in order to prevent confusion in the
/// event when a flag is needed for enabling verbose output.
pub fn versionopt() -> OptGroup {
    optflag("", "version", format!("Print the version of {} being run", argv0()).as_slice())
}
<|endoftext|>