<commit_before>#![feature(box_syntax)]
#![feature(convert)]

use std::collections::HashMap;
use std::fs::File;
use std::io::{stdout, Read, Write};
use std::env;
use std::process;

use self::to_num::ToNum;
use self::input_editor::readln;
use self::tokenizer::{Token, tokenize};
use self::expansion::expand_tokens;
use self::parser::{parse, Job};

pub mod builtin;
pub mod to_num;
pub mod input_editor;
pub mod tokenizer;
pub mod parser;
pub mod expansion;

/// Structure which represents a Terminal's command.
/// This command structure contains a name, and the code which run the
/// functionnality associated to this one, with zero, one or several argument(s).
/// # Example
/// ```
/// let my_command = Command {
///     name: "my_command",
///     help: "Describe what my_command does followed by a newline showing usage",
///     main: box|args: &[String]| {
///         println!("Say 'hello' to my command! :-D");
///     }
/// }
/// ```
pub struct Command {
    pub name: &'static str,
    pub help: &'static str,
    pub main: Box<Fn(&[String], &mut Shell)>,
}

/// This struct will contain all of the data structures related to this
/// instance of the shell.
pub struct Shell {
    pub variables: HashMap<String, String>,
    pub modes: Vec<Mode>,
}

impl Command {
    /// Return the map from command names to commands
    pub fn map() -> HashMap<&'static str, Self> {
        let mut commands: HashMap<&str, Self> = HashMap::new();

        commands.insert("cat",
                        Command {
                            name: "cat",
                            help: "To display a file in the output\n    cat <your_file>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::cat(args);
                            },
                        });

        commands.insert("cd",
                        Command {
                            name: "cd",
                            help: "To change the current directory\n    cd <your_destination>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::cd(args);
                            },
                        });

        commands.insert("echo",
                        Command {
                            name: "echo",
                            help: "To display some text in the output\n    echo Hello world!",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::echo(args);
                            },
                        });

        commands.insert("exit",
                        Command {
                            name: "exit",
                            help: "To exit the curent session",
                            main: box |_: &[String], _: &mut Shell| {},
                        });

        commands.insert("free",
                        Command {
                            name: "free",
                            help: "Show memory information\n    free",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::free();
                            },
                        });

        commands.insert("ls",
                        Command {
                            name: "ls",
                            help: "To list the content of the current directory\n    ls",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::ls(args);
                            },
                        });

        commands.insert("mkdir",
                        Command {
                            name: "mkdir",
                            help: "To create a directory in the current directory\n    mkdir \
                                   <my_new_directory>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::mkdir(args);
                            },
                        });

        commands.insert("poweroff",
                        Command {
                            name: "poweroff",
                            help: "poweroff utility has the machine remove power, if \
                                   possible\n\tpoweroff",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::poweroff();
                            },
                        });

        commands.insert("ps",
                        Command {
                            name: "ps",
                            help: "Show process list\n    ps",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::ps();
                            },
                        });

        commands.insert("pwd",
                        Command {
                            name: "pwd",
                            help: "To output the path of the current directory\n    pwd",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::pwd();
                            },
                        });

        commands.insert("read",
                        Command {
                            name: "read",
                            help: "To read some variables\n    read <my_variable>",
                            main: box |args: &[String], shell: &mut Shell| {
                                builtin::read(args, &mut shell.variables);
                            },
                        });

        commands.insert("rm",
                        Command {
                            name: "rm",
                            help: "Remove a file\n    rm <file>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::rm(args);
                            },
                        });

        commands.insert("rmdir",
                        Command {
                            name: "rmdir",
                            help: "Remove a directory\n    rmdir <directory>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::rmdir(args);
                            },
                        });

        commands.insert("run",
                        Command {
                            name: "run",
                            help: "Run a script\n    run <script>",
                            main: box |args: &[String], shell: &mut Shell| {
                                builtin::run(args, &mut shell.variables);
                            },
                        });

        commands.insert("sleep",
                        Command {
                            name: "sleep",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::sleep(args);
                            },
                        });

        // TODO: Someone should implement FromIterator for HashMap before
        //       changing the type back to HashMap
        let command_helper: HashMap<String, String> = commands.iter()
                                                               .map(|(k, v)| {
                                                                   (k.to_string(),
                                                                    v.help.to_string())
                                                               })
                                                               .collect();

        commands.insert("help",
                        Command {
                            name: "help",
                            help: "Display a little helper for a given command\n    help ls",
                            main: box move |args: &[String], _: &mut Shell| {
                                if let Some(command) = args.get(1) {
                                    if command_helper.contains_key(command) {
                                        match command_helper.get(command) {
                                            Some(help) => println!("{}", help),
                                            None => {
                                                println!("Command helper not found [run 'help']...")
                                            }
                                        }
                                    } else {
                                        println!("Command helper not found [run 'help']...");
                                    }
                                } else {
                                    for (command, _help) in command_helper.iter() {
                                        println!("{}", command);
                                    }
                                }
                            },
                        });

        commands
    }
}

pub struct Mode {
    value: bool,
}

fn on_command(command_string: &str, commands: &HashMap<&str, Command>, shell: &mut Shell) {
    // Show variables
    if command_string == "$" {
        let mut pairs: Vec<_> = shell.variables.iter().collect();
        pairs.sort();
        for (key, value) in pairs {
            println!("{}={}", key, value);
        }
        return;
    }

    let mut tokens: Vec<Token> = expand_tokens(&mut tokenize(command_string), &mut shell.variables);
    let jobs: Vec<Job> = parse(&mut tokens);

    // Execute commands
    for job in jobs.iter() {
        if job.command == "if" {
            let mut value = false;

            if let Some(left) = job.args.get(0) {
                if let Some(cmp) = job.args.get(1) {
                    if let Some(right) = job.args.get(2) {
                        if cmp == "==" {
                            value = *left == *right;
                        } else if cmp == "!=" {
                            value = *left != *right;
                        } else if cmp == ">" {
                            value = left.to_num_signed() > right.to_num_signed();
                        } else if cmp == ">=" {
                            value = left.to_num_signed() >= right.to_num_signed();
                        } else if cmp == "<" {
                            value = left.to_num_signed() < right.to_num_signed();
                        } else if cmp == "<=" {
                            value = left.to_num_signed() <= right.to_num_signed();
                        } else {
                            println!("Unknown comparison: {}", cmp);
                        }
                    } else {
                        println!("No right hand side");
                    }
                } else {
                    println!("No comparison operator");
                }
            } else {
                println!("No left hand side");
            }

            shell.modes.insert(0, Mode { value: value });
            continue;
        }

        if job.command == "else" {
            let mut syntax_error = false;
            match shell.modes.get_mut(0) {
                Some(mode) => mode.value = !mode.value,
                None => syntax_error = true,
            }
            if syntax_error {
                println!("Syntax error: else found with no previous if");
            }
            continue;
        }

        if job.command == "fi" {
            let mut syntax_error = false;
            if !shell.modes.is_empty() {
                shell.modes.remove(0);
            } else {
                syntax_error = true;
            }
            if syntax_error {
                println!("Syntax error: fi found with no previous if");
            }
            continue;
        }

        let mut skipped: bool = false;
        for mode in shell.modes.iter() {
            if !mode.value {
                skipped = true;
                break;
            }
        }
        if skipped {
            continue;
        }

        // Set variables
        if let Some(i) = job.command.find('=') {
            let name = job.command[0..i].trim();
            let mut value = job.command[i + 1..job.command.len()].trim().to_string();

            for i in 0..job.args.len() {
                if let Some(arg) = job.args.get(i) {
                    value = value + " " + &arg;
                }
            }

            set_var(&mut shell.variables, name, &value);
            continue;
        }

        // Commands
        let mut args = job.args.clone();
        args.insert(0, job.command.clone());
        if let Some(command) = commands.get(&job.command.as_str()) {
            (*command.main)(&args, shell);
        } else {
            run_external_commmand(args, &mut shell.variables);
        }
    }
}

pub fn set_var(variables: &mut HashMap<String, String>, name: &str, value: &str) {
    if name.is_empty() {
        return;
    }

    if value.is_empty() {
        variables.remove(&name.to_string());
    } else {
        variables.insert(name.to_string(), value.to_string());
    }
}

fn print_prompt(modes: &Vec<Mode>) {
    for mode in modes.iter().rev() {
        if mode.value {
            print!("+ ");
        } else {
            print!("- ");
        }
    }

    let cwd = match env::current_dir() {
        Ok(path) => {
            match path.to_str() {
                Some(path_str) => path_str.to_string(),
                None => "?".to_string(),
            }
        }
        Err(_) => "?".to_string(),
    };

    print!("ion:{}# ", cwd);
    if let Err(message) = stdout().flush() {
        println!("{}: failed to flush prompt to stdout", message);
    }
}

fn run_external_commmand(args: Vec<String>, variables: &mut HashMap<String, String>) {
    if let Some(path) = args.get(0) {
        let mut command = process::Command::new(path);
        for i in 1..args.len() {
            if let Some(arg) = args.get(i) {
                command.arg(arg);
            }
        }
        match command.spawn() {
            Ok(mut child) => {
                match child.wait() {
                    Ok(status) => {
                        if let Some(code) = status.code() {
                            set_var(variables, "?", &format!("{}", code));
                        } else {
                            println!("{}: No child exit code", path);
                        }
                    }
                    Err(err) => println!("{}: Failed to wait: {}", path, err),
                }
            }
            Err(err) => println!("{}: Failed to execute: {}", path, err),
        }
    }
}

fn main() {
    let commands = Command::map();
    let mut shell = Shell {
        variables: HashMap::new(),
        modes: vec![],
    };

    for arg in env::args().skip(1) {
        let mut command_list = String::new();
        if let Ok(mut file) = File::open(&arg) {
            if let Err(message) = file.read_to_string(&mut command_list) {
                println!("{}: Failed to read {}", message, arg);
            }
        }
        on_command(&command_list, &commands, &mut shell);

        return;
    }

    loop {

        print_prompt(&shell.modes);

        if let Some(command_original) = readln() {
            let command = command_original.trim();
            if command == "exit" {
                break;
            } else if !command.is_empty() {
                on_command(&command, &commands, &mut shell);
            }
        } else {
            break;
        }
    }
}
<commit_msg>Various cleanups based on Ticki's feedback<commit_after>#![feature(box_syntax)]
#![feature(convert)]

use std::collections::HashMap;
use std::fs::File;
use std::io::{stdout, Read, Write};
use std::env;
use std::process;

use self::to_num::ToNum;
use self::input_editor::readln;
use self::tokenizer::tokenize;
use self::expansion::expand_tokens;
use self::parser::parse;

pub mod builtin;
pub mod to_num;
pub mod input_editor;
pub mod tokenizer;
pub mod parser;
pub mod expansion;

/// Structure which represents a Terminal's command.
/// This command structure contains a name, and the code which run the
/// functionnality associated to this one, with zero, one or several argument(s).
/// # Example
/// ```
/// let my_command = Command {
///     name: "my_command",
///     help: "Describe what my_command does followed by a newline showing usage",
///     main: box|args: &[String]| {
///         println!("Say 'hello' to my command! :-D");
///     }
/// }
/// ```
pub struct Command {
    pub name: &'static str,
    pub help: &'static str,
    pub main: Box<Fn(&[String], &mut Shell)>,
}

/// This struct will contain all of the data structures related to this
/// instance of the shell.
pub struct Shell {
    pub variables: HashMap<String, String>,
    pub modes: Vec<Mode>,
}

impl Command {
    /// Return the map from command names to commands
    pub fn map() -> HashMap<&'static str, Self> {
        let mut commands: HashMap<&str, Self> = HashMap::new();

        commands.insert("cat",
                        Command {
                            name: "cat",
                            help: "To display a file in the output\n    cat <your_file>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::cat(args);
                            },
                        });

        commands.insert("cd",
                        Command {
                            name: "cd",
                            help: "To change the current directory\n    cd <your_destination>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::cd(args);
                            },
                        });

        commands.insert("echo",
                        Command {
                            name: "echo",
                            help: "To display some text in the output\n    echo Hello world!",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::echo(args);
                            },
                        });

        commands.insert("exit",
                        Command {
                            name: "exit",
                            help: "To exit the curent session",
                            main: box |_: &[String], _: &mut Shell| {},
                        });

        commands.insert("free",
                        Command {
                            name: "free",
                            help: "Show memory information\n    free",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::free();
                            },
                        });

        commands.insert("ls",
                        Command {
                            name: "ls",
                            help: "To list the content of the current directory\n    ls",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::ls(args);
                            },
                        });

        commands.insert("mkdir",
                        Command {
                            name: "mkdir",
                            help: "To create a directory in the current directory\n    mkdir \
                                   <my_new_directory>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::mkdir(args);
                            },
                        });

        commands.insert("poweroff",
                        Command {
                            name: "poweroff",
                            help: "poweroff utility has the machine remove power, if \
                                   possible\n\tpoweroff",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::poweroff();
                            },
                        });

        commands.insert("ps",
                        Command {
                            name: "ps",
                            help: "Show process list\n    ps",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::ps();
                            },
                        });

        commands.insert("pwd",
                        Command {
                            name: "pwd",
                            help: "To output the path of the current directory\n    pwd",
                            main: box |_: &[String], _: &mut Shell| {
                                builtin::pwd();
                            },
                        });

        commands.insert("read",
                        Command {
                            name: "read",
                            help: "To read some variables\n    read <my_variable>",
                            main: box |args: &[String], shell: &mut Shell| {
                                builtin::read(args, &mut shell.variables);
                            },
                        });

        commands.insert("rm",
                        Command {
                            name: "rm",
                            help: "Remove a file\n    rm <file>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::rm(args);
                            },
                        });

        commands.insert("rmdir",
                        Command {
                            name: "rmdir",
                            help: "Remove a directory\n    rmdir <directory>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::rmdir(args);
                            },
                        });

        commands.insert("run",
                        Command {
                            name: "run",
                            help: "Run a script\n    run <script>",
                            main: box |args: &[String], shell: &mut Shell| {
                                builtin::run(args, &mut shell.variables);
                            },
                        });

        commands.insert("sleep",
                        Command {
                            name: "sleep",
                            help: "Make a sleep in the current session\n    sleep \
                                   <number_of_seconds>",
                            main: box |args: &[String], _: &mut Shell| {
                                builtin::sleep(args);
                            },
                        });

        // TODO: Someone should implement FromIterator for HashMap before
        //       changing the type back to HashMap
        let command_helper: HashMap<String, String> = commands.iter()
                                                              .map(|(k, v)| {
                                                                  (k.to_string(),
                                                                   v.help.to_string())
                                                              })
                                                              .collect();

        commands.insert("help",
                        Command {
                            name: "help",
                            help: "Display a little helper for a given command\n    help ls",
                            main: box move |args: &[String], _: &mut Shell| {
                                if let Some(command) = args.get(1) {
                                    if command_helper.contains_key(command) {
                                        match command_helper.get(command) {
                                            Some(help) => println!("{}", help),
                                            None => {
                                                println!("Command helper not found [run 'help']...")
                                            }
                                        }
                                    } else {
                                        println!("Command helper not found [run 'help']...");
                                    }
                                } else {
                                    for (command, _help) in command_helper.iter() {
                                        println!("{}", command);
                                    }
                                }
                            },
                        });

        commands
    }
}

pub struct Mode {
    value: bool,
}

fn on_command(command_string: &str, commands: &HashMap<&str, Command>, shell: &mut Shell) {
    // Show variables
    if command_string == "$" {
        let mut pairs: Vec<_> = shell.variables.iter().collect();
        pairs.sort();
        for (key, value) in pairs {
            println!("{}={}", key, value);
        }
        return;
    }

    let mut tokens = expand_tokens(&mut tokenize(command_string), &mut shell.variables);
    let jobs = parse(&mut tokens);

    // Execute commands
    for job in jobs.iter() {
        if job.command == "if" {
            let mut value = false;

            if let Some(left) = job.args.get(0) {
                if let Some(cmp) = job.args.get(1) {
                    if let Some(right) = job.args.get(2) {
                        if cmp == "==" {
                            value = *left == *right;
                        } else if cmp == "!=" {
                            value = *left != *right;
                        } else if cmp == ">" {
                            value = left.to_num_signed() > right.to_num_signed();
                        } else if cmp == ">=" {
                            value = left.to_num_signed() >= right.to_num_signed();
                        } else if cmp == "<" {
                            value = left.to_num_signed() < right.to_num_signed();
                        } else if cmp == "<=" {
                            value = left.to_num_signed() <= right.to_num_signed();
                        } else {
                            println!("Unknown comparison: {}", cmp);
                        }
                    } else {
                        println!("No right hand side");
                    }
                } else {
                    println!("No comparison operator");
                }
            } else {
                println!("No left hand side");
            }

            shell.modes.insert(0, Mode { value: value });
            continue;
        }

        if job.command == "else" {
            if let Some(mode) = shell.modes.get_mut(0) {
                mode.value = !mode.value;
            } else {
                println!("Syntax error: else found with no previous if");
            }
            continue;
        }

        if job.command == "fi" {
            if !shell.modes.is_empty() {
                shell.modes.remove(0);
            } else {
                println!("Syntax error: fi found with no previous if");
            }
            continue;
        }

        let mut skipped: bool = false;
        for mode in shell.modes.iter() {
            if !mode.value {
                skipped = true;
                break;
            }
        }
        if skipped {
            continue;
        }

        // Set variables
        if let Some(i) = job.command.find('=') {
            let name = job.command[0..i].trim();
            let mut value = job.command[i + 1..job.command.len()].trim().to_string();

            for i in 0..job.args.len() {
                if let Some(arg) = job.args.get(i) {
                    value = value + " " + &arg;
                }
            }

            set_var(&mut shell.variables, name, &value);
            continue;
        }

        // Commands
        let mut args = job.args.clone();
        args.insert(0, job.command.clone());
        if let Some(command) = commands.get(&job.command.as_str()) {
            (*command.main)(&args, shell);
        } else {
            run_external_commmand(args, &mut shell.variables);
        }
    }
}

pub fn set_var(variables: &mut HashMap<String, String>, name: &str, value: &str) {
    if name.is_empty() {
        return;
    }

    if value.is_empty() {
        variables.remove(&name.to_string());
    } else {
        variables.insert(name.to_string(), value.to_string());
    }
}

fn print_prompt(modes: &Vec<Mode>) {
    for mode in modes.iter().rev() {
        if mode.value {
            print!("+ ");
        } else {
            print!("- ");
        }
    }

    let cwd = match env::current_dir() {
        Ok(path) => {
            match path.to_str() {
                Some(path_str) => path_str.to_string(),
                None => "?".to_string(),
            }
        }
        Err(_) => "?".to_string(),
    };

    print!("ion:{}# ", cwd);
    if let Err(message) = stdout().flush() {
        println!("{}: failed to flush prompt to stdout", message);
    }
}

fn run_external_commmand(args: Vec<String>, variables: &mut HashMap<String, String>) {
    if let Some(path) = args.get(0) {
        let mut command = process::Command::new(path);
        for i in 1..args.len() {
            if let Some(arg) = args.get(i) {
                command.arg(arg);
            }
        }
        match command.spawn() {
            Ok(mut child) => {
                match child.wait() {
                    Ok(status) => {
                        if let Some(code) = status.code() {
                            set_var(variables, "?", &code.to_string());
                        } else {
                            println!("{}: No child exit code", path);
                        }
                    }
                    Err(err) => println!("{}: Failed to wait: {}", path, err),
                }
            }
            Err(err) => println!("{}: Failed to execute: {}", path, err),
        }
    }
}

fn main() {
    let commands = Command::map();
    let mut shell = Shell {
        variables: HashMap::new(),
        modes: vec![],
    };

    for arg in env::args().skip(1) {
        let mut command_list = String::new();
        if let Ok(mut file) = File::open(&arg) {
            if let Err(message) = file.read_to_string(&mut command_list) {
                println!("{}: Failed to read {}", message, arg);
            }
        }
        on_command(&command_list, &commands, &mut shell);

        return;
    }

    loop {

        print_prompt(&shell.modes);

        if let Some(command_original) = readln() {
            let command = command_original.trim();
            if command == "exit" {
                break;
            } else if !command.is_empty() {
                on_command(&command, &commands, &mut shell);
            }
        } else {
            break;
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Change cli msg<commit_after><|endoftext|>


<commit_before><commit_msg>Updated copyright information<commit_after><|endoftext|>


<commit_before>use std::process::{Stdio, Command, Child};
use std::os::unix::io::{FromRawFd, AsRawFd, IntoRawFd};
use std::fs::File;

use super::status::{TERMINATED, NO_SUCH_COMMAND};
use super::peg::Pipeline;

pub fn execute_pipeline(pipeline: Pipeline) -> i32 {
    let mut piped_commands: Vec<Command> = pipeline.jobs
                                                   .iter()
                                                   .map(|job| { job.build_command() })
                                                   .collect();
    if let (Some(stdin_file), Some(command)) = (pipeline.stdin_file, piped_commands.first_mut()) {
        match File::open(&stdin_file) {
            Ok(file) => unsafe { command.stdin(Stdio::from_raw_fd(file.into_raw_fd())); },
            Err(err) => println!("ion: failed to pipe stdin into {}: {}", stdin_file, err)
        }
    }
    if let Some(stdout_file) = pipeline.stdout_file {
        if let Some(mut command) = piped_commands.last_mut() {
            match File::create(&stdout_file) {
                Ok(file) => unsafe { command.stdout(Stdio::from_raw_fd(file.into_raw_fd())); },
                Err(err) => println!("ion: failed to pipe stdout into {}: {}", stdout_file, err)
            }
        }
    }
    pipe(&mut piped_commands)
}

/// This function will panic if called with an empty slice
pub fn pipe(commands: &mut [Command]) -> i32 {
    let end = commands.len() - 1;
    for command in &mut commands[..end] {
        command.stdout(Stdio::piped());
    }
    let mut children: Vec<Option<Child>> = vec![];
    for command in commands {
        if let Some(spawned) = children.last() {
            if let Some(ref child) = *spawned {
                if let Some(ref stdout) = child.stdout {
                    unsafe { command.stdin(Stdio::from_raw_fd(stdout.as_raw_fd())); }
                }
            } else {
                command.stdin(Stdio::null());
            }
        }
        children.push(command.spawn().ok());
    }
    wait(&mut children)
}

/// This function will panic if called with an empty vector
fn wait(children: &mut Vec<Option<Child>>) -> i32 {
    let end = children.len() - 1;
    for child in children.drain(..end) {
        if let Some(mut child) = child {
            child.wait();
        }
    }
    if let Some(mut child) = children.pop().unwrap() {
        match child.wait() {
            Ok(status) => {
                if let Some(code) = status.code() {
                    code
                } else {
                    println!("child ended by signal");
                    TERMINATED
                }
            }
            Err(err) => {
                println!("Failed to wait: {}", err);
                100 // TODO what should we return here?
            }
        }
    } else {
        NO_SUCH_COMMAND
    }
}
<commit_msg>Hack the command name out of the debug information<commit_after>use std::process::{Stdio, Command, Child};
use std::os::unix::io::{FromRawFd, AsRawFd, IntoRawFd};
use std::fs::File;

use super::status::{TERMINATED, NO_SUCH_COMMAND};
use super::peg::Pipeline;

pub fn execute_pipeline(pipeline: Pipeline) -> i32 {
    let mut piped_commands: Vec<Command> = pipeline.jobs
                                                   .iter()
                                                   .map(|job| { job.build_command() })
                                                   .collect();
    if let (Some(stdin_file), Some(command)) = (pipeline.stdin_file, piped_commands.first_mut()) {
        match File::open(&stdin_file) {
            Ok(file) => unsafe { command.stdin(Stdio::from_raw_fd(file.into_raw_fd())); },
            Err(err) => println!("ion: failed to redirect stdin into {}: {}", stdin_file, err)
        }
    }
    if let Some(stdout_file) = pipeline.stdout_file {
        if let Some(mut command) = piped_commands.last_mut() {
            match File::create(&stdout_file) {
                Ok(file) => unsafe { command.stdout(Stdio::from_raw_fd(file.into_raw_fd())); },
                Err(err) => println!("ion: failed to redirect stdout into {}: {}", stdout_file, err)
            }
        }
    }
    pipe(&mut piped_commands)
}

/// This function will panic if called with an empty slice
pub fn pipe(commands: &mut [Command]) -> i32 {
    let end = commands.len() - 1;
    for command in &mut commands[..end] {
        command.stdout(Stdio::piped());
    }
    let mut children: Vec<Option<Child>> = vec![];
    for command in commands {
        if let Some(spawned) = children.last() {
            if let Some(ref child) = *spawned {
                if let Some(ref stdout) = child.stdout {
                    unsafe { command.stdin(Stdio::from_raw_fd(stdout.as_raw_fd())); }
                }
            } else {
                // The previous command failed to spawn
                command.stdin(Stdio::null());
            }
        }
        let child = command.spawn().ok();
        if child.is_none() {
            println!("ion: command not found: {}", get_command_name(&command));
        }
        children.push(child);
    }
    wait(&mut children)
}

/// This function will panic if called with an empty vector
fn wait(children: &mut Vec<Option<Child>>) -> i32 {
    let end = children.len() - 1;
    for child in children.drain(..end) {
        if let Some(mut child) = child {
            child.wait();
        }
    }
    if let Some(mut child) = children.pop().unwrap() {
        match child.wait() {
            Ok(status) => {
                if let Some(code) = status.code() {
                    code
                } else {
                    println!("Child ended by signal");
                    TERMINATED
                }
            }
            Err(err) => {
                println!("Failed to wait: {}", err);
                100 // TODO what should we return here?
            }
        }
    } else {
        NO_SUCH_COMMAND
    }
}

fn get_command_name(command: &Command) -> String {
    format!("{:?}", command).split('"').nth(1).unwrap_or("").to_string()
}
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For you're conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::traits::Button reexported as GtkButtonTrait,
                                // it's trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]

extern crate libc;

pub use gtk::traits::Widget           as GtkWidgetTrait;
pub use gtk::traits::Container        as GtkContainerTrait;
pub use gtk::traits::Window           as GtkWindowTrait;
pub use gtk::traits::Misc             as GtkMiscTrait;
pub use gtk::traits::Button           as GtkButtonTrait;
pub use gtk::traits::Label            as GtkLabelTrait;
pub use gtk::traits::Box              as GtkBoxTrait;
pub use gtk::traits::Orientable       as GtkOrientableTrait;
pub use gtk::traits::Frame            as GtkFrameTrait;
pub use gtk::traits::ToggleButton     as GtkToggleButtonTrait;
pub use gtk::traits::ScaleButton      as GtkScaleButtonTrait;
pub use gtk::traits::Entry            as GtkEntryTrait;
pub use gtk::traits::Bin              as GtkBinTrait;
pub use gtk::traits::ToolShell        as GtkToolShellTrait;
pub use gtk::traits::ToolItem         as GtkToolItemTrait;
pub use gtk::traits::ToolButton       as GtkToolButtonTrait;
pub use gtk::traits::ToggleToolButton as GtkToggleToolButtonTrait;
pub use gtk::traits::Dialog           as GtkDialogTrait;
pub use gtk::traits::ColorChooser     as GtkColorChooserTrait;
pub use gtk::traits::Scrollable       as GtkScrollableTrait;
pub use gtk::traits::FileChooser      as GtkFileChooserTrait;
pub use gtk::traits::FontChooser      as GtkFontChooserTrait;
pub use gtk::traits::AppChooser       as GtkAppChooserTrait;
pub use gtk::traits::Range            as GtkRangeTrait;
pub use gtk::traits::Editable         as GtkEditableTrait;
pub use gtk::traits::MenuShell        as GtkMenuShellTrait;
pub use gtk::traits::MenuItem         as GtkMenuItemTrait;
pub use gtk::traits::CheckMenuItem    as GtkCheckMenuItemTrait;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="windows")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<commit_msg>Reexport CellEditable trait<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For you're conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::traits::Button reexported as GtkButtonTrait,
                                // it's trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]

extern crate libc;

pub use gtk::traits::Widget           as GtkWidgetTrait;
pub use gtk::traits::Container        as GtkContainerTrait;
pub use gtk::traits::Window           as GtkWindowTrait;
pub use gtk::traits::Misc             as GtkMiscTrait;
pub use gtk::traits::Button           as GtkButtonTrait;
pub use gtk::traits::Label            as GtkLabelTrait;
pub use gtk::traits::Box              as GtkBoxTrait;
pub use gtk::traits::Orientable       as GtkOrientableTrait;
pub use gtk::traits::Frame            as GtkFrameTrait;
pub use gtk::traits::ToggleButton     as GtkToggleButtonTrait;
pub use gtk::traits::ScaleButton      as GtkScaleButtonTrait;
pub use gtk::traits::Entry            as GtkEntryTrait;
pub use gtk::traits::Bin              as GtkBinTrait;
pub use gtk::traits::ToolShell        as GtkToolShellTrait;
pub use gtk::traits::ToolItem         as GtkToolItemTrait;
pub use gtk::traits::ToolButton       as GtkToolButtonTrait;
pub use gtk::traits::ToggleToolButton as GtkToggleToolButtonTrait;
pub use gtk::traits::Dialog           as GtkDialogTrait;
pub use gtk::traits::ColorChooser     as GtkColorChooserTrait;
pub use gtk::traits::Scrollable       as GtkScrollableTrait;
pub use gtk::traits::FileChooser      as GtkFileChooserTrait;
pub use gtk::traits::FontChooser      as GtkFontChooserTrait;
pub use gtk::traits::AppChooser       as GtkAppChooserTrait;
pub use gtk::traits::Range            as GtkRangeTrait;
pub use gtk::traits::Editable         as GtkEditableTrait;
pub use gtk::traits::MenuShell        as GtkMenuShellTrait;
pub use gtk::traits::MenuItem         as GtkMenuItemTrait;
pub use gtk::traits::CheckMenuItem    as GtkCheckMenuItemTrait;
pub use gtk::traits::CellEditable     as GtkCellEditable;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="windows")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gio-2.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For you're conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::traits::Button reexported as GtkButtonTrait,
                                // it's trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]

extern crate libc;

pub use GtkWidgetTrait          = gtk::traits::Widget;
pub use GtkContainerTrait       = gtk::traits::Container;
pub use GtkWindowTrait          = gtk::traits::Window;
pub use GtkMiscTrait            = gtk::traits::Misc;
pub use GtkButtonTrait          = gtk::traits::Button;
pub use GtkLabelTrait           = gtk::traits::Label;
pub use GtkBoxTrait             = gtk::traits::Box;
pub use GtkOrientableTrait      = gtk::traits::Orientable;
pub use GtkFrameTrait           = gtk::traits::Frame;
pub use GtkToggleButtonTrait    = gtk::traits::ToggleButton;
pub use GtkScaleButtonTrait     = gtk::traits::ScaleButton;
pub use GtkEntryTrait           = gtk::traits::Entry;
pub use GtkBinTrait             = gtk::traits::Bin;
pub use GtkToolShellTrait       = gtk::traits::ToolShell;
pub use GtkToolItemTrait        = gtk::traits::ToolItem;
pub use GtkToolButtonTrait      = gtk::traits::ToolButton;
pub use GtkToggleToolButtonTrait= gtk::traits::ToggleToolButton;
pub use GtkDialogTrait          = gtk::traits::Dialog;
pub use GtkColorChooserTrait    = gtk::traits::ColorChooser;
pub use GtkScrollableTrait      = gtk::traits::Scrollable;
pub use GtkFileChooserTrait     = gtk::traits::FileChooser;
pub use GtkFontChooserTrait     = gtk::traits::FontChooser;
pub use GtkAppChooserTrait      = gtk::traits::AppChooser;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<commit_msg>Update to last rust compiler version<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

/*!

Bindings and wrappers for __GTK+__, __GLib__ and __Cairo__.

The various parts of __rgtk__ can be found in the submodules __gtk__, __gdk__, __glib__ and __cairo__.

Trait reexports
===============

For you're conveniance the various traits of `rgtk` are reexported in the `rgtk::*`
namespace as `{Gtk/Gdk/Glib/Cairo}{trait_name}Trait` so you can just use...

```Rust
extern mod rgtk;
use rgtk::*;
```

...to easily access all the traits methods:

```Rust
let button = gtk::Button:new(); // trait gtk::traits::Button reexported as GtkButtonTrait,
                                // it's trait methods can be accessed here.
```
*/

#![crate_name = "rgtk"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![feature(macro_rules)]
#![allow(dead_code)] // TODO: drop this
#![feature(unsafe_destructor)]

extern crate libc;

pub use gtk::traits::Widget           as GtkWidgetTrait;
pub use gtk::traits::Container        as GtkContainerTrait;
pub use gtk::traits::Window           as GtkWindowTrait;
pub use gtk::traits::Misc             as GtkMiscTrait;
pub use gtk::traits::Button           as GtkButtonTrait;
pub use gtk::traits::Label            as GtkLabelTrait;
pub use gtk::traits::Box              as GtkBoxTrait;
pub use gtk::traits::Orientable       as GtkOrientableTrait;
pub use gtk::traits::Frame            as GtkFrameTrait;
pub use gtk::traits::ToggleButton     as GtkToggleButtonTrait;
pub use gtk::traits::ScaleButton      as GtkScaleButtonTrait;
pub use gtk::traits::Entry            as GtkEntryTrait;
pub use gtk::traits::Bin              as GtkBinTrait;
pub use gtk::traits::ToolShell        as GtkToolShellTrait;
pub use gtk::traits::ToolItem         as GtkToolItemTrait;
pub use gtk::traits::ToolButton       as GtkToolButtonTrait;
pub use gtk::traits::ToggleToolButton as GtkToggleToolButtonTrait;
pub use gtk::traits::Dialog           as GtkDialogTrait;
pub use gtk::traits::ColorChooser     as GtkColorChooserTrait;
pub use gtk::traits::Scrollable       as GtkScrollableTrait;
pub use gtk::traits::FileChooser      as GtkFileChooserTrait;
pub use gtk::traits::FontChooser      as GtkFontChooserTrait;
pub use gtk::traits::AppChooser       as GtkAppChooserTrait;

#[doc(hidden)]
#[cfg(target_os="macos")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3.0")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3.0")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

#[doc(hidden)]
#[cfg(target_os="linux")]
mod platform {
    #[link(name = "glib-2.0")]
    #[link(name = "gtk-3")]
    #[link(name = "gobject-2.0")]
    #[link(name = "gdk-3")]
    #[link(name = "rgtk_glue", kind = "static")]
    extern{}
}

pub mod gtk;
pub mod cairo;
pub mod gdk;
pub mod glib;
<|endoftext|>


<commit_before><commit_msg>Fix some parts of view not redrawing when changing Scene<commit_after><|endoftext|>


<commit_before><commit_msg>forgot to add testdata.rs<commit_after>use super::*;

pub struct TestImage {
    pub pixels: Vec<Color>,
    pub width: usize,
    pub height: usize,
}

pub fn test_image() -> TestImage {
    TestImage {
        pixels: (0..65536)
            .map(|_| Color::new(0, 0, 0, 255))
            .collect(),
        width: 256,
        height: 256,
    }
}
<|endoftext|>


<commit_before><commit_msg>make map bigger<commit_after><|endoftext|>


<commit_before><commit_msg>Unnecessary feature.<commit_after><|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, TokenStreamExt};
use syn::punctuated::Punctuated;
use syn::synom::Synom;
use syn::{Field, FieldValue, Ident, Meta};

mod metadata;
mod request;
mod response;

use self::metadata::Metadata;
use self::request::Request;
use self::response::Response;

pub fn strip_serde_attrs(field: &Field) -> Field {
    let mut field = field.clone();

    field.attrs = field.attrs.into_iter().filter(|attr| {
        let meta = attr.interpret_meta()
            .expect("ruma_api! could not parse field attributes");

        let meta_list = match meta {
            Meta::List(meta_list) => meta_list,
            _ => return true,
        };

        if meta_list.ident == "serde" {
            return false;
        }

        true
    }).collect();

    field
}

pub struct Api {
    metadata: Metadata,
    request: Request,
    response: Response,
}

impl From<RawApi> for Api {
    fn from(raw_api: RawApi) -> Self {
        Api {
            metadata: raw_api.metadata.into(),
            request: raw_api.request.into(),
            response: raw_api.response.into(),
        }
    }
}

impl ToTokens for Api {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let description = &self.metadata.description;
        let method = Ident::new(self.metadata.method.as_ref(), Span::call_site());
        let name = &self.metadata.name;
        let path = &self.metadata.path;
        let rate_limited = &self.metadata.rate_limited;
        let requires_authentication = &self.metadata.requires_authentication;

        let request = &self.request;
        let request_types = quote! { #request };
        let response = &self.response;
        let response_types = quote! { #response };

        let extract_request_path = if self.request.has_path_fields() {
            quote! {
                let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect();
            }
        } else {
            TokenStream::new()
        };

        let (set_request_path, parse_request_path) = if self.request.has_path_fields() {
            let path_str = path.as_str();

            assert!(path_str.starts_with('/'), "path needs to start with '/'");
            assert!(
                path_str.chars().filter(|c| *c == ':').count() == self.request.path_field_count(),
                "number of declared path parameters needs to match amount of placeholders in path"
            );

            let request_path_init_fields = self.request.request_path_init_fields();

            let mut set_tokens = quote! {
                let request_path = RequestPath {
                    #request_path_init_fields
                };

                // This `unwrap()` can only fail when the url is a
                // cannot-be-base url like `mailto:` or `data:`, which is not
                // the case for our placeholder url.
                let mut path_segments = url.path_segments_mut().unwrap();
            };

            let mut parse_tokens = TokenStream::new();

            for (i, segment) in path_str[1..].split('/').into_iter().enumerate() {
                set_tokens.append_all(quote! {
                    path_segments.push
                });

                if segment.starts_with(':') {
                    let path_var = &segment[1..];
                    let path_var_ident = Ident::new(path_var, Span::call_site());

                    set_tokens.append_all(quote! {
                        (&request_path.#path_var_ident.to_string());
                    });

                    let path_field = self.request.path_field(path_var)
                        .expect("expected request to have path field");
                    let ty = &path_field.ty;

                    parse_tokens.append_all(quote! {
                        #path_var_ident: {
                            let segment = path_segments.get(#i).unwrap().as_bytes();
                            let decoded =
                                ::url::percent_encoding::percent_decode(segment)
                                .decode_utf8_lossy();
                            #ty::deserialize(decoded.into_deserializer())
                                .map_err(|e: ::serde_json::error::Error| e)?
                        },
                    });
                } else {
                    set_tokens.append_all(quote! {
                        (#segment);
                    });
                }
            }

            (set_tokens, parse_tokens)
        } else {
            let set_tokens = quote! {
                url.set_path(metadata.path);
            };
            let parse_tokens = TokenStream::new();
            (set_tokens, parse_tokens)
        };

        let set_request_query = if self.request.has_query_fields() {
            let request_query_init_fields = self.request.request_query_init_fields();

            quote! {
                let request_query = RequestQuery {
                    #request_query_init_fields
                };

                url.set_query(Some(&::serde_urlencoded::to_string(request_query)?));
            }
        } else {
            TokenStream::new()
        };

        let extract_request_query = if self.request.has_query_fields() {
            quote! {
                let request_query: RequestQuery =
                    ::serde_urlencoded::from_str(&request.uri().query().unwrap_or(""))?;
            }
        } else {
            TokenStream::new()
        };

        let parse_request_query = if self.request.has_query_fields() {
            self.request.request_init_query_fields()
        } else {
            TokenStream::new()
        };

        let add_headers_to_request = if self.request.has_header_fields() {
            let mut header_tokens = quote! {
                let headers = http_request.headers_mut();
            };

            header_tokens.append_all(self.request.add_headers_to_request());

            header_tokens
        } else {
            TokenStream::new()
        };

        let extract_request_headers = if self.request.has_header_fields() {
            quote! {
                let headers = request.headers();
            }
        } else {
            TokenStream::new()
        };

        let parse_request_headers = if self.request.has_header_fields() {
            self.request.parse_headers_from_request()
        } else {
            TokenStream::new()
        };

        let create_http_request = if let Some(field) = self.request.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");

            quote! {
                let request_body = RequestBody(request.#field_name);

                let mut http_request = ::http::Request::new(::serde_json::to_vec(&request_body)?.into());
            }
        } else if self.request.has_body_fields() {
            let request_body_init_fields = self.request.request_body_init_fields();

            quote! {
                let request_body = RequestBody {
                    #request_body_init_fields
                };

                let mut http_request = ::http::Request::new(::serde_json::to_vec(&request_body)?.into());
            }
        } else {
            quote! {
                let mut http_request = ::http::Request::new(::hyper::Body::empty());
            }
        };

        let extract_request_body = if let Some(field) = self.request.newtype_body_field() {
            let ty = &field.ty;
            quote! {
                let request_body: #ty =
                    ::serde_json::from_slice(request.body().as_slice())?;
            }
        } else if self.request.has_body_fields() {
            quote! {
                let request_body: RequestBody =
                    ::serde_json::from_slice(request.body().as_slice())?;
            }
        } else {
            TokenStream::new()
        };

        let parse_request_body = if let Some(field) = self.request.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");

            quote! {
                #field_name: request_body,
            }
        } else if self.request.has_body_fields() {
            self.request.request_init_body_fields()
        } else {
            TokenStream::new()
        };

        let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() {
            let field_type = &field.ty;

            quote! {
                let future_response = http_response.into_body()
                    .fold(Vec::new(), |mut vec, chunk| {
                        vec.extend(chunk.iter());
                        ::futures::future::ok::<_, ::hyper::Error>(vec)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|data|
                              ::serde_json::from_slice::<#field_type>(data.as_slice())
                              .map_err(::ruma_api::Error::from)
                              .into_future()
                    )
            }
        } else if self.response.has_body_fields() {
            quote! {
                let future_response = http_response.into_body()
                    .fold(Vec::new(), |mut vec, chunk| {
                        vec.extend(chunk.iter());
                        ::futures::future::ok::<_, ::hyper::Error>(vec)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|data|
                              ::serde_json::from_slice::<ResponseBody>(data.as_slice())
                              .map_err(::ruma_api::Error::from)
                              .into_future()
                    )
            }
        } else {
            quote! {
                let future_response = ::futures::future::ok(())
            }
        };

        let extract_response_headers = if self.response.has_header_fields() {
            quote! {
                let mut headers = http_response.headers().clone();
            }
        } else {
            TokenStream::new()
        };

        let response_init_fields = if self.response.has_fields() {
            self.response.init_fields()
        } else {
            TokenStream::new()
        };

        let serialize_response_headers = self.response.apply_header_fields();

        let serialize_response_body = if self.response.has_body() {
            let body = self.response.to_body();
            quote! {
                .body(::hyper::Body::from(::serde_json::to_vec(&#body)?))
            }
        } else {
            quote! {
                .body(::hyper::Body::from("{}".as_bytes().to_vec()))
            }
        };

        tokens.append_all(quote! {
            #[allow(unused_imports)]
            use ::futures::{Future as _Future, IntoFuture as _IntoFuture, Stream as _Stream};
            use ::ruma_api::Endpoint as _RumaApiEndpoint;
            use ::serde::Deserialize;
            use ::serde::de::{Error as _SerdeError, IntoDeserializer};

            use ::std::convert::{TryInto as _TryInto};

            /// The API endpoint.
            #[derive(Debug)]
            pub struct Endpoint;

            #request_types

            impl ::std::convert::TryFrom<::http::Request<Vec<u8>>> for Request {
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn try_from(request: ::http::Request<Vec<u8>>) -> Result<Self, Self::Error> {
                    #extract_request_path
                    #extract_request_query
                    #extract_request_headers
                    #extract_request_body

                    Ok(Request {
                        #parse_request_path
                        #parse_request_query
                        #parse_request_headers
                        #parse_request_body
                    })
                }
            }

            impl ::futures::future::FutureFrom<::http::Request<::hyper::Body>> for Request {
                type Future = Box<_Future<Item = Self, Error = Self::Error>>;
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn future_from(request: ::http::Request<::hyper::Body>) -> Self::Future {
                    let (parts, body) = request.into_parts();
                    let future = body.from_err().fold(Vec::new(), |mut vec, chunk| {
                        vec.extend(chunk.iter());
                        ::futures::future::ok::<_, Self::Error>(vec)
                    }).and_then(|body| {
                        ::http::Request::from_parts(parts, body)
                            .try_into()
                            .into_future()
                            .from_err()
                    });
                    Box::new(future)
                }
            }

            impl ::std::convert::TryFrom<Request> for ::http::Request<::hyper::Body> {
                type Error = ::ruma_api::Error;

                #[allow(unused_mut, unused_variables)]
                fn try_from(request: Request) -> Result<Self, Self::Error> {
                    let metadata = Endpoint::METADATA;

                    // Use dummy homeserver url which has to be overwritten in
                    // the calling code. Previously (with http::Uri) this was
                    // not required, but Url::parse only accepts absolute urls.
                    let mut url = ::url::Url::parse("http://invalid-host-please-change/").unwrap();

                    { #set_request_path }
                    { #set_request_query }

                    #create_http_request

                    *http_request.method_mut() = ::http::Method::#method;
                    *http_request.uri_mut() = url.into_string().parse().unwrap();

                    { #add_headers_to_request }

                    Ok(http_request)
                }
            }

            #response_types

            impl ::std::convert::TryFrom<Response> for ::http::Response<::hyper::Body> {
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn try_from(response: Response) -> Result<Self, Self::Error> {
                    let response = ::http::Response::builder()
                        .header(::http::header::CONTENT_TYPE, "application/json")
                        #serialize_response_headers
                        #serialize_response_body
                        .unwrap();
                    Ok(response)
                }
            }

            impl ::futures::future::FutureFrom<::http::Response<::hyper::Body>> for Response {
                type Future = Box<_Future<Item = Self, Error = Self::Error>>;
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn future_from(http_response: ::http::Response<::hyper::Body>)
                -> Box<_Future<Item = Self, Error = Self::Error>> {
                    if http_response.status().is_success() {
                        #extract_response_headers

                        #deserialize_response_body
                        .and_then(move |response_body| {
                            let response = Response {
                                #response_init_fields
                            };

                            Ok(response)
                        });

                        Box::new(future_response)
                    } else {
                        Box::new(::futures::future::err(::ruma_api::Error::StatusCode(http_response.status().clone())))
                    }
                }
            }

            impl ::ruma_api::Endpoint for Endpoint {
                type Request = Request;
                type Response = Response;

                const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata {
                    description: #description,
                    method: ::http::Method::#method,
                    name: #name,
                    path: #path,
                    rate_limited: #rate_limited,
                    requires_authentication: #requires_authentication,
                };
            }
        });
    }
}

type ParseMetadata = Punctuated<FieldValue, Token![,]>;
type ParseFields = Punctuated<Field, Token![,]>;

pub struct RawApi {
    pub metadata: Vec<FieldValue>,
    pub request: Vec<Field>,
    pub response: Vec<Field>,
}

impl Synom for RawApi {
    named!(parse -> Self, do_parse!(
        custom_keyword!(metadata) >>
        metadata: braces!(ParseMetadata::parse_terminated) >>
        custom_keyword!(request) >>
        request: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        custom_keyword!(response) >>
        response: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        (RawApi {
            metadata: metadata.1.into_iter().collect(),
            request: request.1.into_iter().collect(),
            response: response.1.into_iter().collect(),
        })
    ));
}
<commit_msg>Make the Future returned by generated `future_from`s be Send<commit_after>use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, TokenStreamExt};
use syn::punctuated::Punctuated;
use syn::synom::Synom;
use syn::{Field, FieldValue, Ident, Meta};

mod metadata;
mod request;
mod response;

use self::metadata::Metadata;
use self::request::Request;
use self::response::Response;

pub fn strip_serde_attrs(field: &Field) -> Field {
    let mut field = field.clone();

    field.attrs = field.attrs.into_iter().filter(|attr| {
        let meta = attr.interpret_meta()
            .expect("ruma_api! could not parse field attributes");

        let meta_list = match meta {
            Meta::List(meta_list) => meta_list,
            _ => return true,
        };

        if meta_list.ident == "serde" {
            return false;
        }

        true
    }).collect();

    field
}

pub struct Api {
    metadata: Metadata,
    request: Request,
    response: Response,
}

impl From<RawApi> for Api {
    fn from(raw_api: RawApi) -> Self {
        Api {
            metadata: raw_api.metadata.into(),
            request: raw_api.request.into(),
            response: raw_api.response.into(),
        }
    }
}

impl ToTokens for Api {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let description = &self.metadata.description;
        let method = Ident::new(self.metadata.method.as_ref(), Span::call_site());
        let name = &self.metadata.name;
        let path = &self.metadata.path;
        let rate_limited = &self.metadata.rate_limited;
        let requires_authentication = &self.metadata.requires_authentication;

        let request = &self.request;
        let request_types = quote! { #request };
        let response = &self.response;
        let response_types = quote! { #response };

        let extract_request_path = if self.request.has_path_fields() {
            quote! {
                let path_segments: Vec<&str> = request.uri().path()[1..].split('/').collect();
            }
        } else {
            TokenStream::new()
        };

        let (set_request_path, parse_request_path) = if self.request.has_path_fields() {
            let path_str = path.as_str();

            assert!(path_str.starts_with('/'), "path needs to start with '/'");
            assert!(
                path_str.chars().filter(|c| *c == ':').count() == self.request.path_field_count(),
                "number of declared path parameters needs to match amount of placeholders in path"
            );

            let request_path_init_fields = self.request.request_path_init_fields();

            let mut set_tokens = quote! {
                let request_path = RequestPath {
                    #request_path_init_fields
                };

                // This `unwrap()` can only fail when the url is a
                // cannot-be-base url like `mailto:` or `data:`, which is not
                // the case for our placeholder url.
                let mut path_segments = url.path_segments_mut().unwrap();
            };

            let mut parse_tokens = TokenStream::new();

            for (i, segment) in path_str[1..].split('/').into_iter().enumerate() {
                set_tokens.append_all(quote! {
                    path_segments.push
                });

                if segment.starts_with(':') {
                    let path_var = &segment[1..];
                    let path_var_ident = Ident::new(path_var, Span::call_site());

                    set_tokens.append_all(quote! {
                        (&request_path.#path_var_ident.to_string());
                    });

                    let path_field = self.request.path_field(path_var)
                        .expect("expected request to have path field");
                    let ty = &path_field.ty;

                    parse_tokens.append_all(quote! {
                        #path_var_ident: {
                            let segment = path_segments.get(#i).unwrap().as_bytes();
                            let decoded =
                                ::url::percent_encoding::percent_decode(segment)
                                .decode_utf8_lossy();
                            #ty::deserialize(decoded.into_deserializer())
                                .map_err(|e: ::serde_json::error::Error| e)?
                        },
                    });
                } else {
                    set_tokens.append_all(quote! {
                        (#segment);
                    });
                }
            }

            (set_tokens, parse_tokens)
        } else {
            let set_tokens = quote! {
                url.set_path(metadata.path);
            };
            let parse_tokens = TokenStream::new();
            (set_tokens, parse_tokens)
        };

        let set_request_query = if self.request.has_query_fields() {
            let request_query_init_fields = self.request.request_query_init_fields();

            quote! {
                let request_query = RequestQuery {
                    #request_query_init_fields
                };

                url.set_query(Some(&::serde_urlencoded::to_string(request_query)?));
            }
        } else {
            TokenStream::new()
        };

        let extract_request_query = if self.request.has_query_fields() {
            quote! {
                let request_query: RequestQuery =
                    ::serde_urlencoded::from_str(&request.uri().query().unwrap_or(""))?;
            }
        } else {
            TokenStream::new()
        };

        let parse_request_query = if self.request.has_query_fields() {
            self.request.request_init_query_fields()
        } else {
            TokenStream::new()
        };

        let add_headers_to_request = if self.request.has_header_fields() {
            let mut header_tokens = quote! {
                let headers = http_request.headers_mut();
            };

            header_tokens.append_all(self.request.add_headers_to_request());

            header_tokens
        } else {
            TokenStream::new()
        };

        let extract_request_headers = if self.request.has_header_fields() {
            quote! {
                let headers = request.headers();
            }
        } else {
            TokenStream::new()
        };

        let parse_request_headers = if self.request.has_header_fields() {
            self.request.parse_headers_from_request()
        } else {
            TokenStream::new()
        };

        let create_http_request = if let Some(field) = self.request.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");

            quote! {
                let request_body = RequestBody(request.#field_name);

                let mut http_request = ::http::Request::new(::serde_json::to_vec(&request_body)?.into());
            }
        } else if self.request.has_body_fields() {
            let request_body_init_fields = self.request.request_body_init_fields();

            quote! {
                let request_body = RequestBody {
                    #request_body_init_fields
                };

                let mut http_request = ::http::Request::new(::serde_json::to_vec(&request_body)?.into());
            }
        } else {
            quote! {
                let mut http_request = ::http::Request::new(::hyper::Body::empty());
            }
        };

        let extract_request_body = if let Some(field) = self.request.newtype_body_field() {
            let ty = &field.ty;
            quote! {
                let request_body: #ty =
                    ::serde_json::from_slice(request.body().as_slice())?;
            }
        } else if self.request.has_body_fields() {
            quote! {
                let request_body: RequestBody =
                    ::serde_json::from_slice(request.body().as_slice())?;
            }
        } else {
            TokenStream::new()
        };

        let parse_request_body = if let Some(field) = self.request.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");

            quote! {
                #field_name: request_body,
            }
        } else if self.request.has_body_fields() {
            self.request.request_init_body_fields()
        } else {
            TokenStream::new()
        };

        let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() {
            let field_type = &field.ty;

            quote! {
                let future_response = http_response.into_body()
                    .fold(Vec::new(), |mut vec, chunk| {
                        vec.extend(chunk.iter());
                        ::futures::future::ok::<_, ::hyper::Error>(vec)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|data|
                              ::serde_json::from_slice::<#field_type>(data.as_slice())
                              .map_err(::ruma_api::Error::from)
                              .into_future()
                    )
            }
        } else if self.response.has_body_fields() {
            quote! {
                let future_response = http_response.into_body()
                    .fold(Vec::new(), |mut vec, chunk| {
                        vec.extend(chunk.iter());
                        ::futures::future::ok::<_, ::hyper::Error>(vec)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|data|
                              ::serde_json::from_slice::<ResponseBody>(data.as_slice())
                              .map_err(::ruma_api::Error::from)
                              .into_future()
                    )
            }
        } else {
            quote! {
                let future_response = ::futures::future::ok(())
            }
        };

        let extract_response_headers = if self.response.has_header_fields() {
            quote! {
                let mut headers = http_response.headers().clone();
            }
        } else {
            TokenStream::new()
        };

        let response_init_fields = if self.response.has_fields() {
            self.response.init_fields()
        } else {
            TokenStream::new()
        };

        let serialize_response_headers = self.response.apply_header_fields();

        let serialize_response_body = if self.response.has_body() {
            let body = self.response.to_body();
            quote! {
                .body(::hyper::Body::from(::serde_json::to_vec(&#body)?))
            }
        } else {
            quote! {
                .body(::hyper::Body::from("{}".as_bytes().to_vec()))
            }
        };

        tokens.append_all(quote! {
            #[allow(unused_imports)]
            use ::futures::{Future as _Future, IntoFuture as _IntoFuture, Stream as _Stream};
            use ::ruma_api::Endpoint as _RumaApiEndpoint;
            use ::serde::Deserialize;
            use ::serde::de::{Error as _SerdeError, IntoDeserializer};

            use ::std::convert::{TryInto as _TryInto};

            /// The API endpoint.
            #[derive(Debug)]
            pub struct Endpoint;

            #request_types

            impl ::std::convert::TryFrom<::http::Request<Vec<u8>>> for Request {
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn try_from(request: ::http::Request<Vec<u8>>) -> Result<Self, Self::Error> {
                    #extract_request_path
                    #extract_request_query
                    #extract_request_headers
                    #extract_request_body

                    Ok(Request {
                        #parse_request_path
                        #parse_request_query
                        #parse_request_headers
                        #parse_request_body
                    })
                }
            }

            impl ::futures::future::FutureFrom<::http::Request<::hyper::Body>> for Request {
                type Future = Box<_Future<Item = Self, Error = Self::Error> + Send>;
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn future_from(request: ::http::Request<::hyper::Body>) -> Self::Future {
                    let (parts, body) = request.into_parts();
                    let future = body.from_err().fold(Vec::new(), |mut vec, chunk| {
                        vec.extend(chunk.iter());
                        ::futures::future::ok::<_, Self::Error>(vec)
                    }).and_then(|body| {
                        ::http::Request::from_parts(parts, body)
                            .try_into()
                            .into_future()
                            .from_err()
                    });
                    Box::new(future)
                }
            }

            impl ::std::convert::TryFrom<Request> for ::http::Request<::hyper::Body> {
                type Error = ::ruma_api::Error;

                #[allow(unused_mut, unused_variables)]
                fn try_from(request: Request) -> Result<Self, Self::Error> {
                    let metadata = Endpoint::METADATA;

                    // Use dummy homeserver url which has to be overwritten in
                    // the calling code. Previously (with http::Uri) this was
                    // not required, but Url::parse only accepts absolute urls.
                    let mut url = ::url::Url::parse("http://invalid-host-please-change/").unwrap();

                    { #set_request_path }
                    { #set_request_query }

                    #create_http_request

                    *http_request.method_mut() = ::http::Method::#method;
                    *http_request.uri_mut() = url.into_string().parse().unwrap();

                    { #add_headers_to_request }

                    Ok(http_request)
                }
            }

            #response_types

            impl ::std::convert::TryFrom<Response> for ::http::Response<::hyper::Body> {
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn try_from(response: Response) -> Result<Self, Self::Error> {
                    let response = ::http::Response::builder()
                        .header(::http::header::CONTENT_TYPE, "application/json")
                        #serialize_response_headers
                        #serialize_response_body
                        .unwrap();
                    Ok(response)
                }
            }

            impl ::futures::future::FutureFrom<::http::Response<::hyper::Body>> for Response {
                type Future = Box<_Future<Item = Self, Error = Self::Error> + Send>;
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn future_from(http_response: ::http::Response<::hyper::Body>) -> Self::Future {
                    if http_response.status().is_success() {
                        #extract_response_headers

                        #deserialize_response_body
                        .and_then(move |response_body| {
                            let response = Response {
                                #response_init_fields
                            };

                            Ok(response)
                        });

                        Box::new(future_response)
                    } else {
                        Box::new(::futures::future::err(::ruma_api::Error::StatusCode(http_response.status().clone())))
                    }
                }
            }

            impl ::ruma_api::Endpoint for Endpoint {
                type Request = Request;
                type Response = Response;

                const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata {
                    description: #description,
                    method: ::http::Method::#method,
                    name: #name,
                    path: #path,
                    rate_limited: #rate_limited,
                    requires_authentication: #requires_authentication,
                };
            }
        });
    }
}

type ParseMetadata = Punctuated<FieldValue, Token![,]>;
type ParseFields = Punctuated<Field, Token![,]>;

pub struct RawApi {
    pub metadata: Vec<FieldValue>,
    pub request: Vec<Field>,
    pub response: Vec<Field>,
}

impl Synom for RawApi {
    named!(parse -> Self, do_parse!(
        custom_keyword!(metadata) >>
        metadata: braces!(ParseMetadata::parse_terminated) >>
        custom_keyword!(request) >>
        request: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        custom_keyword!(response) >>
        response: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        (RawApi {
            metadata: metadata.1.into_iter().collect(),
            request: request.1.into_iter().collect(),
            response: response.1.into_iter().collect(),
        })
    ));
}
<|endoftext|>


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

/// Trait for testing approximate equality
pub trait ApproxEq<Eps> {
    fn approx_epsilon() -> Eps;
    fn approx_eq(&self, other: &Self) -> bool;
    fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool;
}

impl ApproxEq<f32> for f32 {
    #[inline]
    fn approx_epsilon() -> f32 { 1.0e-6 }

    #[inline]
    fn approx_eq(&self, other: &f32) -> bool {
       self.approx_eq_eps(other, &1.0e-6)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &f32, approx_epsilon: &f32) -> bool {
       (*self - *other).abs() < *approx_epsilon
    }
}

impl ApproxEq<f64> for f64 {
    #[inline]
    fn approx_epsilon() -> f64 { 1.0e-6 }

    #[inline]
    fn approx_eq(&self, other: &f64) -> bool {
        self.approx_eq_eps(other, &1.0e-6)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &f64, approx_epsilon: &f64) -> bool {
        (*self - *other).abs() < *approx_epsilon
    }
}
<|endoftext|>


<commit_before><commit_msg>Improve matrix output formatting<commit_after><|endoftext|>


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

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#![feature(core, libc, unsafe_destructor)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate libc;

// public re-exports
pub use render::{Renderer, DrawError};
pub use render::batch;
pub use render::device_ext::{DeviceExt, ShaderSource, ProgramError};
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::Error as MeshError;
pub use render::mesh::{Slice, ToSlice, SliceKind};
pub use render::state::{BlendPreset, DrawState};
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use device::{Device, Resources};
pub use device::{attrib, state, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle, SamplerHandle};
pub use device::BufferUsage;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::{ProgramInfo, UniformValue};
pub use device::target::*;

#[path = "../render/lib.rs"] pub mod render;
#[path = "../device/lib.rs"] pub mod device;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device> Graphics<D> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Create a new ref batch.
    pub fn make_batch<T: shade::ShaderParam<Resources = D::Resources>>(&mut self,
                      program: &ProgramHandle<D::Resources>,
                      mesh: &Mesh<D::Resources>,
                      slice: Slice<D::Resources>,
                      state: &DrawState)
                      -> Result<batch::RefBatch<T>, batch::Error> {
        self.context.make_batch(program, mesh, slice, state)
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a ref batch.
    pub fn draw<'a, T: shade::ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, data: &'a T, frame: &Frame<D::Resources>)
                -> Result<(), DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, data, &self.context), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<commit_msg>Switched Graphics to use the new bind()<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#![feature(core, libc, unsafe_destructor)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate libc;

// public re-exports
pub use render::{Renderer, DrawError};
pub use render::batch;
pub use render::device_ext::{DeviceExt, ShaderSource, ProgramError};
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::Error as MeshError;
pub use render::mesh::{Slice, ToSlice, SliceKind};
pub use render::state::{BlendPreset, DrawState};
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use device::{Device, Resources};
pub use device::{attrib, state, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle, SamplerHandle};
pub use device::BufferUsage;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::{ProgramInfo, UniformValue};
pub use device::target::*;

#[path = "../render/lib.rs"] pub mod render;
#[path = "../device/lib.rs"] pub mod device;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device> Graphics<D> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Create a new ref batch.
    pub fn make_batch<T: shade::ShaderParam<Resources = D::Resources>>(&mut self,
                      program: &ProgramHandle<D::Resources>,
                      mesh: &Mesh<D::Resources>,
                      slice: Slice<D::Resources>,
                      state: &DrawState)
                      -> Result<batch::RefBatch<T>, batch::Error> {
        self.context.make_batch(program, mesh, slice, state)
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a ref batch.
    pub fn draw<'a, T: shade::ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, data: &'a T, frame: &Frame<D::Resources>)
                -> Result<(), DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(batch, data), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<|endoftext|>