<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::run::Process;
use std::run::ProcessOutput;
use std::run::ProcessOptions;
use std::option::{Option, None, Some};
use std::io::buffered::BufferedWriter;
use std::io::File;
use std::comm::Chan;
use std::io::signal::Listener;
use std::io::signal::{Interrupt};
use std::libc;
use std::io::stdio;

struct Shell {
    cmd_prompt: ~str,
    hist: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {

        Shell {
            cmd_prompt: prompt_str.to_owned(),
            hist: ~[],
        }
    }

    fn listen(&mut self, list: Listener) {
	spawn(proc() {
	    loop {
		match list.port.recv() {
		    Interrupt => { }
		    _ => { println("THERE WAS DERP"); }
		}
	    }
	});
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        let mut x = Listener::new();
	let reg = x.register(Interrupt);

	if reg {
	    self.listen(x);
	} else {
	    println("Failed to register listener");
	}

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.hist.push(line);
            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                "history" =>{ self.history(); }
                "gcowsay" => { self.cowsay(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            //Let's process the argv

            let endopt = argv.pop_opt();
            let end = match endopt {
		Some(stringy) => { stringy }
		None => { ~"" }
            };

            if end.eq(&~"&") {
		// println("Start in a new process" + end);

		if argv.contains(&~">") {
		    // println("Contains >");
		    if argv.contains(&~">") {
		    //println("Contains >");
		    let mut found = false;
		    let mut filename = ~"";
		    let mut x = 0;
		    for stringy in argv.clone().move_iter() {
			if stringy.eq(&~">") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_out(program, argv, filename, true);
		} else {
		    self.run_cmd(program, argv, true);
		}
		}

		self.run_cmd(program, argv, true);
            } else {
		//println("No new process");
		if !end.eq(&~"") {
		    argv.push(end.to_owned());
		}
		if argv.contains(&~">") && argv.contains(&~"<") {
		    println("In and out");
		}else if argv.contains(&~"<") {
		    let mut found = false;
		    let mut filename = ~"";
		    let mut x = 0;
		    for stringy in argv.clone().move_iter() {
			if stringy.eq(&~"<") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_in(program, argv, filename, false);
		} else if argv.contains(&~">") {
		    //println("Contains >");
		    let mut found = false;
		    let mut filename = ~"";
		    let mut x = 0;
		    for stringy in argv.clone().move_iter() {
			if stringy.eq(&~">") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_out(program, argv, filename, false);
		} else {
		    self.run_cmd(program, argv, false);
		}
            }
        }
    }

    fn run_cmd_in(&mut self, program: &str, argv: &[~str], filename: &str, bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		// run::process_status(program, argv);
		let mut whichprocop = ProcessOptions::new();
		unsafe {
		    whichprocop.in_fd = Some(libc::fileno(libc::fopen(filename.to_c_str().unwrap(), "r".to_c_str().unwrap())));
		}
		whichprocop.out_fd = Some(1);
		match(Process::new(program, argv, whichprocop)) {
		    Some(mut process) => {
			process.finish();
			std::io::stdio::flush();
			println("process finished");
		    }
		    None => { println("ERROR"); }
		}

	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();
		let f = filename.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    unsafe {
			whichprocop.in_fd = Some(libc::fileno(libc::fopen(f.to_c_str().unwrap(), "r".to_c_str().unwrap())));
		    }
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			    std::io::stdio::flush();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd_out(&mut self, program: &str, argv: &[~str], filename: &str, bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		// run::process_status(program, argv);
		let mut whichprocop = ProcessOptions::new();
		unsafe {
		    whichprocop.out_fd = Some(libc::fileno(libc::fopen(filename.to_c_str().unwrap(), "w".to_c_str().unwrap())));
		}
		match(Process::new(program, argv, whichprocop)) {
		    Some(mut process) => {
			process.finish();
		    }
		    None => { println("ERROR"); }
		}

	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();
		let f = filename.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    unsafe {
			whichprocop.out_fd = Some(libc::fileno(libc::fopen(f.to_c_str().unwrap(), "w".to_c_str().unwrap())));
		    }
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		run::process_status(program, argv);
	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }
    /*
    fn makefunky(&mut self, program: &str, argv: &[~str]) -> (proc(&str, &[~str])) {
	proc(program: &str, argv: &[~str]) {

	    // whichprocop.dir = self.cwdopt.as_ref();

	    let mut whichproc = Process::new(program, argv, whichprocop);
	    let mut process = whichproc.unwrap();

	    let mut procout = process.finish_with_output();
	    println(std::str::from_utf8(procout.output));
	}
    }
    */

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            //println!("You want to change cwd to {:s}", pstring);

            let npath = Path::new(pstring);

            let mut cpath = getcwd();
            cpath.push(npath);

            if cpath.exists() {
		let mut cpathforopt = cpath.clone();
		std::os::change_dir(&cpath);
		// self.cwd = cpath;
            } else {
		println("Path does not exist!");
            }

        }

        let x = getcwd();

        match x.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }

    fn history(&mut self) {
	let mut n :int = 1;
	for stringy in self.hist.iter() {
	    let x = stringy.clone();
	    print("[" + n.to_str() + "]" + ~"\t" + x);
	    n += 1;
	}
    }

    fn cowsay(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
	let mut stringer = ~"";

	if argv.len() > 1 {
	    argv.remove(0);
	}

	for stringy in argv.iter() {
	    stringer = stringer + ~" " + stringy.to_owned();
	}

	println(" _______");
	println("< " + stringer + " >");
	println(" -------");
	println("        \\   ^__^");
	println("         \\  (oo)\\_______");
	println("            (__)\\       )\\/\\");
	println("                ||----w |");
	println("                ||     ||");
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {

    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>bg for < io redirection<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
/*
Vikram Bhasin vb8nd and Justin Ingram jci5kb
*/

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::os::getcwd;
use extra::getopts;
use std::run::Process;
use std::run::ProcessOutput;
use std::run::ProcessOptions;
use std::option::{Option, None, Some};
use std::io::buffered::BufferedWriter;
use std::io::File;
use std::comm::Chan;
use std::io::signal::Listener;
use std::io::signal::{Interrupt};
use std::libc;
use std::io::stdio;

struct Shell {
    cmd_prompt: ~str,
    hist: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {

        Shell {
            cmd_prompt: prompt_str.to_owned(),
            hist: ~[],
        }
    }

    fn listen(&mut self, list: Listener) {
	spawn(proc() {
	    loop {
		match list.port.recv() {
		    Interrupt => { }
		    _ => { println("THERE WAS DERP"); }
		}
	    }
	});
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        let mut x = Listener::new();
	let reg = x.register(Interrupt);

	if reg {
	    self.listen(x);
	} else {
	    println("Failed to register listener");
	}

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.hist.push(line);
            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                "history" =>{ self.history(); }
                "gcowsay" => { self.cowsay(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            //Let's process the argv

            let endopt = argv.pop_opt();
            let end = match endopt {
		Some(stringy) => { stringy }
		None => { ~"" }
            };

            if end.eq(&~"&") {
		// println("Start in a new process" + end);

		if argv.contains(&~"<") {
		   if argv.contains(&~"<") {
		   let mut found = false;
		   let mut filename = ~"";
		   let mut x = 0;
		   for stringy in argv.clone().move_iter() {
			if stringy.eq(&~"<") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_in(program, argv, filename, true);
		    }else {
		      self.run_cmd(program, argv, true);
		}
		}

		if argv.contains(&~">") {
		    // println("Contains >");
		    if argv.contains(&~">") {
		    //println("Contains >");
		    let mut found = false;
		    let mut filename = ~"";
		    let mut x = 0;
		    for stringy in argv.clone().move_iter() {
			if stringy.eq(&~">") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_out(program, argv, filename, true);
		} else {
		    self.run_cmd(program, argv, true);
		}
		}

		self.run_cmd(program, argv, true);
            } else {
		//println("No new process");
		if !end.eq(&~"") {
		    argv.push(end.to_owned());
		}
		if argv.contains(&~">") && argv.contains(&~"<") {
		    println("In and out");
		}else if argv.contains(&~"<") {
		    let mut found = false;
		    let mut filename = ~"";
		    let mut x = 0;
		    for stringy in argv.clone().move_iter() {
			if stringy.eq(&~"<") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_in(program, argv, filename, false);
		} else if argv.contains(&~">") {
		    //println("Contains >");
		    let mut found = false;
		    let mut filename = ~"";
		    let mut x = 0;
		    for stringy in argv.clone().move_iter() {
			if stringy.eq(&~">") {
			    break;
			}
			x += 1;
		    }
		    match argv.get_opt(x+1) {
			Some(text) => { filename = text.to_owned(); }
			None => {}
		    }
		    argv.remove(x+1);
		    argv.remove(x);
		    self.run_cmd_out(program, argv, filename, false);
		} else {
		    self.run_cmd(program, argv, false);
		}
            }
        }
    }

    fn run_cmd_in(&mut self, program: &str, argv: &[~str], filename: &str, bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		// run::process_status(program, argv);
		let mut whichprocop = ProcessOptions::new();
		unsafe {
		    whichprocop.in_fd = Some(libc::fileno(libc::fopen(filename.to_c_str().unwrap(), "r".to_c_str().unwrap())));
		}
		whichprocop.out_fd = Some(1);
		match(Process::new(program, argv, whichprocop)) {
		    Some(mut process) => {
			process.finish();
			std::io::stdio::flush();
			println("process finished");
		    }
		    None => { println("ERROR"); }
		}

	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();
		let f = filename.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    unsafe {
			whichprocop.in_fd = Some(libc::fileno(libc::fopen(f.to_c_str().unwrap(), "r".to_c_str().unwrap())));
		    }
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			    std::io::stdio::flush();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd_out(&mut self, program: &str, argv: &[~str], filename: &str, bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		// run::process_status(program, argv);
		let mut whichprocop = ProcessOptions::new();
		unsafe {
		    whichprocop.out_fd = Some(libc::fileno(libc::fopen(filename.to_c_str().unwrap(), "w".to_c_str().unwrap())));
		}
		match(Process::new(program, argv, whichprocop)) {
		    Some(mut process) => {
			process.finish();
		    }
		    None => { println("ERROR"); }
		}

	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();
		let f = filename.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    unsafe {
			whichprocop.out_fd = Some(libc::fileno(libc::fopen(f.to_c_str().unwrap(), "w".to_c_str().unwrap())));
		    }
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], bg: bool) {
        if self.cmd_exists(program) {
	    // Old stuff

            //println("Run command hit");
            //println(program);

	    if !bg {
		run::process_status(program, argv);
	    } else {
		//let f = self.makefunky(program, argv);
		//let (recvp, recvc): (Port<~str>, Chan<~str>) = Chan::new();
		//spawn(expr(f(program, argv)));

		let x = program.clone().to_owned();
		let y = argv.clone().to_owned();

		spawn(proc() {
		    let mut whichprocop = ProcessOptions::new();
		    match(Process::new(x, y, whichprocop)) {
			Some(mut process) => {
			    process.finish();
			}
			None => { println("ERROR"); }
		    }
		});
	    }

        } else {
            println!("{:s}: command not found", program);
        }
    }
    /*
    fn makefunky(&mut self, program: &str, argv: &[~str]) -> (proc(&str, &[~str])) {
	proc(program: &str, argv: &[~str]) {

	    // whichprocop.dir = self.cwdopt.as_ref();

	    let mut whichproc = Process::new(program, argv, whichprocop);
	    let mut process = whichproc.unwrap();

	    let mut procout = process.finish_with_output();
	    println(std::str::from_utf8(procout.output));
	}
    }
    */

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);

            //println!("You want to change cwd to {:s}", pstring);

            let npath = Path::new(pstring);

            let mut cpath = getcwd();
            cpath.push(npath);

            if cpath.exists() {
		let mut cpathforopt = cpath.clone();
		std::os::change_dir(&cpath);
		// self.cwd = cpath;
            } else {
		println("Path does not exist!");
            }

        }

        let x = getcwd();

        match x.as_str() {
	    Some(path_str) => {println!("{:s}", path_str); }
	    None	=> {println("Path not representable as string!"); }
        }
    }

    fn history(&mut self) {
	let mut n :int = 1;
	for stringy in self.hist.iter() {
	    let x = stringy.clone();
	    print("[" + n.to_str() + "]" + ~"\t" + x);
	    n += 1;
	}
    }

    fn cowsay(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
	let mut stringer = ~"";

	if argv.len() > 1 {
	    argv.remove(0);
	}

	for stringy in argv.iter() {
	    stringer = stringer + ~" " + stringy.to_owned();
	}

	println(" _______");
	println("< " + stringer + " >");
	println(" -------");
	println("        \\   ^__^");
	println("         \\  (oo)\\_______");
	println("            (__)\\       )\\/\\");
	println("                ||----w |");
	println("                ||     ||");
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {

    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>// Interior vector utility functions.

import option::none;
import option::some;

type operator2[T,U,V] = fn(&T, &U) -> V;

native "rust-intrinsic" mod rusti {
    fn ivec_len[T](&T[] v) -> uint;
}

native "rust" mod rustrt {
    fn ivec_reserve[T](&mutable T[] v, uint n);
    fn ivec_on_heap[T](&T[] v) -> bool;
    fn ivec_to_ptr[T](&T[] v) -> *T;
    fn ivec_copy_from_buf[T](&mutable T[] v, *T ptr, uint count);
}

/// Reserves space for `n` elements in the given vector.
fn reserve[T](&mutable T[] v, uint n) {
    rustrt::ivec_reserve(v, n);
}

fn on_heap[T](&T[] v) -> bool {
    ret rustrt::ivec_on_heap(v);
}

fn to_ptr[T](&T[] v) -> *T {
    ret rustrt::ivec_to_ptr(v);
}

fn len[T](&T[] v) -> uint {
    ret rusti::ivec_len(v);
}

type init_op[T] = fn(uint) -> T;

fn init_fn[T](&init_op[T] op, uint n_elts) -> T[] {
    auto v = ~[];
    reserve(v, n_elts);
    let uint i = 0u;
    while (i < n_elts) { v += ~[op(i)]; i += 1u; }
    ret v;
}

mod unsafe {
    fn copy_from_buf[T](&mutable T[] v, *T ptr, uint count) {
        ret rustrt::ivec_copy_from_buf(v, ptr, count);
    }
}

<commit_msg>stdlib: Add some more ivec functions, untested as of yet<commit_after>// Interior vector utility functions.

import option::none;
import option::some;

type operator2[T,U,V] = fn(&T, &U) -> V;

native "rust-intrinsic" mod rusti {
    fn ivec_len[T](&T[] v) -> uint;
}

native "rust" mod rustrt {
    fn ivec_reserve[T](&mutable T[mutable?] v, uint n);
    fn ivec_on_heap[T](&T[] v) -> bool;
    fn ivec_to_ptr[T](&T[] v) -> *T;
    fn ivec_copy_from_buf[T](&mutable T[mutable?] v, *T ptr, uint count);
}

/// Reserves space for `n` elements in the given vector.
fn reserve[T](&mutable T[mutable?] v, uint n) {
    rustrt::ivec_reserve(v, n);
}

fn on_heap[T](&T[] v) -> bool {
    ret rustrt::ivec_on_heap(v);
}

fn to_ptr[T](&T[] v) -> *T {
    ret rustrt::ivec_to_ptr(v);
}

fn len[T](&T[] v) -> uint {
    ret rusti::ivec_len(v);
}

type init_op[T] = fn(uint) -> T;

fn init_fn[T](&init_op[T] op, uint n_elts) -> T[] {
    auto v = ~[];
    reserve(v, n_elts);
    let uint i = 0u;
    while (i < n_elts) { v += ~[op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut[T](&init_op[T] op, uint n_elts) -> T[mutable] {
    auto v = ~[mutable];
    reserve(v, n_elts);
    let uint i = 0u;
    while (i < n_elts) { v += ~[mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt[T](&T t, uint n_elts) -> T[] {
    auto v = ~[];
    reserve(v, n_elts);
    let uint i = 0u;
    while (i < n_elts) { v += ~[t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut[T](&T t, uint n_elts) -> T[mutable] {
    auto v = ~[mutable];
    reserve(v, n_elts);
    let uint i = 0u;
    while (i < n_elts) { v += ~[mutable t]; i += 1u; }
    ret v;
}

// Accessors

/// Returns the last element of `v`.
fn last[T](&T[mutable?] v) -> option::t[T] {
    if (len(v) == 0u) { ret none; }
    ret some(v.(len(v) - 1u));
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice[T](&T[mutable?] v, uint start, uint end) -> T[] {
    assert (start <= end);
    assert (end <= len(v));
    auto result = ~[];
    reserve(result, end - start);
    auto i = start;
    while (i < end) { result += ~[v.(i)]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut[T](&T[mutable?] v, uint start, uint end) -> T[mutable] {
    assert (start <= end);
    assert (end <= len(v));
    auto result = ~[mutable];
    reserve(result, end - start);
    auto i = start;
    while (i < end) { result += ~[mutable v.(i)]; i += 1u; }
    ret result;
}

// Mutators

// TODO

mod unsafe {
    fn copy_from_buf[T](&mutable T[] v, *T ptr, uint count) {
        ret rustrt::ivec_copy_from_buf(v, ptr, count);
    }
}

<|endoftext|>


<commit_before>//! Densely numbered entity references as mapping keys.
//!
//! This module defines an `EntityRef` trait that should be implemented by reference types wrapping
//! a small integer index. The `EntityMap` data structure uses the dense index space to implement a
//! map with a vector. There are primary and secondary entity maps:
//!
//! - A *primary* `EntityMap` contains the main definition of an entity, and it can be used to
//!   allocate new entity references with the `push` method. The values stores in a primary map
//!   must implement the `PrimaryEntityData` marker trait.
//! - A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
//!   values need to implement `Clone + Default` traits so the map can be grown with `ensure`.

use std::vec::Vec;
use std::default::Default;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key
/// of an `EntityMap`.
pub trait EntityRef: Copy + Eq {
    /// Create a new entity reference from a small integer.
    /// This should crash if the requested index is not representable.
    fn new(usize) -> Self;

    /// Get the index that was used to create this entity reference.
    fn index(self) -> usize;

    /// Convert an `EntityRef` to an `Optional<EntityRef>` by using the default value as the null
    /// reference.
    ///
    /// Entity references are often used in compact data structures like linked lists where a
    /// sentinel 'null' value is needed. Normally we would use an `Optional` for that, but
    /// currently that uses twice the memory of a plain `EntityRef`.
    ///
    /// This method is called `wrap()` because it is the inverse of `unwrap()`.
    fn wrap(self) -> Option<Self>
        where Self: Default
    {
        if self == Self::default() {
            None
        } else {
            Some(self)
        }
    }
}

/// A mapping `K -> V` for densely indexed entity references.
#[derive(Debug, Clone)]
pub struct EntityMap<K, V>
    where K: EntityRef
{
    elems: Vec<V>,
    unused: PhantomData<K>,
}

/// Shared `EntityMap` implementation for all value types.
impl<K, V> EntityMap<K, V>
    where K: EntityRef
{
    /// Create a new empty map.
    pub fn new() -> Self {
        EntityMap {
            elems: Vec::new(),
            unused: PhantomData,
        }
    }

    /// Check if `k` is a valid key in the map.
    pub fn is_valid(&self, k: K) -> bool {
        k.index() < self.elems.len()
    }

    /// Get the element at `k` if it exists.
    pub fn get(&self, k: K) -> Option<&V> {
        self.elems.get(k.index())
    }

    /// Is this map completely empty?
    pub fn is_empty(&self) -> bool {
        self.elems.is_empty()
    }

    /// Remove all entries from this map.
    pub fn clear(&mut self) {
        self.elems.clear()
    }

    /// Iterate over all the keys in this map.
    pub fn keys(&self) -> Keys<K> {
        Keys {
            pos: 0,
            len: self.elems.len(),
            unused: PhantomData,
        }
    }
}

/// A marker trait for data stored in primary entity maps.
///
/// A primary entity map can be used to allocate new entity references with the `push` method. It
/// is important that entity references can't be created anywhere else, so the data stored in a
/// primary entity map must be tagged as `PrimaryEntityData` to unlock the `push` method.
pub trait PrimaryEntityData {}

/// Additional methods for primary entry maps only.
///
/// These are identified by the `PrimaryEntityData` marker trait.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: PrimaryEntityData
{
    /// Get the key that will be assigned to the next pushed value.
    pub fn next_key(&self) -> K {
        K::new(self.elems.len())
    }

    /// Append `v` to the mapping, assigning a new key which is returned.
    pub fn push(&mut self, v: V) -> K {
        let k = self.next_key();
        self.elems.push(v);
        k
    }

    /// Get the total number of entity references created.
    pub fn len(&self) -> usize {
        self.elems.len()
    }
}

/// Additional methods for value types that implement `Clone` and `Default`.
///
/// When the value type implements these additional traits, the `EntityMap` can be resized
/// explicitly with the `ensure` method.
///
/// Use this for secondary maps that are mapping keys created by another primary map.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: Clone + Default
{
    /// Create a new secondary `EntityMap` that is prepared to hold `n` elements.
    ///
    /// Use this when the length of the primary map is known:
    /// ```
    /// let secondary_map = EntityMap::with_capacity(primary_map.len());
    /// ```
    pub fn with_capacity(n: usize) -> Self {
        let mut map = EntityMap {
            elems: Vec::with_capacity(n),
            unused: PhantomData,
        };
        map.elems.resize(n, V::default());
        map
    }

    /// Resize the map to have `n` entries by adding default entries as needed.
    pub fn resize(&mut self, n: usize) {
        self.elems.resize(n, V::default());
    }

    /// Ensure that `k` is a valid key but adding default entries if necesssary.
    ///
    /// Return a mutable reference to the corresponding entry.
    pub fn ensure(&mut self, k: K) -> &mut V {
        if !self.is_valid(k) {
            self.resize(k.index() + 1)
        }
        &mut self.elems[k.index()]
    }
}

/// Immutable indexing into an `EntityMap`.
/// The indexed value must be in the map, either because it was created by `push`, or the key was
/// passed to `ensure`.
impl<K, V> Index<K> for EntityMap<K, V>
    where K: EntityRef
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.elems[k.index()]
    }
}

/// Mutable indexing into an `EntityMap`.
/// Use `ensure` instead if the key is not known to be valid.
impl<K, V> IndexMut<K> for EntityMap<K, V>
    where K: EntityRef
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.elems[k.index()]
    }
}

/// Iterate over all keys in order.
pub struct Keys<K>
    where K: EntityRef
{
    pos: usize,
    len: usize,
    unused: PhantomData<K>,
}

impl<K> Iterator for Keys<K>
    where K: EntityRef
{
    type Item = K;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.len {
            let k = K::new(self.pos);
            self.pos += 1;
            Some(k)
        } else {
            None
        }
    }
}

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

    // EntityRef impl for testing.
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    struct E(u32);

    impl EntityRef for E {
        fn new(i: usize) -> Self {
            E(i as u32)
        }
        fn index(self) -> usize {
            self.0 as usize
        }
    }

    impl PrimaryEntityData for isize {}

    #[test]
    fn basic() {
        let r0 = E(0);
        let r1 = E(1);
        let r2 = E(2);
        let mut m = EntityMap::new();

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, []);

        assert!(!m.is_valid(r0));
        m.ensure(r2);
        m[r2] = 3;
        assert!(m.is_valid(r1));
        m[r1] = 5;

        assert_eq!(m[r1], 5);
        assert_eq!(m[r2], 3);

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, [r0, r1, r2]);

        let shared = &m;
        assert_eq!(shared[r0], 0);
        assert_eq!(shared[r1], 5);
        assert_eq!(shared[r2], 3);
    }

    #[test]
    fn push() {
        let mut m = EntityMap::new();
        let k1: E = m.push(12);
        let k2 = m.push(33);

        assert_eq!(m[k1], 12);
        assert_eq!(m[k2], 33);
    }
}
<commit_msg>Remove EntityRef::wrap().<commit_after>//! Densely numbered entity references as mapping keys.
//!
//! This module defines an `EntityRef` trait that should be implemented by reference types wrapping
//! a small integer index. The `EntityMap` data structure uses the dense index space to implement a
//! map with a vector. There are primary and secondary entity maps:
//!
//! - A *primary* `EntityMap` contains the main definition of an entity, and it can be used to
//!   allocate new entity references with the `push` method. The values stores in a primary map
//!   must implement the `PrimaryEntityData` marker trait.
//! - A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
//!   values need to implement `Clone + Default` traits so the map can be grown with `ensure`.

use std::vec::Vec;
use std::default::Default;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key
/// of an `EntityMap`.
pub trait EntityRef: Copy + Eq {
    /// Create a new entity reference from a small integer.
    /// This should crash if the requested index is not representable.
    fn new(usize) -> Self;

    /// Get the index that was used to create this entity reference.
    fn index(self) -> usize;
}

/// A mapping `K -> V` for densely indexed entity references.
#[derive(Debug, Clone)]
pub struct EntityMap<K, V>
    where K: EntityRef
{
    elems: Vec<V>,
    unused: PhantomData<K>,
}

/// Shared `EntityMap` implementation for all value types.
impl<K, V> EntityMap<K, V>
    where K: EntityRef
{
    /// Create a new empty map.
    pub fn new() -> Self {
        EntityMap {
            elems: Vec::new(),
            unused: PhantomData,
        }
    }

    /// Check if `k` is a valid key in the map.
    pub fn is_valid(&self, k: K) -> bool {
        k.index() < self.elems.len()
    }

    /// Get the element at `k` if it exists.
    pub fn get(&self, k: K) -> Option<&V> {
        self.elems.get(k.index())
    }

    /// Is this map completely empty?
    pub fn is_empty(&self) -> bool {
        self.elems.is_empty()
    }

    /// Remove all entries from this map.
    pub fn clear(&mut self) {
        self.elems.clear()
    }

    /// Iterate over all the keys in this map.
    pub fn keys(&self) -> Keys<K> {
        Keys {
            pos: 0,
            len: self.elems.len(),
            unused: PhantomData,
        }
    }
}

/// A marker trait for data stored in primary entity maps.
///
/// A primary entity map can be used to allocate new entity references with the `push` method. It
/// is important that entity references can't be created anywhere else, so the data stored in a
/// primary entity map must be tagged as `PrimaryEntityData` to unlock the `push` method.
pub trait PrimaryEntityData {}

/// Additional methods for primary entry maps only.
///
/// These are identified by the `PrimaryEntityData` marker trait.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: PrimaryEntityData
{
    /// Get the key that will be assigned to the next pushed value.
    pub fn next_key(&self) -> K {
        K::new(self.elems.len())
    }

    /// Append `v` to the mapping, assigning a new key which is returned.
    pub fn push(&mut self, v: V) -> K {
        let k = self.next_key();
        self.elems.push(v);
        k
    }

    /// Get the total number of entity references created.
    pub fn len(&self) -> usize {
        self.elems.len()
    }
}

/// Additional methods for value types that implement `Clone` and `Default`.
///
/// When the value type implements these additional traits, the `EntityMap` can be resized
/// explicitly with the `ensure` method.
///
/// Use this for secondary maps that are mapping keys created by another primary map.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: Clone + Default
{
    /// Create a new secondary `EntityMap` that is prepared to hold `n` elements.
    ///
    /// Use this when the length of the primary map is known:
    /// ```
    /// let secondary_map = EntityMap::with_capacity(primary_map.len());
    /// ```
    pub fn with_capacity(n: usize) -> Self {
        let mut map = EntityMap {
            elems: Vec::with_capacity(n),
            unused: PhantomData,
        };
        map.elems.resize(n, V::default());
        map
    }

    /// Resize the map to have `n` entries by adding default entries as needed.
    pub fn resize(&mut self, n: usize) {
        self.elems.resize(n, V::default());
    }

    /// Ensure that `k` is a valid key but adding default entries if necesssary.
    ///
    /// Return a mutable reference to the corresponding entry.
    pub fn ensure(&mut self, k: K) -> &mut V {
        if !self.is_valid(k) {
            self.resize(k.index() + 1)
        }
        &mut self.elems[k.index()]
    }
}

/// Immutable indexing into an `EntityMap`.
/// The indexed value must be in the map, either because it was created by `push`, or the key was
/// passed to `ensure`.
impl<K, V> Index<K> for EntityMap<K, V>
    where K: EntityRef
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.elems[k.index()]
    }
}

/// Mutable indexing into an `EntityMap`.
/// Use `ensure` instead if the key is not known to be valid.
impl<K, V> IndexMut<K> for EntityMap<K, V>
    where K: EntityRef
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.elems[k.index()]
    }
}

/// Iterate over all keys in order.
pub struct Keys<K>
    where K: EntityRef
{
    pos: usize,
    len: usize,
    unused: PhantomData<K>,
}

impl<K> Iterator for Keys<K>
    where K: EntityRef
{
    type Item = K;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.len {
            let k = K::new(self.pos);
            self.pos += 1;
            Some(k)
        } else {
            None
        }
    }
}

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

    // EntityRef impl for testing.
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    struct E(u32);

    impl EntityRef for E {
        fn new(i: usize) -> Self {
            E(i as u32)
        }
        fn index(self) -> usize {
            self.0 as usize
        }
    }

    impl PrimaryEntityData for isize {}

    #[test]
    fn basic() {
        let r0 = E(0);
        let r1 = E(1);
        let r2 = E(2);
        let mut m = EntityMap::new();

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, []);

        assert!(!m.is_valid(r0));
        m.ensure(r2);
        m[r2] = 3;
        assert!(m.is_valid(r1));
        m[r1] = 5;

        assert_eq!(m[r1], 5);
        assert_eq!(m[r2], 3);

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, [r0, r1, r2]);

        let shared = &m;
        assert_eq!(shared[r0], 0);
        assert_eq!(shared[r1], 5);
        assert_eq!(shared[r2], 3);
    }

    #[test]
    fn push() {
        let mut m = EntityMap::new();
        let k1: E = m.push(12);
        let k2 = m.push(33);

        assert_eq!(m[k1], 12);
        assert_eq!(m[k2], 33);
    }
}
<|endoftext|>


<commit_before>//! External names.
//!
//! These are identifiers for declaring entities defined outside the current
//! function. The name of an external declaration doesn't have any meaning to
//! Cretonne, which compiles functions independently.

use std::fmt::{self, Write};
#[allow(unused_imports)]
use std::ascii::AsciiExt;

/// The name of an external can be any sequence of bytes.
///
/// External names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::FuncRef or similar to additional associated data.
///
/// External names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
pub struct ExternalName(NameRepr);

impl ExternalName {
    /// Creates a new external name from a sequence of bytes.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from a string.
    /// let name = ExternalName::new("hello");
    /// assert_eq!(name.to_string(), "%hello");
    ///
    /// // Create `ExternalName` from a sequence of bytes.
    /// let bytes: &[u8] = &[10, 9, 8];
    /// let name = ExternalName::new(bytes);
    /// assert_eq!(name.to_string(), "#0a0908");
    /// ```
    pub fn new<T>(v: T) -> ExternalName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        if vec.len() <= NAME_LENGTH_THRESHOLD {
            let mut bytes = [0u8; NAME_LENGTH_THRESHOLD];
            for (i, &byte) in vec.iter().enumerate() {
                bytes[i] = byte;
            }
            ExternalName(NameRepr::Short {
                length: vec.len() as u8,
                bytes: bytes,
            })
        } else {
            ExternalName(NameRepr::Long(vec))
        }
    }
}

/// Tries to interpret bytes as ASCII alphanumerical characters and `_`.
fn try_as_name(bytes: &[u8]) -> Option<String> {
    let mut name = String::with_capacity(bytes.len());
    for c in bytes.iter().map(|&b| b as char) {
        if c.is_ascii() && c.is_alphanumeric() || c == '_' {
            name.push(c);
        } else {
            return None;
        }
    }
    Some(name)
}

const NAME_LENGTH_THRESHOLD: usize = 22;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum NameRepr {
    Short {
        length: u8,
        bytes: [u8; NAME_LENGTH_THRESHOLD],
    },
    Long(Vec<u8>),
}

impl AsRef<[u8]> for NameRepr {
    fn as_ref(&self) -> &[u8] {
        match *self {
            NameRepr::Short { length, ref bytes } => &bytes[0..length as usize],
            NameRepr::Long(ref vec) => vec.as_ref(),
        }
    }
}

impl AsRef<[u8]> for ExternalName {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for NameRepr {
    fn default() -> Self {
        NameRepr::Short {
            length: 0,
            bytes: [0; NAME_LENGTH_THRESHOLD],
        }
    }
}

impl fmt::Display for ExternalName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(name) = try_as_name(self.0.as_ref()) {
            write!(f, "%{}", name)
        } else {
            f.write_char('#')?;
            for byte in self.0.as_ref() {
                write!(f, "{:02x}", byte)?;
            }
            Ok(())
        }
    }
}

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

    #[test]
    fn displaying() {
        assert_eq!(ExternalName::new("").to_string(), "%");
        assert_eq!(ExternalName::new("x").to_string(), "%x");
        assert_eq!(ExternalName::new("x_1").to_string(), "%x_1");
        assert_eq!(ExternalName::new(" ").to_string(), "#20");
        assert_eq!(
            ExternalName::new("кретон").to_string(),
            "#d0bad180d0b5d182d0bed0bd"
        );
        assert_eq!(
            ExternalName::new("印花棉布").to_string(),
            "#e58db0e88ab1e6a389e5b883"
        );
        assert_eq!(
            ExternalName::new(vec![0, 1, 2, 3, 4, 5]).to_string(),
            "#000102030405"
        );
    }
}
<commit_msg>ir::ExternalName representation and constructors rewritten<commit_after>//! External names.
//!
//! These are identifiers for declaring entities defined outside the current
//! function. The name of an external declaration doesn't have any meaning to
//! Cretonne, which compiles functions independently.

use std::fmt::{self, Write};

const TESTCASE_NAME_LENGTH: usize = 10;

/// The name of an external is either a reference to a user-defined symbol
/// table, or a short sequence of ascii bytes so that test cases do not have
/// to keep track of a sy mbol table.
///
/// External names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::FuncRef or similar to additional associated data.
///
/// External names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExternalName {
    /// A name in a user-defined symbol table. Cretonne does not interpret
    /// these numbers in any way.
    User {
        /// Arbitrary
        namespace: u32,
        /// Arbitrary
        index: u32,
    },
    /// A test case function name of up to 10 ascii characters. This is
    /// not intended to be used outside test cases.
    TestCase {
        /// How many of the bytes in `ascii` are valid
        length: u8,
        /// Ascii bytes of the name
        ascii: [u8; TESTCASE_NAME_LENGTH],
    },
}

impl ExternalName {
    /// Creates a new external name from a sequence of bytes. Caller is expected
    /// to guarantee bytes are only ascii alphanumeric or `_`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from a string.
    /// let name = ExternalName::testcase("hello");
    /// assert_eq!(name.to_string(), "%hello");
    /// ```
    pub fn testcase<T>(v: T) -> ExternalName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        let len = if vec.len() > TESTCASE_NAME_LENGTH {
            TESTCASE_NAME_LENGTH
        } else {
            vec.len()
        };
        let mut bytes = [0u8; TESTCASE_NAME_LENGTH];
        for (i, &byte) in vec.iter().take(len).enumerate() {
            bytes[i] = byte;
        }
        ExternalName::TestCase {
            length: len as u8,
            ascii: bytes,
        }
    }

    /// Create a new external name from user-provided integer indicies.
    ///
    /// # Examples
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from integer indicies
    /// let name = ExternalName::user(123, 456);
    /// assert_eq!(name.to_string(), "u123:456");
    /// ```
    pub fn user(namespace: u32, index: u32) -> ExternalName {
        ExternalName::User {
            namespace: namespace,
            index: index,
        }
    }
}

impl Default for ExternalName {
    fn default() -> ExternalName {
        ExternalName::user(0, 0)
    }
}

impl fmt::Display for ExternalName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExternalName::User { namespace, index } => write!(f, "u{}:{}", namespace, index),
            ExternalName::TestCase { length, ascii } => {
                f.write_char('%')?;
                for byte in ascii.iter().take(length as usize) {
                    f.write_char(*byte as char)?;
                }
                Ok(())
            }
        }
    }
}

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

    #[test]
    fn display_testcase() {
        assert_eq!(ExternalName::testcase("").to_string(), "%");
        assert_eq!(ExternalName::testcase("x").to_string(), "%x");
        assert_eq!(ExternalName::testcase("x_1").to_string(), "%x_1");
        assert_eq!(
            ExternalName::testcase("long123456").to_string(),
            "%long123456"
        );
        // Constructor will silently drop bytes beyond the 10th
        assert_eq!(
            ExternalName::testcase("long1234567").to_string(),
            "%long123456"
        );
    }

    #[test]
    fn display_user() {
        assert_eq!(ExternalName::user(0, 0).to_string(), "u0:0");
        assert_eq!(ExternalName::user(1, 1).to_string(), "u1:1");
        assert_eq!(
            ExternalName::user(::std::u32::MAX, ::std::u32::MAX).to_string(),
            "u4294967295:4294967295"
        );
    }
}
<|endoftext|>


<commit_before>use crate::i18n::LocalText;
use crate::*;

use colored::Colorize;
use regex::Regex;
use std::io::prelude::*;
use std::{ffi::OsString, io};
use subprocess::{Exec, ExitStatus, Redirection};

// FTL: help-subcommand-make
/// Build specified target(s)
pub fn run(target: Vec<String>) -> Result<()> {
    setup::is_setup()?;
    show_header("make-header");
    let mut makeflags: Vec<OsString> = Vec::new();
    let cpus = num_cpus::get();
    makeflags.push(OsString::from(format!("--jobs={}", cpus)));
    let mut makefiles: Vec<OsString> = Vec::new();
    makefiles.push(OsString::from("-f"));
    makefiles.push(OsString::from(format!(
        "{}{}",
        CONFIGURE_DATADIR, "rules/casile.mk"
    )));
    let rules = status::get_rules()?;
    for rule in rules {
        makefiles.push(OsString::from("-f"));
        let p = rule.into_os_string();
        makefiles.push(p);
    }
    makefiles.push(OsString::from("-f"));
    makefiles.push(OsString::from(format!(
        "{}{}",
        CONFIGURE_DATADIR, "rules/rules.mk"
    )));
    let mut process = Exec::cmd("make")
        .args(&makeflags)
        .args(&makefiles)
        .args(&target);
    let targets: Vec<_> = target.into_iter().collect();
    let gitname = status::get_gitname()?;
    let git_version = status::get_git_version();
    process = process
        .env("CASILE_CLI", "true")
        .env("CASILEDIR", CONFIGURE_DATADIR)
        .env("CONTAINERIZED", status::is_container().to_string())
        .env("GITNAME", &gitname)
        .env("PROJECT", pname(&gitname))
        .env("PROJECTDIR", CONF.get_string("path")?)
        .env("PROJECTVERSION", git_version);
    if CONF.get_bool("debug")? {
        process = process.env("DEBUG", "true");
    };
    if CONF.get_bool("quiet")? {
        process = process.env("QUIET", "true");
    };
    if CONF.get_bool("verbose")? || targets.contains(&"debug".into()) {
        process = process.env("VERBOSE", "true");
    };
    let repo = get_repo()?;
    let workdir = repo.workdir().unwrap();
    process = process.cwd(workdir);
    let process = process.stderr(Redirection::Merge).stdout(Redirection::Pipe);
    let mut popen = process.popen()?;
    let buf = io::BufReader::new(popen.stdout.as_mut().unwrap());
    let mut backlog: Vec<String> = Vec::new();
    let seps = Regex::new(r"").unwrap();
    let mut ret: u32 = 0;
    for line in buf.lines() {
        let text: &str = &line.unwrap();
        let fields: Vec<&str> = seps.splitn(text, 4).collect();
        match fields[0] {
            "CASILE" => match fields[1] {
                "PRE" => report_start(fields[2]),
                "STDOUT" => {
                    if targets.contains(&"_gha".into()) {
                        println!("{}", fields[3]);
                    } else if CONF.get_bool("verbose")? {
                        report_line(fields[3]);
                    } else {
                        backlog.push(String::from(fields[3]));
                    }
                }
                "STDERR" => {
                    if CONF.get_bool("verbose")? {
                        report_line(fields[3]);
                    } else {
                        backlog.push(String::from(fields[3]));
                    }
                }
                "POST" => match fields[2] {
                    "0" => {
                        report_end(fields[3]);
                    }
                    val => {
                        report_fail(fields[3]);
                        ret = val.parse().unwrap_or(1);
                    }
                },
                _ => {
                    let errmsg = LocalText::new("make-error-unknown-code").fmt();
                    panic!(errmsg)
                }
            },
            _ => backlog.push(String::from(fields[0])),
        }
    }
    let status = popen.wait();
    match status {
        Ok(ExitStatus::Exited(int)) => {
            let foo = int + ret;
            match foo {
                0 => {
                    if targets.contains(&"debug".into()) {
                        dump_backlog(&backlog)
                    };
                    Ok(())
                }
                1 => {
                    dump_backlog(&backlog);
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-unfinished").fmt(),
                    )))
                }
                2 => {
                    dump_backlog(&backlog);
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-build").fmt(),
                    )))
                }
                3 => {
                    if !CONF.get_bool("verbose")? {
                        dump_backlog(&backlog);
                    }
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-target").fmt(),
                    )))
                }
                _ => {
                    dump_backlog(&backlog);
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-unknown").fmt(),
                    )))
                }
            }
        }
        _ => Err(Box::new(io::Error::new(
            io::ErrorKind::InvalidInput,
            LocalText::new("make-error").fmt(),
        ))),
    }
}

fn dump_backlog(backlog: &Vec<String>) {
    let start = LocalText::new("make-backlog-start").fmt();
    eprintln!("{} {}", "┖┄".cyan(), start);
    for line in backlog.iter() {
        eprintln!("{}", line);
    }
    let end = LocalText::new("make-backlog-end").fmt();
    eprintln!("{} {}", "┎┄".cyan(), end);
}

fn report_line(line: &str) {
    eprintln!("{} {}", "┠╎".cyan(), line.dimmed());
}

fn report_start(target: &str) {
    let text = LocalText::new("make-report-start")
        .arg("target", target.white().bold())
        .fmt();
    eprintln!("{} {}", "┠┄".cyan(), text.yellow());
}

fn report_end(target: &str) {
    let text = LocalText::new("make-report-end")
        .arg("target", target.white().bold())
        .fmt();
    eprintln!("{} {}", "┠┄".cyan(), text.green());
}

fn report_fail(target: &str) {
    let text = LocalText::new("make-report-fail")
        .arg("target", target.white().bold())
        .fmt();
    eprintln!("{} {}", "┠┄".cyan(), text.red());
}
<commit_msg>fix(cli): Pass language flag through to make targets<commit_after>use crate::i18n::LocalText;
use crate::*;

use colored::Colorize;
use regex::Regex;
use std::io::prelude::*;
use std::{ffi::OsString, io};
use subprocess::{Exec, ExitStatus, Redirection};

// FTL: help-subcommand-make
/// Build specified target(s)
pub fn run(target: Vec<String>) -> Result<()> {
    setup::is_setup()?;
    show_header("make-header");
    let mut makeflags: Vec<OsString> = Vec::new();
    let cpus = num_cpus::get();
    makeflags.push(OsString::from(format!("--jobs={}", cpus)));
    let mut makefiles: Vec<OsString> = Vec::new();
    makefiles.push(OsString::from("-f"));
    makefiles.push(OsString::from(format!(
        "{}{}",
        CONFIGURE_DATADIR, "rules/casile.mk"
    )));
    let rules = status::get_rules()?;
    for rule in rules {
        makefiles.push(OsString::from("-f"));
        let p = rule.into_os_string();
        makefiles.push(p);
    }
    makefiles.push(OsString::from("-f"));
    makefiles.push(OsString::from(format!(
        "{}{}",
        CONFIGURE_DATADIR, "rules/rules.mk"
    )));
    let mut process = Exec::cmd("make")
        .args(&makeflags)
        .args(&makefiles)
        .args(&target);
    let targets: Vec<_> = target.into_iter().collect();
    let gitname = status::get_gitname()?;
    let git_version = status::get_git_version();
    process = process
        .env("CASILE_CLI", "true")
        .env("CASILEDIR", CONFIGURE_DATADIR)
        .env("CONTAINERIZED", status::is_container().to_string())
        .env("GITNAME", &gitname)
        .env("LANGUAGE", CONF.get_string("language")?)
        .env("PROJECT", pname(&gitname))
        .env("PROJECTDIR", CONF.get_string("path")?)
        .env("PROJECTVERSION", git_version);
    if CONF.get_bool("debug")? {
        process = process.env("DEBUG", "true");
    };
    if CONF.get_bool("quiet")? {
        process = process.env("QUIET", "true");
    };
    if CONF.get_bool("verbose")? || targets.contains(&"debug".into()) {
        process = process.env("VERBOSE", "true");
    };
    let repo = get_repo()?;
    let workdir = repo.workdir().unwrap();
    process = process.cwd(workdir);
    let process = process.stderr(Redirection::Merge).stdout(Redirection::Pipe);
    let mut popen = process.popen()?;
    let buf = io::BufReader::new(popen.stdout.as_mut().unwrap());
    let mut backlog: Vec<String> = Vec::new();
    let seps = Regex::new(r"").unwrap();
    let mut ret: u32 = 0;
    for line in buf.lines() {
        let text: &str = &line.unwrap();
        let fields: Vec<&str> = seps.splitn(text, 4).collect();
        match fields[0] {
            "CASILE" => match fields[1] {
                "PRE" => report_start(fields[2]),
                "STDOUT" => {
                    if targets.contains(&"_gha".into()) {
                        println!("{}", fields[3]);
                    } else if CONF.get_bool("verbose")? {
                        report_line(fields[3]);
                    } else {
                        backlog.push(String::from(fields[3]));
                    }
                }
                "STDERR" => {
                    if CONF.get_bool("verbose")? {
                        report_line(fields[3]);
                    } else {
                        backlog.push(String::from(fields[3]));
                    }
                }
                "POST" => match fields[2] {
                    "0" => {
                        report_end(fields[3]);
                    }
                    val => {
                        report_fail(fields[3]);
                        ret = val.parse().unwrap_or(1);
                    }
                },
                _ => {
                    let errmsg = LocalText::new("make-error-unknown-code").fmt();
                    panic!(errmsg)
                }
            },
            _ => backlog.push(String::from(fields[0])),
        }
    }
    let status = popen.wait();
    match status {
        Ok(ExitStatus::Exited(int)) => {
            let foo = int + ret;
            match foo {
                0 => {
                    if targets.contains(&"debug".into()) {
                        dump_backlog(&backlog)
                    };
                    Ok(())
                }
                1 => {
                    dump_backlog(&backlog);
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-unfinished").fmt(),
                    )))
                }
                2 => {
                    dump_backlog(&backlog);
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-build").fmt(),
                    )))
                }
                3 => {
                    if !CONF.get_bool("verbose")? {
                        dump_backlog(&backlog);
                    }
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-target").fmt(),
                    )))
                }
                _ => {
                    dump_backlog(&backlog);
                    Err(Box::new(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        LocalText::new("make-error-unknown").fmt(),
                    )))
                }
            }
        }
        _ => Err(Box::new(io::Error::new(
            io::ErrorKind::InvalidInput,
            LocalText::new("make-error").fmt(),
        ))),
    }
}

fn dump_backlog(backlog: &Vec<String>) {
    let start = LocalText::new("make-backlog-start").fmt();
    eprintln!("{} {}", "┖┄".cyan(), start);
    for line in backlog.iter() {
        eprintln!("{}", line);
    }
    let end = LocalText::new("make-backlog-end").fmt();
    eprintln!("{} {}", "┎┄".cyan(), end);
}

fn report_line(line: &str) {
    eprintln!("{} {}", "┠╎".cyan(), line.dimmed());
}

fn report_start(target: &str) {
    let text = LocalText::new("make-report-start")
        .arg("target", target.white().bold())
        .fmt();
    eprintln!("{} {}", "┠┄".cyan(), text.yellow());
}

fn report_end(target: &str) {
    let text = LocalText::new("make-report-end")
        .arg("target", target.white().bold())
        .fmt();
    eprintln!("{} {}", "┠┄".cyan(), text.green());
}

fn report_fail(target: &str) {
    let text = LocalText::new("make-report-fail")
        .arg("target", target.white().bold())
        .fmt();
    eprintln!("{} {}", "┠┄".cyan(), text.red());
}
<|endoftext|>


<commit_before>use crate::{texture, Document};

pub use json::material::AlphaMode;

lazy_static! {
    static ref DEFAULT_MATERIAL: json::material::Material = Default::default();
}

/// The material appearance of a primitive.
pub struct Material<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON index - `None` when the default material.
    index: Option<usize>,

    /// The corresponding JSON struct.
    json: &'a json::material::Material,
}

impl<'a> Material<'a> {
    /// Constructs a `Material`.
    pub(crate) fn new(
        document: &'a Document,
        index: usize,
        json: &'a json::material::Material,
    ) -> Self {
        Self {
            document: document,
            index: Some(index),
            json: json,
        }
    }

    /// Constructs the default `Material`.
    pub(crate) fn default(document: &'a Document) -> Self {
        Self {
            document: document,
            index: None,
            json: &DEFAULT_MATERIAL,
        }
    }

    /// Returns the internal JSON index if this `Material` was explicity defined.
    ///
    /// This function returns `None` if the `Material` is the default material.
    pub fn index(&self) -> Option<usize> {
        self.index
    }

    ///  The alpha cutoff value of the material.
    pub fn alpha_cutoff(&self) -> f32 {
        self.json.alpha_cutoff.0
    }

    /// The alpha rendering mode of the material.  The material's alpha rendering
    /// mode enumeration specifying the interpretation of the alpha value of the main
    /// factor and texture.
    ///
    /// * In `Opaque` mode (default) the alpha value is ignored
    ///   and the rendered output is fully opaque.
    /// * In `Mask` mode, the rendered
    ///   output is either fully opaque or fully transparent depending on the alpha
    ///   value and the specified alpha cutoff value.
    /// * In `Blend` mode, the alpha value is used to composite the source and
    ///   destination areas and the rendered output is combined with the background
    ///   using the normal painting operation (i.e. the Porter and Duff over
    ///   operator).
    pub fn alpha_mode(&self) -> AlphaMode {
        self.json.alpha_mode.unwrap()
    }

    /// Specifies whether the material is double-sided.
    ///
    /// * When this value is false, back-face culling is enabled.
    /// * When this value is true, back-face culling is disabled and double sided
    ///   lighting is enabled.  The back-face must have its normals reversed before
    ///   the lighting equation is evaluated.
    pub fn double_sided(&self) -> bool {
        self.json.double_sided
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Parameter values that define the metallic-roughness material model from
    /// Physically-Based Rendering (PBR) methodology.
    pub fn pbr_metallic_roughness(&self) -> PbrMetallicRoughness<'a> {
        PbrMetallicRoughness::new(self.document, &self.json.pbr_metallic_roughness)
    }

    /// Parameter values that define the specular-glossiness material model from
    /// Physically-Based Rendering (PBR) methodology.
    #[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
    pub fn pbr_specular_glossiness(&self) -> Option<PbrSpecularGlossiness<'a>> {
        self.json.extensions
            .as_ref()?
            .pbr_specular_glossiness.as_ref()
            .map(|x| PbrSpecularGlossiness::new(self.document, x))
    }

    /// A tangent space normal map.
    ///
    /// The texture contains RGB components in linear space. Each texel represents
    /// the XYZ components of a normal vector in tangent space.
    ///
    /// * Red [0 to 255] maps to X [-1 to 1].
    /// * Green [0 to 255] maps to Y [-1 to 1].
    /// * Blue [128 to 255] maps to Z [1/255 to 1].
    ///
    /// The normal vectors use OpenGL conventions where +X is right, +Y is up, and
    /// +Z points toward the viewer.
    pub fn normal_texture(&self) -> Option<NormalTexture<'a>> {
        self.json.normal_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            NormalTexture::new(texture, json)
        })
    }

    /// The occlusion map texture.
    ///
    /// The occlusion values are sampled from the R channel. Higher values indicate
    /// areas that should receive full indirect lighting and lower values indicate
    /// no indirect lighting. These values are linear.
    ///
    /// If other channels are present (GBA), they are ignored for occlusion
    /// calculations.
    pub fn occlusion_texture(&self) -> Option<OcclusionTexture<'a>> {
        self.json.occlusion_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            OcclusionTexture::new(texture, json)
        })
    }

    /// The emissive map texture.
    ///
    /// The emissive map controls the color and intensity of the light being
    /// emitted by the material.
    ///
    /// This texture contains RGB components in sRGB color space. If a fourth
    /// component (A) is present, it is ignored.
    pub fn emissive_texture(&self) -> Option<texture::Info<'a>> {
        self.json.emissive_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// The emissive color of the material.
    ///
    /// The default value is `[0.0, 0.0, 0.0]`.
    pub fn emissive_factor(&self) -> [f32; 3] {
        self.json.emissive_factor.0
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
pub struct PbrMetallicRoughness<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON struct.
    json: &'a json::material::PbrMetallicRoughness,
}

impl<'a> PbrMetallicRoughness<'a> {
    /// Constructs `PbrMetallicRoughness`.
    pub(crate) fn new(
        document: &'a Document,
        json: &'a json::material::PbrMetallicRoughness,
    ) -> Self {
        Self {
            document: document,
            json: json,
        }
    }

    /// Returns the material's base color factor.
    ///
    /// The default value is `[1.0, 1.0, 1.0, 1.0]`.
    pub fn base_color_factor(&self) -> [f32; 4] {
        self.json.base_color_factor.0
    }

    /// Returns the base color texture.
    pub fn base_color_texture(&self) -> Option<texture::Info<'a>> {
        self.json.base_color_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Returns the metalness factor of the material.
    ///
    /// The default value is `1.0`.
    pub fn metallic_factor(&self) -> f32 {
        self.json.metallic_factor.0
    }

    /// Returns the roughness factor of the material.
    ///
    /// * A value of 1.0 means the material is completely rough.
    /// * A value of 0.0 means the material is completely smooth.
    ///
    /// The default value is `1.0`.
    pub fn roughness_factor(&self) -> f32 {
        self.json.roughness_factor.0
    }

    /// The metallic-roughness texture.
    ///
    /// The metalness values are sampled from the B channel.
    /// The roughness values are sampled from the G channel.
    /// These values are linear. If other channels are present (R or A),
    /// they are ignored for metallic-roughness calculations.
    pub fn metallic_roughness_texture(&self) -> Option<texture::Info<'a>> {
        self.json.metallic_roughness_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// A set of parameter values that are used to define the specular-glossiness
/// material model from Physically-Based Rendering (PBR) methodology.
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
pub struct PbrSpecularGlossiness<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON struct.
    json: &'a json::extensions::material::PbrSpecularGlossiness,
}

#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
impl<'a> PbrSpecularGlossiness<'a> {
    /// Constructs `PbrSpecularGlossiness`.
    pub(crate) fn new(
        document: &'a Document,
        json: &'a json::extensions::material::PbrSpecularGlossiness,
    ) -> Self {
        Self {
            document: document,
            json: json,
        }
    }

    /// Returns the material's base color factor.
    ///
    /// The default value is `[1.0, 1.0, 1.0, 1.0]`.
    pub fn diffuse_factor(&self) -> [f32; 4] {
        self.json.diffuse_factor.0
    }

    /// Returns the base color texture.
    pub fn diffuse_texture(&self) -> Option<texture::Info<'a>> {
        self.json.diffuse_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Returns the specular factor of the material.
    ///
    /// The default value is `[1.0, 1.0, 1.0]`.
    pub fn specular_factor(&self) -> [f32; 3] {
        self.json.specular_factor.0
    }

    /// Returns the glossiness factor of the material.
    ///
    /// A value of 1.0 means the material has full glossiness or is perfectly
    /// smooth. A value of 0.0 means the material has no glossiness or is
    /// completely rough. This value is linear.
    ///
    /// The default value is `1.0`.
    pub fn glossiness_factor(&self) -> f32 {
        self.json.glossiness_factor.0
    }

    /// The specular-glossiness texture.
    ///
    /// A RGBA texture, containing the specular color of the material (RGB
    /// components) and its glossiness (A component). The color values are in
    /// sRGB space.
    pub fn specular_glossiness_texture(&self) -> Option<texture::Info<'a>> {
        self.json.specular_glossiness_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// Defines the normal texture of a material.
pub struct NormalTexture<'a> {
    /// The parent `Texture` struct.
    texture: texture::Texture<'a>,

    /// The corresponding JSON struct.
    json: &'a json::material::NormalTexture,
}

impl<'a> NormalTexture<'a> {
    /// Constructs a `NormalTexture`.
    pub(crate) fn new(
        texture: texture::Texture<'a>,
        json: &'a json::material::NormalTexture,
    ) -> Self {
        Self {
            texture: texture,
            json: json,
        }
    }

    /// Returns the scalar multiplier applied to each normal vector of the texture.
    pub fn scale(&self) -> f32 {
        self.json.scale
    }

    /// The set index of the texture's `TEXCOORD` attribute.
    pub fn tex_coord(&self) -> u32 {
        self.json.tex_coord
    }

    /// Returns the referenced texture.
    pub fn texture(&self) -> texture::Texture<'a> {
        self.texture.clone()
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// Defines the occlusion texture of a material.
pub struct OcclusionTexture<'a> {
    /// The parent `Texture` struct.
    texture: texture::Texture<'a>,

    /// The corresponding JSON struct.
    json: &'a json::material::OcclusionTexture,
}

impl<'a> OcclusionTexture<'a> {
    /// Constructs a `OcclusionTexture`.
    pub(crate) fn new(
        texture: texture::Texture<'a>,
        json: &'a json::material::OcclusionTexture,
    ) -> Self {
        Self {
            texture: texture,
            json: json,
        }
    }

    /// Returns the scalar multiplier controlling the amount of occlusion applied.
    pub fn strength(&self) -> f32 {
        self.json.strength.0
    }

    /// Returns the set index of the texture's `TEXCOORD` attribute.
    pub fn tex_coord(&self) -> u32 {
        self.json.tex_coord
    }

    /// Returns the referenced texture.
    pub fn texture(&self) -> texture::Texture<'a> {
        self.texture.clone()
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

impl<'a> AsRef<texture::Texture<'a>> for NormalTexture<'a> {
    fn as_ref(&self) -> &texture::Texture<'a> {
        &self.texture
    }
}

impl<'a> AsRef<texture::Texture<'a>> for OcclusionTexture<'a> {
    fn as_ref(&self) -> &texture::Texture<'a> {
        &self.texture
    }
}
<commit_msg>Add sRGB color space docs to base_color_texture<commit_after>use crate::{texture, Document};

pub use json::material::AlphaMode;

lazy_static! {
    static ref DEFAULT_MATERIAL: json::material::Material = Default::default();
}

/// The material appearance of a primitive.
pub struct Material<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON index - `None` when the default material.
    index: Option<usize>,

    /// The corresponding JSON struct.
    json: &'a json::material::Material,
}

impl<'a> Material<'a> {
    /// Constructs a `Material`.
    pub(crate) fn new(
        document: &'a Document,
        index: usize,
        json: &'a json::material::Material,
    ) -> Self {
        Self {
            document: document,
            index: Some(index),
            json: json,
        }
    }

    /// Constructs the default `Material`.
    pub(crate) fn default(document: &'a Document) -> Self {
        Self {
            document: document,
            index: None,
            json: &DEFAULT_MATERIAL,
        }
    }

    /// Returns the internal JSON index if this `Material` was explicity defined.
    ///
    /// This function returns `None` if the `Material` is the default material.
    pub fn index(&self) -> Option<usize> {
        self.index
    }

    ///  The alpha cutoff value of the material.
    pub fn alpha_cutoff(&self) -> f32 {
        self.json.alpha_cutoff.0
    }

    /// The alpha rendering mode of the material.  The material's alpha rendering
    /// mode enumeration specifying the interpretation of the alpha value of the main
    /// factor and texture.
    ///
    /// * In `Opaque` mode (default) the alpha value is ignored
    ///   and the rendered output is fully opaque.
    /// * In `Mask` mode, the rendered
    ///   output is either fully opaque or fully transparent depending on the alpha
    ///   value and the specified alpha cutoff value.
    /// * In `Blend` mode, the alpha value is used to composite the source and
    ///   destination areas and the rendered output is combined with the background
    ///   using the normal painting operation (i.e. the Porter and Duff over
    ///   operator).
    pub fn alpha_mode(&self) -> AlphaMode {
        self.json.alpha_mode.unwrap()
    }

    /// Specifies whether the material is double-sided.
    ///
    /// * When this value is false, back-face culling is enabled.
    /// * When this value is true, back-face culling is disabled and double sided
    ///   lighting is enabled.  The back-face must have its normals reversed before
    ///   the lighting equation is evaluated.
    pub fn double_sided(&self) -> bool {
        self.json.double_sided
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Parameter values that define the metallic-roughness material model from
    /// Physically-Based Rendering (PBR) methodology.
    pub fn pbr_metallic_roughness(&self) -> PbrMetallicRoughness<'a> {
        PbrMetallicRoughness::new(self.document, &self.json.pbr_metallic_roughness)
    }

    /// Parameter values that define the specular-glossiness material model from
    /// Physically-Based Rendering (PBR) methodology.
    #[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
    pub fn pbr_specular_glossiness(&self) -> Option<PbrSpecularGlossiness<'a>> {
        self.json.extensions
            .as_ref()?
            .pbr_specular_glossiness.as_ref()
            .map(|x| PbrSpecularGlossiness::new(self.document, x))
    }

    /// A tangent space normal map.
    ///
    /// The texture contains RGB components in linear space. Each texel represents
    /// the XYZ components of a normal vector in tangent space.
    ///
    /// * Red [0 to 255] maps to X [-1 to 1].
    /// * Green [0 to 255] maps to Y [-1 to 1].
    /// * Blue [128 to 255] maps to Z [1/255 to 1].
    ///
    /// The normal vectors use OpenGL conventions where +X is right, +Y is up, and
    /// +Z points toward the viewer.
    pub fn normal_texture(&self) -> Option<NormalTexture<'a>> {
        self.json.normal_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            NormalTexture::new(texture, json)
        })
    }

    /// The occlusion map texture.
    ///
    /// The occlusion values are sampled from the R channel. Higher values indicate
    /// areas that should receive full indirect lighting and lower values indicate
    /// no indirect lighting. These values are linear.
    ///
    /// If other channels are present (GBA), they are ignored for occlusion
    /// calculations.
    pub fn occlusion_texture(&self) -> Option<OcclusionTexture<'a>> {
        self.json.occlusion_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            OcclusionTexture::new(texture, json)
        })
    }

    /// The emissive map texture.
    ///
    /// The emissive map controls the color and intensity of the light being
    /// emitted by the material.
    ///
    /// This texture contains RGB components in sRGB color space. If a fourth
    /// component (A) is present, it is ignored.
    pub fn emissive_texture(&self) -> Option<texture::Info<'a>> {
        self.json.emissive_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// The emissive color of the material.
    ///
    /// The default value is `[0.0, 0.0, 0.0]`.
    pub fn emissive_factor(&self) -> [f32; 3] {
        self.json.emissive_factor.0
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
pub struct PbrMetallicRoughness<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON struct.
    json: &'a json::material::PbrMetallicRoughness,
}

impl<'a> PbrMetallicRoughness<'a> {
    /// Constructs `PbrMetallicRoughness`.
    pub(crate) fn new(
        document: &'a Document,
        json: &'a json::material::PbrMetallicRoughness,
    ) -> Self {
        Self {
            document: document,
            json: json,
        }
    }

    /// Returns the material's base color factor.
    ///
    /// The default value is `[1.0, 1.0, 1.0, 1.0]`.
    pub fn base_color_factor(&self) -> [f32; 4] {
        self.json.base_color_factor.0
    }

    /// Returns the base color texture. The texture contians RGB(A) components
    /// in sRGB color space.
    pub fn base_color_texture(&self) -> Option<texture::Info<'a>> {
        self.json.base_color_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Returns the metalness factor of the material.
    ///
    /// The default value is `1.0`.
    pub fn metallic_factor(&self) -> f32 {
        self.json.metallic_factor.0
    }

    /// Returns the roughness factor of the material.
    ///
    /// * A value of 1.0 means the material is completely rough.
    /// * A value of 0.0 means the material is completely smooth.
    ///
    /// The default value is `1.0`.
    pub fn roughness_factor(&self) -> f32 {
        self.json.roughness_factor.0
    }

    /// The metallic-roughness texture.
    ///
    /// The metalness values are sampled from the B channel.
    /// The roughness values are sampled from the G channel.
    /// These values are linear. If other channels are present (R or A),
    /// they are ignored for metallic-roughness calculations.
    pub fn metallic_roughness_texture(&self) -> Option<texture::Info<'a>> {
        self.json.metallic_roughness_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// A set of parameter values that are used to define the specular-glossiness
/// material model from Physically-Based Rendering (PBR) methodology.
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
pub struct PbrSpecularGlossiness<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON struct.
    json: &'a json::extensions::material::PbrSpecularGlossiness,
}

#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
impl<'a> PbrSpecularGlossiness<'a> {
    /// Constructs `PbrSpecularGlossiness`.
    pub(crate) fn new(
        document: &'a Document,
        json: &'a json::extensions::material::PbrSpecularGlossiness,
    ) -> Self {
        Self {
            document: document,
            json: json,
        }
    }

    /// Returns the material's base color factor.
    ///
    /// The default value is `[1.0, 1.0, 1.0, 1.0]`.
    pub fn diffuse_factor(&self) -> [f32; 4] {
        self.json.diffuse_factor.0
    }

    /// Returns the base color texture.
    pub fn diffuse_texture(&self) -> Option<texture::Info<'a>> {
        self.json.diffuse_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Returns the specular factor of the material.
    ///
    /// The default value is `[1.0, 1.0, 1.0]`.
    pub fn specular_factor(&self) -> [f32; 3] {
        self.json.specular_factor.0
    }

    /// Returns the glossiness factor of the material.
    ///
    /// A value of 1.0 means the material has full glossiness or is perfectly
    /// smooth. A value of 0.0 means the material has no glossiness or is
    /// completely rough. This value is linear.
    ///
    /// The default value is `1.0`.
    pub fn glossiness_factor(&self) -> f32 {
        self.json.glossiness_factor.0
    }

    /// The specular-glossiness texture.
    ///
    /// A RGBA texture, containing the specular color of the material (RGB
    /// components) and its glossiness (A component). The color values are in
    /// sRGB space.
    pub fn specular_glossiness_texture(&self) -> Option<texture::Info<'a>> {
        self.json.specular_glossiness_texture.as_ref().map(|json| {
            let texture = self.document.textures().nth(json.index.value()).unwrap();
            texture::Info::new(texture, json)
        })
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// Defines the normal texture of a material.
pub struct NormalTexture<'a> {
    /// The parent `Texture` struct.
    texture: texture::Texture<'a>,

    /// The corresponding JSON struct.
    json: &'a json::material::NormalTexture,
}

impl<'a> NormalTexture<'a> {
    /// Constructs a `NormalTexture`.
    pub(crate) fn new(
        texture: texture::Texture<'a>,
        json: &'a json::material::NormalTexture,
    ) -> Self {
        Self {
            texture: texture,
            json: json,
        }
    }

    /// Returns the scalar multiplier applied to each normal vector of the texture.
    pub fn scale(&self) -> f32 {
        self.json.scale
    }

    /// The set index of the texture's `TEXCOORD` attribute.
    pub fn tex_coord(&self) -> u32 {
        self.json.tex_coord
    }

    /// Returns the referenced texture.
    pub fn texture(&self) -> texture::Texture<'a> {
        self.texture.clone()
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

/// Defines the occlusion texture of a material.
pub struct OcclusionTexture<'a> {
    /// The parent `Texture` struct.
    texture: texture::Texture<'a>,

    /// The corresponding JSON struct.
    json: &'a json::material::OcclusionTexture,
}

impl<'a> OcclusionTexture<'a> {
    /// Constructs a `OcclusionTexture`.
    pub(crate) fn new(
        texture: texture::Texture<'a>,
        json: &'a json::material::OcclusionTexture,
    ) -> Self {
        Self {
            texture: texture,
            json: json,
        }
    }

    /// Returns the scalar multiplier controlling the amount of occlusion applied.
    pub fn strength(&self) -> f32 {
        self.json.strength.0
    }

    /// Returns the set index of the texture's `TEXCOORD` attribute.
    pub fn tex_coord(&self) -> u32 {
        self.json.tex_coord
    }

    /// Returns the referenced texture.
    pub fn texture(&self) -> texture::Texture<'a> {
        self.texture.clone()
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }
}

impl<'a> AsRef<texture::Texture<'a>> for NormalTexture<'a> {
    fn as_ref(&self) -> &texture::Texture<'a> {
        &self.texture
    }
}

impl<'a> AsRef<texture::Texture<'a>> for OcclusionTexture<'a> {
    fn as_ref(&self) -> &texture::Texture<'a> {
        &self.texture
    }
}
<|endoftext|>