<commit_before>use redox::ops::DerefMut;
use redox::string::*;
use redox::vec::Vec;
use redox::boxed::Box;
use redox::fs::*;
use redox::io::*;
use redox::env::*;
use redox::time::Duration;
use redox::to_num::*;

/* Magic Macros { */
static mut application: *mut Application<'static> = 0 as *mut Application;

/// Execute a command
macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd.to_string());
        }
    })
}
/* } Magic Macros */

/// A command
pub struct Command<'a> {
    pub name: &'a str,
    pub main: Box<Fn(&Vec<String>)>,
}

impl<'a> Command<'a> {
    /// Return the vector of the commands
    // TODO: Use a more efficient collection instead
    pub fn vec() -> Vec<Self> {
        let mut commands: Vec<Self> = Vec::new();

        commands.push(Command {
            name: "cat",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read: {}", path),
                    }
                } else {
                    println!("Failed to open file: {}", path);
                }
            },
        });

        commands.push(Command {
            name: "cd",
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(path) => {
                        if !change_cwd(&path) {
                            println!("Bad path: {}", path);
                        }
                    }
                    None => println!("No path given")
                }
            },
        });

        commands.push(Command {
            name: "echo",
            main: box |args: &Vec<String>| {
                let echo = args.iter()
                    .skip(1)
                    .fold(String::new(), |string, arg| string + " " + arg);
                println!("{}", echo.trim());
            },
        });

        commands.push(Command {
            name: "else",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "exec",
            main: box |args: &Vec<String>| {
                if let Some(arg) = args.get(1) {
                    File::exec(arg);
                }
            },
        });

        commands.push(Command {
            name: "exit",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "fi",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "if",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "ls",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(dir) = read_dir(&path) {
                    for entry in dir {
                        println!("{}", entry.path());
                    }
                } else {
                    println!("Failed to open directory: {}", path);
                }
            }
        });

        commands.push(Command {
            name: "pwd",
            main: box |_: &Vec<String>| {
                if let Some(file) = File::open("") {
                    if let Some(path) = file.path() {
                        println!("{}", path);
                    } else {
                        println!("Could not get the path");
                    }
                } else {
                    println!("Could not open the working directory");
                }
            },
        });

        commands.push(Command {
            name: "read",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "run",
            main: box |args: &Vec<String>| {
                if let Some(path) = args.get(1) {

                    let mut commands = String::new();
                    if let Some(mut file) = File::open(path) {
                        file.read_to_string(&mut commands);
                    }

                    for command in commands.split('\n') {
                        exec!(command);
                    }
                }
            },
        });

        commands.push(Command {
            name: "sleep",
            main: box |args: &Vec<String>| {
                let secs = {
                    match args.get(1) {
                        Some(arg) => arg.to_num() as i64,
                        None => 0,
                    }
                };

                let nanos = {
                    match args.get(2) {
                        Some(arg) => arg.to_num() as i32,
                        None => 0,
                    }
                };

                println!("Sleep: {} {}", secs, nanos);
                let remaining = Duration::new(secs, nanos).sleep();
                println!("Remaining: {} {}", remaining.secs, remaining.nanos);
            },
        });

        commands.push(Command {
            name: "send",
            main: box |args: &Vec<String>| {
                if args.len() < 3 {
                    println!("Error: incorrect arguments");
                    println!("Usage: send [url] [data]");
                    return;
                }

                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    println!("URL: {:?}", file.path());

                    let string: String = args.iter()
                        .skip(2)
                        .fold(String::new(), |s, arg| s + " " + arg)
                        + "\r\n\r\n";

                    match file.write(string.trim_left().as_bytes()) {
                        Some(size) => println!("Wrote {} bytes", size),
                        None => println!("Failed to write"),
                    }

                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        // Simple command to create a file, in the current directory
        // The file has got the name given as the first argument of the command
        // If the command have no arguments, the command don't create the file
        commands.push(Command {
            name: "touch",
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(file_name) => if File::create(file_name).is_none() {
                        println!("Failed to create: {}", file_name);
                    },
                    None => println!("No name provided")
                }
            }
        });

        commands.push(Command {
            name: "url_hex",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut vec: Vec<u8> = Vec::new();
                    match file.read_to_end(&mut vec) {
                        Some(_) => {
                            let mut line = "HEX:".to_string();
                            for byte in vec.iter() {
                                line = line + " " + &format!("{:X}", *byte);
                            }
                            println!("{}", line);
                        }
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "wget",
            main: box |args: &Vec<String>| {
                if let Some(host) = args.get(1) {
                    if let Some(req) = args.get(2) {
                        if let Some(mut con) = File::open(&("tcp://".to_string() + host)) {
                            con.write(("GET ".to_string() + req + " HTTP/1.1").as_bytes());

                            let mut res = Vec::new();
                            con.read_to_end(&mut res);

                            if let Some(mut file) = File::open(&req) {
                                file.write(&res);
                            }
                        }
                    } else {
                        println!("No request given");
                    }
                } else {
                    println!("No url given");
                }
            },
        });

        let command_list = commands.iter().fold(String::new(), |l , c| l + " " + c.name);

        commands.push(Command {
            name: "help",
            main: box move |_: &Vec<String>| {
                println!("Commands:{}", command_list);
            },
         });

        commands
    }
}

/// A (env) variable
pub struct Variable {
    pub name: String,
    pub value: String,
}

pub struct Mode {
    value: bool,
}

/// An application
pub struct Application<'a> {
    commands: Vec<Command<'a>>,
    variables: Vec<Variable>,
    modes: Vec<Mode>,
}

impl<'a> Application<'a> {
    /// Create a new empty application
    pub fn new() -> Self {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new(),
        };
    }

    fn on_command(&mut self, command_string: &str) {
        //Comment
        if command_string.starts_with('#') {
            return;
        }

        //Show variables
        if command_string == "$" {
            for variable in self.variables.iter() {
                println!("{}={}", variable.name, variable.value);
            }
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(' ') {
            if !arg.is_empty() {
                if arg.starts_with('$') {
                    let name = arg[1 .. arg.len()].to_string();
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                } else {
                    args.push(arg.to_string());
                }
            }
        }

        //Execute commands
        if let Some(cmd) = args.get(0) {
            if cmd == "if" {
                let mut value = false;

                if let Some(left) = args.get(1) {
                    if let Some(cmp) = args.get(2) {
                        if let Some(right) = args.get(3) {
                            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");
                }

                self.modes.insert(0, Mode { value: value });
                return;
            }

            if cmd == "else" {
                let mut syntax_error = false;
                match self.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");
                }
                return;
            }

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

            for mode in self.modes.iter() {
                if !mode.value {
                    return;
                }
            }

            if cmd == "read" {
                for i in 1..args.len() {
                    if let Some(arg_original) = args.get(i) {
                        let arg = arg_original.trim();
                        print!("{}=", arg);
                        if let Some(value_original) = readln!() {
                            let value = value_original.trim();
                            self.set_var(arg, value);
                        }
                    }
                }
            }

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

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

                self.set_var(name, &value);
                return;
            }

            //Commands
            for command in self.commands.iter() {
                if &command.name == cmd {
                    (*command.main)(&args);
                    return;
                }
            }

            println!("Unknown command: '{}'", cmd);
        }
    }

    pub fn set_var(&mut self, name: &str, value: &str){
        if name.is_empty() {
            return;
        }

        if value.is_empty() {
            let mut remove = -1;
            for i in 0..self.variables.len() {
                match self.variables.get(i) {
                    Some(variable) => if variable.name == name {
                        remove = i as isize;
                        break;
                    },
                    None => break,
                }
            }

            if remove >= 0 {
                self.variables.remove(remove as usize);
            }
        } else {
            for variable in self.variables.iter_mut() {
                if variable.name == name {
                    variable.value = value.to_string();
                    return;
                }
            }

            self.variables.push(Variable {
                name: name.to_string(),
                value: value.to_string(),
            });
        }
    }

    /// Run the application
    pub fn main(&mut self) {
        println!("Type help for a command list");
        if let Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# {}", command);
            self.on_command(&command);
        }

        loop {
            for mode in self.modes.iter().rev() {
                if mode.value {
                    print!("+ ");
                } else {
                    print!("- ");
                }
            }
            print!("# ");
            if let Some(command_original) = readln!() {
                let command = command_original.trim();
                if command == "exit" {
                    println!("Exit temporarily blocked (due to using terminal as init)")
                    //break;
                } else if !command.is_empty() {
                    self.on_command(&command);
                }
            } else {
                println!("Failed to read from stdin");
            }
        }
    }
}

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<commit_msg>Add simple method to get the current directory, from the terminal<commit_after>use redox::ops::DerefMut;
use redox::string::*;
use redox::vec::Vec;
use redox::boxed::Box;
use redox::fs::*;
use redox::io::*;
use redox::env::*;
use redox::time::Duration;
use redox::to_num::*;

/* Magic Macros { */
static mut application: *mut Application<'static> = 0 as *mut Application;

/// Execute a command
macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd.to_string());
        }
    })
}
/* } Magic Macros */

/// A command
pub struct Command<'a> {
    pub name: &'a str,
    pub main: Box<Fn(&Vec<String>)>,
}

impl<'a> Command<'a> {
    /// Return the vector of the commands
    // TODO: Use a more efficient collection instead
    pub fn vec() -> Vec<Self> {
        let mut commands: Vec<Self> = Vec::new();

        commands.push(Command {
            name: "cat",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read: {}", path),
                    }
                } else {
                    println!("Failed to open file: {}", path);
                }
            },
        });

        commands.push(Command {
            name: "cd",
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(path) => {
                        if !change_cwd(&path) {
                            println!("Bad path: {}", path);
                        }
                    }
                    None => println!("No path given")
                }
            },
        });

        commands.push(Command {
            name: "echo",
            main: box |args: &Vec<String>| {
                let echo = args.iter()
                    .skip(1)
                    .fold(String::new(), |string, arg| string + " " + arg);
                println!("{}", echo.trim());
            },
        });

        commands.push(Command {
            name: "else",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "exec",
            main: box |args: &Vec<String>| {
                if let Some(arg) = args.get(1) {
                    File::exec(arg);
                }
            },
        });

        commands.push(Command {
            name: "exit",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "fi",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "if",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "ls",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(dir) = read_dir(&path) {
                    for entry in dir {
                        println!("{}", entry.path());
                    }
                } else {
                    println!("Failed to open directory: {}", path);
                }
            }
        });

        commands.push(Command {
            name: "pwd",
            main: box |_: &Vec<String>| {
                if let Some(file) = File::open("") {
                    if let Some(path) = file.path() {
                        println!("{}", path);
                    } else {
                        println!("Could not get the path");
                    }
                } else {
                    println!("Could not open the working directory");
                }
            },
        });

        commands.push(Command {
            name: "read",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "run",
            main: box |args: &Vec<String>| {
                if let Some(path) = args.get(1) {

                    let mut commands = String::new();
                    if let Some(mut file) = File::open(path) {
                        file.read_to_string(&mut commands);
                    }

                    for command in commands.split('\n') {
                        exec!(command);
                    }
                }
            },
        });

        commands.push(Command {
            name: "sleep",
            main: box |args: &Vec<String>| {
                let secs = {
                    match args.get(1) {
                        Some(arg) => arg.to_num() as i64,
                        None => 0,
                    }
                };

                let nanos = {
                    match args.get(2) {
                        Some(arg) => arg.to_num() as i32,
                        None => 0,
                    }
                };

                println!("Sleep: {} {}", secs, nanos);
                let remaining = Duration::new(secs, nanos).sleep();
                println!("Remaining: {} {}", remaining.secs, remaining.nanos);
            },
        });

        commands.push(Command {
            name: "send",
            main: box |args: &Vec<String>| {
                if args.len() < 3 {
                    println!("Error: incorrect arguments");
                    println!("Usage: send [url] [data]");
                    return;
                }

                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    println!("URL: {:?}", file.path());

                    let string: String = args.iter()
                        .skip(2)
                        .fold(String::new(), |s, arg| s + " " + arg)
                        + "\r\n\r\n";

                    match file.write(string.trim_left().as_bytes()) {
                        Some(size) => println!("Wrote {} bytes", size),
                        None => println!("Failed to write"),
                    }

                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        // Simple command to create a file, in the current directory
        // The file has got the name given as the first argument of the command
        // If the command have no arguments, the command don't create the file
        commands.push(Command {
            name: "touch",
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(file_name) => if File::create(file_name).is_none() {
                        println!("Failed to create: {}", file_name);
                    },
                    None => println!("No name provided")
                }
            }
        });

        commands.push(Command {
            name: "url_hex",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut vec: Vec<u8> = Vec::new();
                    match file.read_to_end(&mut vec) {
                        Some(_) => {
                            let mut line = "HEX:".to_string();
                            for byte in vec.iter() {
                                line = line + " " + &format!("{:X}", *byte);
                            }
                            println!("{}", line);
                        }
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "wget",
            main: box |args: &Vec<String>| {
                if let Some(host) = args.get(1) {
                    if let Some(req) = args.get(2) {
                        if let Some(mut con) = File::open(&("tcp://".to_string() + host)) {
                            con.write(("GET ".to_string() + req + " HTTP/1.1").as_bytes());

                            let mut res = Vec::new();
                            con.read_to_end(&mut res);

                            if let Some(mut file) = File::open(&req) {
                                file.write(&res);
                            }
                        }
                    } else {
                        println!("No request given");
                    }
                } else {
                    println!("No url given");
                }
            },
        });

        let command_list = commands.iter().fold(String::new(), |l , c| l + " " + c.name);

        commands.push(Command {
            name: "help",
            main: box move |_: &Vec<String>| {
                println!("Commands:{}", command_list);
            },
         });

        commands
    }
}

/// A (env) variable
pub struct Variable {
    pub name: String,
    pub value: String,
}

pub struct Mode {
    value: bool,
}

/// An application
pub struct Application<'a> {
    commands: Vec<Command<'a>>,
    variables: Vec<Variable>,
    modes: Vec<Mode>,
}

impl<'a> Application<'a> {
    /// Create a new empty application
    pub fn new() -> Self {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new(),
        };
    }

    fn on_command(&mut self, command_string: &str) {
        //Comment
        if command_string.starts_with('#') {
            return;
        }

        //Show variables
        if command_string == "$" {
            for variable in self.variables.iter() {
                println!("{}={}", variable.name, variable.value);
            }
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(' ') {
            if !arg.is_empty() {
                if arg.starts_with('$') {
                    let name = arg[1 .. arg.len()].to_string();
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                } else {
                    args.push(arg.to_string());
                }
            }
        }

        //Execute commands
        if let Some(cmd) = args.get(0) {
            if cmd == "if" {
                let mut value = false;

                if let Some(left) = args.get(1) {
                    if let Some(cmp) = args.get(2) {
                        if let Some(right) = args.get(3) {
                            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");
                }

                self.modes.insert(0, Mode { value: value });
                return;
            }

            if cmd == "else" {
                let mut syntax_error = false;
                match self.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");
                }
                return;
            }

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

            for mode in self.modes.iter() {
                if !mode.value {
                    return;
                }
            }

            if cmd == "read" {
                for i in 1..args.len() {
                    if let Some(arg_original) = args.get(i) {
                        let arg = arg_original.trim();
                        print!("{}=", arg);
                        if let Some(value_original) = readln!() {
                            let value = value_original.trim();
                            self.set_var(arg, value);
                        }
                    }
                }
            }

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

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

                self.set_var(name, &value);
                return;
            }

            //Commands
            for command in self.commands.iter() {
                if &command.name == cmd {
                    (*command.main)(&args);
                    return;
                }
            }

            println!("Unknown command: '{}'", cmd);
        }
    }

    pub fn set_var(&mut self, name: &str, value: &str){
        if name.is_empty() {
            return;
        }

        if value.is_empty() {
            let mut remove = -1;
            for i in 0..self.variables.len() {
                match self.variables.get(i) {
                    Some(variable) => if variable.name == name {
                        remove = i as isize;
                        break;
                    },
                    None => break,
                }
            }

            if remove >= 0 {
                self.variables.remove(remove as usize);
            }
        } else {
            for variable in self.variables.iter_mut() {
                if variable.name == name {
                    variable.value = value.to_string();
                    return;
                }
            }

            self.variables.push(Variable {
                name: name.to_string(),
                value: value.to_string(),
            });
        }
    }

    pub fn get_current_directory(&mut self) -> String {
        //Print user directory
        if let Some(file) = File::open("") {
            if let Some(path) = file.path() {
                return path
            }
            else {
                return "?".to_string()
            }
        }
        else {
            return "?".to_string()
        }
    }

    /// Run the application
    pub fn main(&mut self) {
        println!("Type help for a command list");
        if let Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# {}", command);
            self.on_command(&command);
        }

        loop {
            for mode in self.modes.iter().rev() {
                if mode.value {
                    print!("+ ");
                } else {
                    print!("- ");
                }
            }
            print!("# ");
            if let Some(command_original) = readln!() {
                let command = command_original.trim();
                if command == "exit" {
                    println!("Exit temporarily blocked (due to using terminal as init)")
                    //break;
                } else if !command.is_empty() {
                    self.on_command(&command);
                }
            } else {
                println!("Failed to read from stdin");
            }
        }
    }
}

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<|endoftext|>


<commit_before>use base64;

// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
// the next four bits are the actual value, and the 6th bit is the
// continuation bit. The continuation bit tells us whether there are more
// digits in this value following this digit.
//
//   Continuation
//   |    Sign
//   |    |
//   V    V
//   101011

const VLQ_BASE_SHIFT: i32 = 5;

// binary: 100000
const VLQ_BASE: i32 = 1 << VLQ_BASE_SHIFT;

// binary: 011111
const VLQ_BASE_MASK: i32 = VLQ_BASE - 1;

// binary: 100000
const VLQ_CONTINUATION_BIT: i32 = VLQ_BASE;

#[test]
fn it_defines_sane_constants() {
  assert!(VLQ_BASE == 0b100000);
  assert!(VLQ_BASE_MASK == 0b011111);
  assert!(VLQ_CONTINUATION_BIT == 0b100000);
}

/**
 * Converts from a two-complement value to a value where the sign bit is
 * placed in the least significant bit.  For example, as decimals:
 *   1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
 *   2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
 */
fn to_vql(value: i32) -> i32 {
  if value < 0 {
    ((-value) << 1) + 1
  } else {
    (value << 1) + 0
  }
}

#[test]
fn it_converts_to_vql() {
  assert!(to_vql(1) == 2);
  assert!(to_vql(-1) == 3);
  assert!(to_vql(2) == 4);
  assert!(to_vql(-2) == 5);
}

/**
 * Converts to a two-complement value from a value where the sign bit is
 * placed in the least significant bit.  For example, as decimals:
 *   2 (10 binary) becomes 1, 3 (11 binary) becomes -1
 *   4 (100 binary) becomes 2, 5 (101 binary) becomes -2
 */
fn from_vql(value: i32) -> i32 {
  let is_neative = (value & 1) == 1;
  let shifted = value >> 1;
  if is_neative {
    -shifted
  } else {
    shifted
  }
}

#[test]
fn it_converts_from_vql() {
  assert!(from_vql(2) == 1);
  assert!(from_vql(3) == -1);
  assert!(from_vql(4) == 2);
  assert!(from_vql(5) == -2);
}

#[test]
fn it_convert_to_vql_and_back() {
  for x in -1000000..1000000 {
    assert!(from_vql(to_vql(x)) == x);
  }
}

/**
 * Returns the base 64 VLQ encoded value.
 */
pub fn encode(value: i32) -> Option<String> {
  let mut encoded: Vec<u8> = Vec::new();
  let mut vlq = to_vql(value);

  loop {
    let mut digit = vlq & VLQ_BASE_MASK;
    vlq = vlq >> VLQ_BASE_SHIFT;
    if vlq > 0 {
      // There are still more digits in this value, so we must make sure the
      // continuation bit is marked.
      digit |= VLQ_CONTINUATION_BIT;
    }

    encoded.push(match base64::encode(digit) {
      Some(x) => x,
      None => return None
    });

    if vlq <= 0 {
      break;
    }
  };

  match String::from_utf8(encoded) {
    Ok(s) => Some(s),
    Err(_) => None
  }
}

macro_rules! assert_encodes_to(
  ($number:expr, $string:expr) => (
    assert!(encode($number) == Some($string.into()))
  );
);
#[test]
fn it_encodes_some_numbers() {
  assert_encodes_to!(-1000000, "hkh9B");
  assert_encodes_to!(-124133, "ruyH");
  assert_encodes_to!(-12332, "5iY");
  assert_encodes_to!(-2222, "9qE");
  assert_encodes_to!(-1579, "3iD");
  assert_encodes_to!(-65, "jE");
  assert_encodes_to!(-25, "zB");
  assert_encodes_to!(-20, "pB");
  assert_encodes_to!(-11, "X");
  assert_encodes_to!(-9, "T");
  assert_encodes_to!(-2, "F");
  assert_encodes_to!(-1, "D");
  assert_encodes_to!(0, "A");
  assert_encodes_to!(1, "C");
  assert_encodes_to!(7, "O");
  assert_encodes_to!(15, "e");
  assert_encodes_to!(23, "uB");
  assert_encodes_to!(88, "wF");
  assert_encodes_to!(1254, "suC");
  assert_encodes_to!(2493, "67E");
  assert_encodes_to!(23903, "+1uB");
  assert_encodes_to!(129383, "u28H");
  assert_encodes_to!(298322, "k1mS");
  assert_encodes_to!(1000000, "gkh9B");
}

/*
 * Decodes the next base 64 VLQ value from the given string and returns the
 * value and the rest of the string via the out parameter.
 */
pub fn decode(encoded: &str) -> Option<i32> {
  let mut result: i32  = 0;
  let mut shift: i32  = 0;

  for character in encoded.chars() {
    let mut digit = match base64::decode(character as u8) {
      Some(x) => x,
      None => return None
    };
    let continuation = (digit & VLQ_CONTINUATION_BIT) != 0;
    digit &= VLQ_BASE_MASK;
    result = result + (digit << shift);
    shift += VLQ_BASE_SHIFT;
    if !continuation {
      break;
    }
  }

  Some(from_vql(result))
}

macro_rules! assert_decodes_to(
  ($str_slice:expr, $number:expr) => (
    assert!(decode($str_slice) == Some($number))
  );
);
#[test]
fn it_decodes_some_numbers() {
  assert_decodes_to!("hkh9B", -1000000);
  assert_decodes_to!("ruyH", -124133);
  assert_decodes_to!("5iY", -12332);
  assert_decodes_to!("9qE", -2222);
  assert_decodes_to!("3iD", -1579);
  assert_decodes_to!("jE", -65);
  assert_decodes_to!("zB", -25);
  assert_decodes_to!("pB", -20);
  assert_decodes_to!("X", -11);
  assert_decodes_to!("T", -9);
  assert_decodes_to!("F", -2);
  assert_decodes_to!("D", -1);
  assert_decodes_to!("A", 0);
  assert_decodes_to!("C", 1);
  assert_decodes_to!("O", 7);
  assert_decodes_to!("e", 15);
  assert_decodes_to!("uB", 23);
  assert_decodes_to!("wF", 88);
  assert_decodes_to!("suC", 1254);
  assert_decodes_to!("67E", 2493);
  assert_decodes_to!("+1uB", 23903);
  assert_decodes_to!("u28H", 129383);
  assert_decodes_to!("k1mS", 298322);
  assert_decodes_to!("gkh9B", 1000000);
}

#[test]
fn it_encodes_and_decodes_some_numbers() {
  for x in -1000000..1000000 {
    assert!(encode(x).and_then(|x| decode(&x)) == Some(x));
  }
}
<commit_msg>Reduce test sample size of numeric test<commit_after>use base64;

// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
// the next four bits are the actual value, and the 6th bit is the
// continuation bit. The continuation bit tells us whether there are more
// digits in this value following this digit.
//
//   Continuation
//   |    Sign
//   |    |
//   V    V
//   101011

const VLQ_BASE_SHIFT: i32 = 5;

// binary: 100000
const VLQ_BASE: i32 = 1 << VLQ_BASE_SHIFT;

// binary: 011111
const VLQ_BASE_MASK: i32 = VLQ_BASE - 1;

// binary: 100000
const VLQ_CONTINUATION_BIT: i32 = VLQ_BASE;

#[test]
fn it_defines_sane_constants() {
  assert!(VLQ_BASE == 0b100000);
  assert!(VLQ_BASE_MASK == 0b011111);
  assert!(VLQ_CONTINUATION_BIT == 0b100000);
}

/**
 * Converts from a two-complement value to a value where the sign bit is
 * placed in the least significant bit.  For example, as decimals:
 *   1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
 *   2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
 */
fn to_vql(value: i32) -> i32 {
  if value < 0 {
    ((-value) << 1) + 1
  } else {
    (value << 1) + 0
  }
}

#[test]
fn it_converts_to_vql() {
  assert!(to_vql(1) == 2);
  assert!(to_vql(-1) == 3);
  assert!(to_vql(2) == 4);
  assert!(to_vql(-2) == 5);
}

/**
 * Converts to a two-complement value from a value where the sign bit is
 * placed in the least significant bit.  For example, as decimals:
 *   2 (10 binary) becomes 1, 3 (11 binary) becomes -1
 *   4 (100 binary) becomes 2, 5 (101 binary) becomes -2
 */
fn from_vql(value: i32) -> i32 {
  let is_neative = (value & 1) == 1;
  let shifted = value >> 1;
  if is_neative {
    -shifted
  } else {
    shifted
  }
}

#[test]
fn it_converts_from_vql() {
  assert!(from_vql(2) == 1);
  assert!(from_vql(3) == -1);
  assert!(from_vql(4) == 2);
  assert!(from_vql(5) == -2);
}

#[test]
fn it_convert_to_vql_and_back() {
  for x in -1000000..1000000 {
    assert!(from_vql(to_vql(x)) == x);
  }
}

/**
 * Returns the base 64 VLQ encoded value.
 */
pub fn encode(value: i32) -> Option<String> {
  let mut encoded: Vec<u8> = Vec::new();
  let mut vlq = to_vql(value);

  loop {
    let mut digit = vlq & VLQ_BASE_MASK;
    vlq = vlq >> VLQ_BASE_SHIFT;
    if vlq > 0 {
      // There are still more digits in this value, so we must make sure the
      // continuation bit is marked.
      digit |= VLQ_CONTINUATION_BIT;
    }

    encoded.push(match base64::encode(digit) {
      Some(x) => x,
      None => return None
    });

    if vlq <= 0 {
      break;
    }
  };

  match String::from_utf8(encoded) {
    Ok(s) => Some(s),
    Err(_) => None
  }
}

macro_rules! assert_encodes_to(
  ($number:expr, $string:expr) => (
    assert!(encode($number) == Some($string.into()))
  );
);
#[test]
fn it_encodes_some_numbers() {
  assert_encodes_to!(-1000000, "hkh9B");
  assert_encodes_to!(-124133, "ruyH");
  assert_encodes_to!(-12332, "5iY");
  assert_encodes_to!(-2222, "9qE");
  assert_encodes_to!(-1579, "3iD");
  assert_encodes_to!(-65, "jE");
  assert_encodes_to!(-25, "zB");
  assert_encodes_to!(-20, "pB");
  assert_encodes_to!(-11, "X");
  assert_encodes_to!(-9, "T");
  assert_encodes_to!(-2, "F");
  assert_encodes_to!(-1, "D");
  assert_encodes_to!(0, "A");
  assert_encodes_to!(1, "C");
  assert_encodes_to!(7, "O");
  assert_encodes_to!(15, "e");
  assert_encodes_to!(23, "uB");
  assert_encodes_to!(88, "wF");
  assert_encodes_to!(1254, "suC");
  assert_encodes_to!(2493, "67E");
  assert_encodes_to!(23903, "+1uB");
  assert_encodes_to!(129383, "u28H");
  assert_encodes_to!(298322, "k1mS");
  assert_encodes_to!(1000000, "gkh9B");
}

/*
 * Decodes the next base 64 VLQ value from the given string and returns the
 * value and the rest of the string via the out parameter.
 */
pub fn decode(encoded: &str) -> Option<i32> {
  let mut result: i32  = 0;
  let mut shift: i32  = 0;

  for character in encoded.chars() {
    let mut digit = match base64::decode(character as u8) {
      Some(x) => x,
      None => return None
    };
    let continuation = (digit & VLQ_CONTINUATION_BIT) != 0;
    digit &= VLQ_BASE_MASK;
    result = result + (digit << shift);
    shift += VLQ_BASE_SHIFT;
    if !continuation {
      break;
    }
  }

  Some(from_vql(result))
}

macro_rules! assert_decodes_to(
  ($str_slice:expr, $number:expr) => (
    assert!(decode($str_slice) == Some($number))
  );
);
#[test]
fn it_decodes_some_numbers() {
  assert_decodes_to!("hkh9B", -1000000);
  assert_decodes_to!("ruyH", -124133);
  assert_decodes_to!("5iY", -12332);
  assert_decodes_to!("9qE", -2222);
  assert_decodes_to!("3iD", -1579);
  assert_decodes_to!("jE", -65);
  assert_decodes_to!("zB", -25);
  assert_decodes_to!("pB", -20);
  assert_decodes_to!("X", -11);
  assert_decodes_to!("T", -9);
  assert_decodes_to!("F", -2);
  assert_decodes_to!("D", -1);
  assert_decodes_to!("A", 0);
  assert_decodes_to!("C", 1);
  assert_decodes_to!("O", 7);
  assert_decodes_to!("e", 15);
  assert_decodes_to!("uB", 23);
  assert_decodes_to!("wF", 88);
  assert_decodes_to!("suC", 1254);
  assert_decodes_to!("67E", 2493);
  assert_decodes_to!("+1uB", 23903);
  assert_decodes_to!("u28H", 129383);
  assert_decodes_to!("k1mS", 298322);
  assert_decodes_to!("gkh9B", 1000000);
}

#[test]
fn it_encodes_and_decodes_some_numbers() {
  for x in -100000..100000 {
    assert!(encode(x).and_then(|x| decode(&x)) == Some(x));
  }
}
<|endoftext|>


<commit_before>//! A buffer is a memory location accessible to the video card.
//!
//! The purpose of buffers is to serve as a space where the GPU can read from or write data to.
//! It can contain a list of vertices, indices, uniform data, etc.
//!
//! # Buffers management in glium
//!
//! There are three levels of abstraction in glium:
//!
//!  - An `Alloc` corresponds to an OpenGL buffer object and is unsafe to use.
//!    This type is not public.
//!  - A `Buffer` wraps around an `Alloc` and provides safety by handling the data type and fences.
//!  - The `VertexBuffer`, `IndexBuffer`, `UniformBuffer`, `PixelBuffer`, etc. types are
//!    abstractions over a `Buffer` indicating their specific purpose. They implement `Deref`
//!    for the `Buffer`. These types are in the `vertex`, `index`, etc. modules.
//!
//! # Unsized types
//!
//! In order to put some data in a buffer, it must implement the `Content` trait. This trait is
//! automatically implemented on all `Sized` types and on slices (like `[u8]`). This means that
//! you can create a `Buffer<Foo>` (if `Foo` is sized) or a `Buffer<[u8]>` for example without
//! worrying about it.
//!
//! However unsized structs don't automatically implement this trait and you must call the
//! `implement_buffer_content!` macro on them. You must then use the `empty_unsized` constructor.
//!
//! ```no_run
//! # #[macro_use] extern crate glium; fn main() {
//! # use std::mem;
//! # use glium::buffer::{BufferType, BufferMode};
//! # let display: glium::Display = unsafe { mem::uninitialized() };
//! struct Data {
//!     data: [f32],        // `[f32]` is unsized, therefore `Data` is unsized too
//! }
//!
//! implement_buffer_content!(Data);    // without this, you can't put `Data` in a glium buffer
//!
//! // creates a buffer of 64 bytes, which thus holds 8 f32s
//! let mut buffer = glium::buffer::Buffer::<Data>::empty_unsized(&display, BufferType::UniformBuffer,
//!                                                               64, BufferMode::Default).unwrap();
//!
//! // you can then write to it like you normally would
//! buffer.map().data[4] = 2.1;
//! # }
//! ```
//!
pub use self::view::{Buffer, BufferAny, BufferMutSlice};
pub use self::view::{BufferSlice, BufferAnySlice};
pub use self::alloc::{Mapping, WriteMapping, ReadMapping, ReadError, CopyError};
pub use self::alloc::{is_buffer_read_supported};
pub use self::fences::Inserter;

/// DEPRECATED. Only here for backward compatibility.
pub use self::view::Buffer as BufferView;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferSlice as BufferViewSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferMutSlice as BufferViewMutSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAny as BufferViewAny;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAnySlice as BufferViewAnySlice;

use gl;
use std::error::Error;
use std::fmt;
use std::mem;
use std::slice;

mod alloc;
mod fences;
mod view;

/// Trait for types of data that can be put inside buffers.
pub unsafe trait Content {
    /// A type that holds a sized version of the content.
    type Owned;

    /// Prepares an output buffer, then turns this buffer into an `Owned`.
    fn read<F, E>(size: usize, F) -> Result<Self::Owned, E>
                  where F: FnOnce(&mut Self) -> Result<(), E>;

    /// Returns the size of each element.
    fn get_elements_size() -> usize;

    /// Produces a pointer to the data.
    fn to_void_ptr(&self) -> *const ();

    /// Builds a pointer to this type from a raw pointer.
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut Self>;

    /// Returns true if the size is suitable to store a type like this.
    fn is_size_suitable(usize) -> bool;
}

unsafe impl<T> Content for T where T: Copy {
    type Owned = T;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<T, E> where F: FnOnce(&mut T) -> Result<(), E> {
        assert!(size == mem::size_of::<T>());
        let mut value = unsafe { mem::uninitialized() };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        self as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut T> {
        if size != mem::size_of::<T>() {
            return None;
        }

        Some(ptr as *mut T)
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size == mem::size_of::<T>()
    }
}

unsafe impl<T> Content for [T] where T: Copy {
    type Owned = Vec<T>;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<Vec<T>, E>
                  where F: FnOnce(&mut [T]) -> Result<(), E>
    {
        assert!(size % mem::size_of::<T>() == 0);
        let len = size / mem::size_of::<T>();
        let mut value = Vec::with_capacity(len);
        unsafe { value.set_len(len) };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        &self[0] as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut [T]> {
        if size % mem::size_of::<T>() != 0 {
            return None;
        }

        let ptr = ptr as *mut T;
        let size = size / mem::size_of::<T>();
        Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size % mem::size_of::<T>() == 0
    }
}

/// Error that can happen when creating a buffer.
#[derive(Debug, Copy, Clone)]
pub enum BufferCreationError {
    /// Not enough memory to create the buffer.
    OutOfMemory,

    /// This type of buffer is not supported.
    BufferTypeNotSupported,
}

impl fmt::Display for BufferCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for BufferCreationError {
    fn description(&self) -> &str {
        match self {
            &BufferCreationError::OutOfMemory => "Not enough memory to create the buffer",
            &BufferCreationError::BufferTypeNotSupported => "This type of buffer is not supported",
        }
    }
}

/// How the buffer is created.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferMode {
    /// This is the default mode suitable for any usage. Will never be slow, will never be fast
    /// either.
    ///
    /// Other modes should always be preferred, but you can use this one if you don't know what
    /// will happen to the buffer.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` flag.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Default,

    /// The mode to use when you modify a buffer multiple times per frame. Simiar to `Default` in
    /// that it is suitable for most usages.
    ///
    /// Use this if you do a quick succession of modify the buffer, draw, modify, draw, etc. This
    /// is something that you shouldn't do by the way.
    ///
    /// With this mode, the OpenGL driver automatically manages the buffer for us. It will try to
    /// find the most appropriate storage depending on how we use it. It is guaranteed to never be
    /// too slow, but it won't be too fast either.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` and
    /// `GL_CLIENT_STORAGE_BIT` flags.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Dynamic,

    /// Optimized for when you modify a buffer exactly once per frame. You can modify it more than
    /// once per frame, but if you modify it too often things will slow down.
    ///
    /// With this mode, glium automatically handles synchronization to prevent the buffer from
    /// being access by both the GPU and the CPU simultaneously. If you try to modify the buffer,
    /// the execution will block until the GPU has finished using it. For this reason, a quick
    /// succession of modifying and drawing using the same buffer will be very slow.
    ///
    /// When using persistent mapping, it is recommended to use triple buffering. This is done by
    /// creating a buffer that has three times the capacity that it would normally have. You modify
    /// and draw the first third, then modify and draw the second third, then the last part, then
    /// go back to the first third, etc.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with `GL_MAP_PERSISTENT_BIT`. Sync fences are automatically
    /// managed by glium.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Persistent,

    /// Optimized when you will never touch the content of the buffer.
    ///
    /// Immutable buffers should be created once and never touched again. Modifying their content
    /// is permitted, but is very slow.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` without any flag. Modifications are done by creating
    /// temporary buffers and making the GPU copy the data from the temporary buffer to the real
    /// one.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Immutable,
}

impl Default for BufferMode {
    fn default() -> BufferMode {
        BufferMode::Default
    }
}

/// Type of a buffer.
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferType {
    ArrayBuffer,
    PixelPackBuffer,
    PixelUnpackBuffer,
    UniformBuffer,
    CopyReadBuffer,
    CopyWriteBuffer,
    AtomicCounterBuffer,
    DispatchIndirectBuffer,
    DrawIndirectBuffer,
    QueryBuffer,
    ShaderStorageBuffer,
    TextureBuffer,
    TransformFeedbackBuffer,
    ElementArrayBuffer,
}

impl BufferType {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            BufferType::ArrayBuffer => gl::ARRAY_BUFFER,
            BufferType::PixelPackBuffer => gl::PIXEL_PACK_BUFFER,
            BufferType::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER,
            BufferType::UniformBuffer => gl::UNIFORM_BUFFER,
            BufferType::CopyReadBuffer => gl::COPY_READ_BUFFER,
            BufferType::CopyWriteBuffer => gl::COPY_WRITE_BUFFER,
            BufferType::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER,
            BufferType::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER,
            BufferType::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER,
            BufferType::QueryBuffer => gl::QUERY_BUFFER,
            BufferType::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER,
            BufferType::TextureBuffer => gl::TEXTURE_BUFFER,
            BufferType::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER,
            BufferType::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER,
        }
    }
}
<commit_msg>Fixed #1445<commit_after>//! A buffer is a memory location accessible to the video card.
//!
//! The purpose of buffers is to serve as a space where the GPU can read from or write data to.
//! It can contain a list of vertices, indices, uniform data, etc.
//!
//! # Buffers management in glium
//!
//! There are three levels of abstraction in glium:
//!
//!  - An `Alloc` corresponds to an OpenGL buffer object and is unsafe to use.
//!    This type is not public.
//!  - A `Buffer` wraps around an `Alloc` and provides safety by handling the data type and fences.
//!  - The `VertexBuffer`, `IndexBuffer`, `UniformBuffer`, `PixelBuffer`, etc. types are
//!    abstractions over a `Buffer` indicating their specific purpose. They implement `Deref`
//!    for the `Buffer`. These types are in the `vertex`, `index`, etc. modules.
//!
//! # Unsized types
//!
//! In order to put some data in a buffer, it must implement the `Content` trait. This trait is
//! automatically implemented on all `Sized` types and on slices (like `[u8]`). This means that
//! you can create a `Buffer<Foo>` (if `Foo` is sized) or a `Buffer<[u8]>` for example without
//! worrying about it.
//!
//! However unsized structs don't automatically implement this trait and you must call the
//! `implement_buffer_content!` macro on them. You must then use the `empty_unsized` constructor.
//!
//! ```no_run
//! # #[macro_use] extern crate glium; fn main() {
//! # use std::mem;
//! # use glium::buffer::{BufferType, BufferMode};
//! # let display: glium::Display = unsafe { mem::uninitialized() };
//! struct Data {
//!     data: [f32],        // `[f32]` is unsized, therefore `Data` is unsized too
//! }
//!
//! implement_buffer_content!(Data);    // without this, you can't put `Data` in a glium buffer
//!
//! // creates a buffer of 64 bytes, which thus holds 8 f32s
//! let mut buffer = glium::buffer::Buffer::<Data>::empty_unsized(&display, BufferType::UniformBuffer,
//!                                                               64, BufferMode::Default).unwrap();
//!
//! // you can then write to it like you normally would
//! buffer.map().data[4] = 2.1;
//! # }
//! ```
//!
pub use self::view::{Buffer, BufferAny, BufferMutSlice};
pub use self::view::{BufferSlice, BufferAnySlice};
pub use self::alloc::{Mapping, WriteMapping, ReadMapping, ReadError, CopyError};
pub use self::alloc::{is_buffer_read_supported};
pub use self::fences::Inserter;

/// DEPRECATED. Only here for backward compatibility.
pub use self::view::Buffer as BufferView;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferSlice as BufferViewSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferMutSlice as BufferViewMutSlice;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAny as BufferViewAny;
/// DEPRECATED. Only here for backward compatibility.
pub use self::view::BufferAnySlice as BufferViewAnySlice;

use gl;
use std::error::Error;
use std::fmt;
use std::mem;
use std::slice;

mod alloc;
mod fences;
mod view;

/// Trait for types of data that can be put inside buffers.
pub unsafe trait Content {
    /// A type that holds a sized version of the content.
    type Owned;

    /// Prepares an output buffer, then turns this buffer into an `Owned`.
    fn read<F, E>(size: usize, F) -> Result<Self::Owned, E>
                  where F: FnOnce(&mut Self) -> Result<(), E>;

    /// Returns the size of each element.
    fn get_elements_size() -> usize;

    /// Produces a pointer to the data.
    fn to_void_ptr(&self) -> *const ();

    /// Builds a pointer to this type from a raw pointer.
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut Self>;

    /// Returns true if the size is suitable to store a type like this.
    fn is_size_suitable(usize) -> bool;
}

unsafe impl<T> Content for T where T: Copy {
    type Owned = T;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<T, E> where F: FnOnce(&mut T) -> Result<(), E> {
        assert!(size == mem::size_of::<T>());
        let mut value = unsafe { mem::uninitialized() };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        self as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut T> {
        if size != mem::size_of::<T>() {
            return None;
        }

        Some(ptr as *mut T)
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size == mem::size_of::<T>()
    }
}

unsafe impl<T> Content for [T] where T: Copy {
    type Owned = Vec<T>;

    #[inline]
    fn read<F, E>(size: usize, f: F) -> Result<Vec<T>, E>
                  where F: FnOnce(&mut [T]) -> Result<(), E>
    {
        assert!(size % mem::size_of::<T>() == 0);
        let len = size / mem::size_of::<T>();
        let mut value = Vec::with_capacity(len);
        unsafe { value.set_len(len) };
        try!(f(&mut value));
        Ok(value)
    }

    #[inline]
    fn get_elements_size() -> usize {
        mem::size_of::<T>()
    }

    #[inline]
    fn to_void_ptr(&self) -> *const () {
        &self[0] as *const T as *const ()
    }

    #[inline]
    fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut [T]> {
        if size % mem::size_of::<T>() != 0 {
            return None;
        }

        let ptr = ptr as *mut T;
        let size = size / mem::size_of::<T>();
        Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
    }

    #[inline]
    fn is_size_suitable(size: usize) -> bool {
        size % mem::size_of::<T>() == 0
    }
}

/// Error that can happen when creating a buffer.
#[derive(Debug, Copy, Clone)]
pub enum BufferCreationError {
    /// Not enough memory to create the buffer.
    OutOfMemory,

    /// This type of buffer is not supported.
    BufferTypeNotSupported,
}

impl fmt::Display for BufferCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for BufferCreationError {
    fn description(&self) -> &str {
        match self {
            &BufferCreationError::OutOfMemory => "Not enough memory to create the buffer",
            &BufferCreationError::BufferTypeNotSupported => "This type of buffer is not supported",
        }
    }
}

/// How the buffer is created.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferMode {
    /// This is the default mode suitable for any usage. Will never be slow, will never be fast
    /// either.
    ///
    /// Other modes should always be preferred, but you can use this one if you don't know what
    /// will happen to the buffer.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` flag.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Default,

    /// The mode to use when you modify a buffer multiple times per frame. Simiar to `Default` in
    /// that it is suitable for most usages.
    ///
    /// Use this if you do a quick succession of modify the buffer, draw, modify, draw, etc. This
    /// is something that you shouldn't do by the way.
    ///
    /// With this mode, the OpenGL driver automatically manages the buffer for us. It will try to
    /// find the most appropriate storage depending on how we use it. It is guaranteed to never be
    /// too slow, but it won't be too fast either.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` and
    /// `GL_CLIENT_STORAGE_BIT` flags.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Dynamic,

    /// Optimized for when you modify a buffer exactly once per frame. You can modify it more than
    /// once per frame, but if you modify it too often things will slow down.
    ///
    /// With this mode, glium automatically handles synchronization to prevent the buffer from
    /// being access by both the GPU and the CPU simultaneously. If you try to modify the buffer,
    /// the execution will block until the GPU has finished using it. For this reason, a quick
    /// succession of modifying and drawing using the same buffer will be very slow.
    ///
    /// When using persistent mapping, it is recommended to use triple buffering. This is done by
    /// creating a buffer that has three times the capacity that it would normally have. You modify
    /// and draw the first third, then modify and draw the second third, then the last part, then
    /// go back to the first third, etc.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` with `GL_MAP_PERSISTENT_BIT`. Sync fences are automatically
    /// managed by glium.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
    ///
    Persistent,

    /// Optimized when you will never touch the content of the buffer.
    ///
    /// Immutable buffers should be created once and never touched again. Modifying their content
    /// is permitted, but is very slow.
    ///
    /// # Implementation
    ///
    /// Tries to use `glBufferStorage` without any flag. Modifications are done by creating
    /// temporary buffers and making the GPU copy the data from the temporary buffer to the real
    /// one.
    ///
    /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
    ///
    Immutable,
}

impl Default for BufferMode {
    fn default() -> BufferMode {
        BufferMode::Default
    }
}

/// Type of a buffer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferType {
    ArrayBuffer,
    PixelPackBuffer,
    PixelUnpackBuffer,
    UniformBuffer,
    CopyReadBuffer,
    CopyWriteBuffer,
    AtomicCounterBuffer,
    DispatchIndirectBuffer,
    DrawIndirectBuffer,
    QueryBuffer,
    ShaderStorageBuffer,
    TextureBuffer,
    TransformFeedbackBuffer,
    ElementArrayBuffer,
}

impl BufferType {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            BufferType::ArrayBuffer => gl::ARRAY_BUFFER,
            BufferType::PixelPackBuffer => gl::PIXEL_PACK_BUFFER,
            BufferType::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER,
            BufferType::UniformBuffer => gl::UNIFORM_BUFFER,
            BufferType::CopyReadBuffer => gl::COPY_READ_BUFFER,
            BufferType::CopyWriteBuffer => gl::COPY_WRITE_BUFFER,
            BufferType::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER,
            BufferType::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER,
            BufferType::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER,
            BufferType::QueryBuffer => gl::QUERY_BUFFER,
            BufferType::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER,
            BufferType::TextureBuffer => gl::TEXTURE_BUFFER,
            BufferType::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER,
            BufferType::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER,
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
#![allow(dead_code)]

use libc::types::os::arch::c95::c_uint;
use libc::types::os::arch::c95::c_char;

pub type Enum_CassErrorSource_ = c_uint;
pub const CASS_ERROR_SOURCE_NONE: c_uint = 0;
pub const CASS_ERROR_SOURCE_LIB: c_uint = 1;
pub const CASS_ERROR_SOURCE_SERVER: c_uint = 2;
pub const CASS_ERROR_SOURCE_SSL: c_uint = 3;
pub const CASS_ERROR_SOURCE_COMPRESSION: c_uint = 4;
pub type CassErrorSource = Enum_CassErrorSource_;

#[derive(Show,Eq,PartialEq,Copy)]
#[repr(C)]
pub enum CassError {
    CASS_OK = 0,
    LIB_BAD_PARAMS = 16777217,
    LIB_NO_STREAMS = 16777218,
    LIB_UNABLE_TO_INIT = 16777219,
    LIB_MESSAGE_ENCODE = 16777220,
    LIB_HOST_RESOLUTION = 16777221,
    LIB_UNEXPECTED_RESPONSE = 16777222,
    LIB_REQUEST_QUEUE_FULL = 16777223,
    LIB_NO_AVAILABLE_IO_THREAD = 16777224,
    LIB_WRITE_ERROR = 16777225,
    LIB_NO_HOSTS_AVAILABLE = 16777226,
    LIB_INDEX_OUT_OF_BOUNDS = 16777227,
    LIB_INVALID_ITEM_COUNT = 16777228,
    LIB_INVALID_VALUE_TYPE = 16777229,
    LIB_REQUEST_TIMED_OUT = 16777230,
    LIB_UNABLE_TO_SET_KEYSPACE = 16777231,
    LIB_CALLBACK_ALREADY_SET = 16777232,
    LIB_INVALID_STATEMENT_TYPE = 16777233,
    LIB_NAME_DOES_NOT_EXIST = 16777234,
    LIB_UNABLE_TO_DETERMINE_PROTOCOL = 16777235,
    LIB_NULL_VALUE = 16777236,
    LIB_NOT_IMPLEMENTED = 16777237,
    LIB_UNABLE_TO_CONNECT = 16777238,
    LIB_UNABLE_TO_CLOSE = 16777239,
    SERVER_SERVER_ERROR = 33554432,
    SERVER_PROTOCOL_ERROR = 33554442,
    SERVER_BAD_CREDENTIALS = 33554688,
    SERVER_UNAVAILABLE = 33558528,
    SERVER_OVERLOADED = 33558529,
    SERVER_IS_BOOTSTRAPPING = 33558530,
    SERVER_TRUNCATE_ERROR = 33558531,
    SERVER_WRITE_TIMEOUT = 33558784,
    SERVER_READ_TIMEOUT = 33559040,
    SERVER_SYNTAX_ERROR = 33562624,
    SERVER_UNAUTHORIZED = 33562880,
    SERVER_INVALID_QUERY = 33563136,
    SERVER_CONFIG_ERROR = 33563392,
    SERVER_ALREADY_EXISTS = 33563648,
    SERVER_UNPREPARED = 33563904,
    SSL_INVALID_CERT = 50331649,
    SSL_INVALID_PRIVATE_KEY = 50331650,
    SSL_NO_PEER_CERT = 50331651,
    SSL_INVALID_PEER_CERT = 50331652,
    SSL_IDENTITY_MISMATCH = 50331653,
    LAST_ENTRY = 50331654
}

extern "C" {
    pub fn cass_error_desc(error: CassError) -> *const c_char;
}
<commit_msg>cleaned up consistency enum<commit_after>#![allow(non_camel_case_types)]
#![allow(dead_code)]

use libc::types::os::arch::c95::c_uint;
use libc::types::os::arch::c95::c_char;

#[derive(Show,Eq,PartialEq,Copy)]
#[repr(C)]
pub enum CassErrorSource {
    NONE = 0is,
    LIB = 1,
    SERVER = 2,
    SSL = 3,
    COMPRESSION = 4
}

#[derive(Show,Eq,PartialEq,Copy)]
#[repr(C)]
pub enum CassError {
    CASS_OK = 0,
    LIB_BAD_PARAMS = 16777217,
    LIB_NO_STREAMS = 16777218,
    LIB_UNABLE_TO_INIT = 16777219,
    LIB_MESSAGE_ENCODE = 16777220,
    LIB_HOST_RESOLUTION = 16777221,
    LIB_UNEXPECTED_RESPONSE = 16777222,
    LIB_REQUEST_QUEUE_FULL = 16777223,
    LIB_NO_AVAILABLE_IO_THREAD = 16777224,
    LIB_WRITE_ERROR = 16777225,
    LIB_NO_HOSTS_AVAILABLE = 16777226,
    LIB_INDEX_OUT_OF_BOUNDS = 16777227,
    LIB_INVALID_ITEM_COUNT = 16777228,
    LIB_INVALID_VALUE_TYPE = 16777229,
    LIB_REQUEST_TIMED_OUT = 16777230,
    LIB_UNABLE_TO_SET_KEYSPACE = 16777231,
    LIB_CALLBACK_ALREADY_SET = 16777232,
    LIB_INVALID_STATEMENT_TYPE = 16777233,
    LIB_NAME_DOES_NOT_EXIST = 16777234,
    LIB_UNABLE_TO_DETERMINE_PROTOCOL = 16777235,
    LIB_NULL_VALUE = 16777236,
    LIB_NOT_IMPLEMENTED = 16777237,
    LIB_UNABLE_TO_CONNECT = 16777238,
    LIB_UNABLE_TO_CLOSE = 16777239,
    SERVER_SERVER_ERROR = 33554432,
    SERVER_PROTOCOL_ERROR = 33554442,
    SERVER_BAD_CREDENTIALS = 33554688,
    SERVER_UNAVAILABLE = 33558528,
    SERVER_OVERLOADED = 33558529,
    SERVER_IS_BOOTSTRAPPING = 33558530,
    SERVER_TRUNCATE_ERROR = 33558531,
    SERVER_WRITE_TIMEOUT = 33558784,
    SERVER_READ_TIMEOUT = 33559040,
    SERVER_SYNTAX_ERROR = 33562624,
    SERVER_UNAUTHORIZED = 33562880,
    SERVER_INVALID_QUERY = 33563136,
    SERVER_CONFIG_ERROR = 33563392,
    SERVER_ALREADY_EXISTS = 33563648,
    SERVER_UNPREPARED = 33563904,
    SSL_INVALID_CERT = 50331649,
    SSL_INVALID_PRIVATE_KEY = 50331650,
    SSL_NO_PEER_CERT = 50331651,
    SSL_INVALID_PEER_CERT = 50331652,
    SSL_IDENTITY_MISMATCH = 50331653,
    LAST_ENTRY = 50331654
}

extern "C" {
    pub fn cass_error_desc(error: CassError) -> *const c_char;
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// 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.

use std::{
  env,
  fs::{self, File},
  io::Write,
  path::{Path, PathBuf},
};

use anyhow::{anyhow, Context, Result};

use cargo_metadata::Metadata;
use docopt::Docopt;

use cargo_raze::{
  checks,
  metadata::{MetadataFetcher, RazeMetadata, RazeMetadataFetcher},
  planning::{BuildPlanner, BuildPlannerImpl, PlannedBuild},
  rendering::FileOutputs,
  rendering::{bazel::BazelRenderer, BuildRenderer, RenderDetails},
  settings::RazeSettings,
  settings::{load_settings, GenMode, SettingsMetadataFetcher},
  util::{find_bazel_workspace_root, find_lockfile, PlatformDetails},
};

use serde::Deserialize;
use url::Url;

#[derive(Debug, Deserialize)]
struct Options {
  flag_verbose: Option<bool>,
  flag_quiet: Option<bool>,
  flag_host: Option<String>,
  flag_color: Option<String>,
  flag_target: Option<String>,
  flag_dryrun: Option<bool>,
  flag_cargo_bin_path: Option<String>,
  flag_output: Option<String>,
  flag_manifest_path: Option<String>,
  flag_generate_lockfile: Option<bool>,
}

const USAGE: &str = r#"
Generate BUILD files for your pre-vendored Cargo dependencies.

Usage:
    cargo raze (-h | --help)
    cargo raze [--verbose] [--quiet] [--color=<WHEN>] [--dryrun] [--cargo-bin-path=<PATH>]
               [--manifest-path=<PATH>] [--output=<PATH>] [--generate-lockfile]
    cargo raze (-V | --version)

Options:
    -h, --help                          Print this message
    -V, --version                       Print version info and exit
    -v, --verbose                       Use verbose output
    -q, --quiet                         No output printed to stdout
    --color=<WHEN>                      Coloring: auto, always, never
    -d, --dryrun                        Do not emit any files
    --cargo-bin-path=<PATH>             Path to the cargo binary to be used for loading workspace metadata
    --manifest-path=<PATH>              Path to the Cargo.toml file to generate BUILD files for
    --output=<PATH>                     Path to output the generated into.
    --generate-lockfile                 Force a new `Cargo.raze.lock` file to be generated
"#;

fn main() -> Result<()> {
  // Parse options
  let options = parse_options();

  // Load settings
  let (local_metadata, settings) = load_raze_settings(&options)?;

  // Fetch metadata
  let raze_metadata = fetch_raze_metadata(&options, &settings, &local_metadata)?;

  // Do Planning
  let planned_build = do_planning(&settings, &raze_metadata)?;

  // Render BUILD files
  let (render_details, bazel_file_outputs) =
    render_files(&settings, &raze_metadata, &planned_build, &local_metadata)?;

  // Write BUILD files
  write_files(&bazel_file_outputs, &render_details, &settings, &options)?;

  Ok(())
}

fn parse_options() -> Options {
  let options: Options = Docopt::new(USAGE)
    .map(|d| {
      d.version(Some(
        concat!("cargo-raze ", env!("CARGO_PKG_VERSION")).to_string(),
      ))
    })
    .and_then(|d| d.deserialize())
    .unwrap_or_else(|e| e.exit());

  options
}

fn load_raze_settings(options: &Options) -> Result<(Metadata, RazeSettings)> {
  let metadata = fetch_local_metadata(options)?;

  // Parse settings with that metadata
  let settings = match load_settings(&metadata) {
    Ok(settings) => settings,
    Err(err) => return Err(anyhow!(err.to_string())),
  };

  if options.flag_verbose.unwrap_or(false) {
    println!("Loaded override settings: {:#?}", settings);
  }

  Ok((metadata, settings))
}

fn fetch_local_metadata(options: &Options) -> Result<Metadata> {
  // Gather basic, offline metadata to parse settings from
  let fetcher = if let Some(cargo_bin_path) = &options.flag_cargo_bin_path {
    SettingsMetadataFetcher {
      cargo_bin_path: PathBuf::from(cargo_bin_path),
    }
  } else {
    SettingsMetadataFetcher::default()
  };

  let working_directory = if let Some(manifest_path) = &options.flag_manifest_path {
    let manifest_path = PathBuf::from(manifest_path).canonicalize()?;
    if !manifest_path.is_file() {
      return Err(anyhow!("manifest path `{}` is not a file.", manifest_path.display()));
    }
    // UNWRAP: Unwrap safe due to check above.
    PathBuf::from(manifest_path.parent().unwrap())
  } else {
    env::current_dir()?
  };

  fetcher
    .fetch_metadata(&working_directory, false)
    .with_context(|| {
      format!(
        "Failed to fetch metadata for {}",
        working_directory.display()
      )
    })
}

fn fetch_raze_metadata(
  options: &Options,
  settings: &RazeSettings,
  local_metadata: &Metadata,
) -> Result<RazeMetadata> {
  let metadata_fetcher: RazeMetadataFetcher = match options.flag_cargo_bin_path {
    Some(ref cargo_bin_path) => RazeMetadataFetcher::new(
      cargo_bin_path,
      Url::parse(&settings.registry)?,
      Url::parse(&settings.index_url)?,
    ),
    None => RazeMetadataFetcher::default(),
  };

  let cargo_raze_working_dir =
    find_bazel_workspace_root(&local_metadata.workspace_root).unwrap_or(env::current_dir()?);

  let binary_dep_info = if settings.genmode == GenMode::Remote {
    Some(&settings.binary_deps)
  } else {
    None
  };

  let reused_lockfile = if !options.flag_generate_lockfile.unwrap_or(false) {
    find_lockfile(
      &local_metadata.workspace_root,
      &cargo_raze_working_dir.join(settings.workspace_path.trim_start_matches("/")),
    )
  } else {
    None
  };

  let raze_metadata = metadata_fetcher.fetch_metadata(
    &local_metadata.workspace_root,
    binary_dep_info,
    reused_lockfile,
  )?;

  checks::check_metadata(&raze_metadata, &settings, &cargo_raze_working_dir)?;
  Ok(raze_metadata)
}

fn do_planning(settings: &RazeSettings, metadata: &RazeMetadata) -> Result<PlannedBuild> {
  let platform_details = match &settings.target {
    Some(target) => Some(PlatformDetails::new_using_rustc(target)?),
    None => None,
  };

  BuildPlannerImpl::new(metadata.clone(), settings.clone()).plan_build(platform_details)
}

fn render_files(
  settings: &RazeSettings,
  metadata: &RazeMetadata,
  planned_build: &PlannedBuild,
  local_metadata: &Metadata,
) -> Result<(RenderDetails, Vec<FileOutputs>)> {
  let cargo_raze_working_dir =
    find_bazel_workspace_root(&local_metadata.workspace_root).unwrap_or(env::current_dir()?);

  let mut bazel_renderer = BazelRenderer::new();
  let render_details = RenderDetails {
    cargo_root: metadata.cargo_workspace_root.clone(),
    path_prefix: PathBuf::from(&settings.workspace_path.trim_start_matches("/")),
    package_aliases_dir: settings.package_aliases_dir.clone(),
    vendored_buildfile_name: settings.output_buildfile_suffix.clone(),
    bazel_root: cargo_raze_working_dir,
    rust_rules_workspace_name: settings.rust_rules_workspace_name.clone(),
    experimental_api: settings.experimental_api,
    render_package_aliases: settings.render_package_aliases,
  };
  let bazel_file_outputs = match &settings.genmode {
    GenMode::Vendored => bazel_renderer.render_planned_build(&render_details, &planned_build)?,
    GenMode::Remote => {
      bazel_renderer.render_remote_planned_build(&render_details, &planned_build)?
    }, /* exhaustive, we control the definition */
    // There are no file outputs to produce if `genmode` is Unspecified
    GenMode::Unspecified => Vec::new(),
  };

  Ok((render_details, bazel_file_outputs))
}

fn write_files(
  bazel_file_outputs: &Vec<FileOutputs>,
  render_details: &RenderDetails,
  settings: &RazeSettings,
  options: &Options,
) -> Result<()> {
  if &settings.genmode == &GenMode::Remote {
    let remote_dir = render_details
      .bazel_root
      .join(&render_details.path_prefix)
      .join("remote");
    // Clean out the "remote" directory so users can easily see what build files are relevant
    if remote_dir.exists() {
      let build_glob = format!("{}/BUILD*.bazel", remote_dir.display());
      for entry in glob::glob(&build_glob)? {
        if let Ok(path) = entry {
          fs::remove_file(path)?;
        }
      }
    }
  }

  for output in bazel_file_outputs.iter() {
    if options.flag_dryrun.unwrap_or(false) {
      println!("{}:\n{}", output.path.display(), output.contents);
      continue;
    }
    // Ensure all parent directories exist
    if let Some(parent) = &output.path.parent() {
      fs::create_dir_all(parent)?
    }
    write_to_file(
      &output.path,
      &output.contents,
      options.flag_verbose.unwrap_or(false),
    )?;
  }

  Ok(())
}

/// Writes rendered files to filesystem.
fn write_to_file(path: &Path, contents: &str, verbose: bool) -> Result<()> {
  File::create(&path).and_then(|mut f| f.write_all(contents.as_bytes()))?;
  if verbose {
    println!("Generated {} successfully", path.display());
  }
  Ok(())
}
<commit_msg>Fixed argument parsing when used as a cargo subcommand (#349)<commit_after>// Copyright 2018 Google Inc.
//
// 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.

use std::{
  env,
  fs::{self, File},
  io::Write,
  path::{Path, PathBuf},
};

use anyhow::{anyhow, Context, Result};

use cargo_metadata::Metadata;
use docopt::Docopt;

use cargo_raze::{
  checks,
  metadata::{MetadataFetcher, RazeMetadata, RazeMetadataFetcher},
  planning::{BuildPlanner, BuildPlannerImpl, PlannedBuild},
  rendering::FileOutputs,
  rendering::{bazel::BazelRenderer, BuildRenderer, RenderDetails},
  settings::RazeSettings,
  settings::{load_settings, GenMode, SettingsMetadataFetcher},
  util::{find_bazel_workspace_root, find_lockfile, PlatformDetails},
};

use serde::Deserialize;
use url::Url;

#[derive(Debug, Deserialize)]
struct Options {
  flag_verbose: Option<bool>,
  flag_quiet: Option<bool>,
  flag_host: Option<String>,
  flag_color: Option<String>,
  flag_target: Option<String>,
  flag_dryrun: Option<bool>,
  flag_cargo_bin_path: Option<String>,
  flag_output: Option<String>,
  flag_manifest_path: Option<String>,
  flag_generate_lockfile: Option<bool>,
}

const USAGE: &str = r#"
Generate BUILD files for your pre-vendored Cargo dependencies.

Usage:
    cargo-raze (-h | --help)
    cargo-raze (-V | --version)
    cargo-raze [--verbose] [--quiet] [--color=<WHEN>] [--dryrun] [--cargo-bin-path=<PATH>]
               [--manifest-path=<PATH>] [--output=<PATH>] [--generate-lockfile]

Options:
    -h, --help                          Print this message
    -V, --version                       Print version info and exit
    -v, --verbose                       Use verbose output
    -q, --quiet                         No output printed to stdout
    --color=<WHEN>                      Coloring: auto, always, never
    -d, --dryrun                        Do not emit any files
    --cargo-bin-path=<PATH>             Path to the cargo binary to be used for loading workspace metadata
    --manifest-path=<PATH>              Path to the Cargo.toml file to generate BUILD files for
    --output=<PATH>                     Path to output the generated into.
    --generate-lockfile                 Force a new `Cargo.raze.lock` file to be generated
"#;

fn main() -> Result<()> {
  // Parse options
  let options = parse_options();

  // Load settings
  let (local_metadata, settings) = load_raze_settings(&options)?;

  // Fetch metadata
  let raze_metadata = fetch_raze_metadata(&options, &settings, &local_metadata)?;

  // Do Planning
  let planned_build = do_planning(&settings, &raze_metadata)?;

  // Render BUILD files
  let (render_details, bazel_file_outputs) =
    render_files(&settings, &raze_metadata, &planned_build, &local_metadata)?;

  // Write BUILD files
  write_files(&bazel_file_outputs, &render_details, &settings, &options)?;

  Ok(())
}

fn parse_options() -> Options {
  // When used as a cargo subcommand, the string "raze" will always be
  // passed as the second `argv` entry. We need to remove that to keep
  // the behavior consistent between direct uses and cargo subcommand
  // uses.
  let mut args: Vec<String> = env::args().collect();
  if args.len() > 1 && args[1] == "raze" {
    args.remove(1);
  }

  let options: Options = Docopt::new(USAGE)
    .map(|d| {
      d.version(Some(
        concat!("cargo-raze ", env!("CARGO_PKG_VERSION")).to_string(),
      ))
    })
    .and_then(|d| d.argv(args).parse())
    .and_then(|d| d.deserialize())
    .unwrap_or_else(|e| e.exit());

  options
}

fn load_raze_settings(options: &Options) -> Result<(Metadata, RazeSettings)> {
  let metadata = fetch_local_metadata(options)?;

  // Parse settings with that metadata
  let settings = match load_settings(&metadata) {
    Ok(settings) => settings,
    Err(err) => return Err(anyhow!(err.to_string())),
  };

  if options.flag_verbose.unwrap_or(false) {
    println!("Loaded override settings: {:#?}", settings);
  }

  Ok((metadata, settings))
}

fn fetch_local_metadata(options: &Options) -> Result<Metadata> {
  // Gather basic, offline metadata to parse settings from
  let fetcher = if let Some(cargo_bin_path) = &options.flag_cargo_bin_path {
    SettingsMetadataFetcher {
      cargo_bin_path: PathBuf::from(cargo_bin_path),
    }
  } else {
    SettingsMetadataFetcher::default()
  };

  let working_directory = if let Some(manifest_path) = &options.flag_manifest_path {
    let manifest_path = PathBuf::from(manifest_path).canonicalize()?;
    if !manifest_path.is_file() {
      return Err(anyhow!("manifest path `{}` is not a file.", manifest_path.display()));
    }
    // UNWRAP: Unwrap safe due to check above.
    PathBuf::from(manifest_path.parent().unwrap())
  } else {
    env::current_dir()?
  };

  fetcher
    .fetch_metadata(&working_directory, false)
    .with_context(|| {
      format!(
        "Failed to fetch metadata for {}",
        working_directory.display()
      )
    })
}

fn fetch_raze_metadata(
  options: &Options,
  settings: &RazeSettings,
  local_metadata: &Metadata,
) -> Result<RazeMetadata> {
  let metadata_fetcher: RazeMetadataFetcher = match options.flag_cargo_bin_path {
    Some(ref cargo_bin_path) => RazeMetadataFetcher::new(
      cargo_bin_path,
      Url::parse(&settings.registry)?,
      Url::parse(&settings.index_url)?,
    ),
    None => RazeMetadataFetcher::default(),
  };

  let cargo_raze_working_dir =
    find_bazel_workspace_root(&local_metadata.workspace_root).unwrap_or(env::current_dir()?);

  let binary_dep_info = if settings.genmode == GenMode::Remote {
    Some(&settings.binary_deps)
  } else {
    None
  };

  let reused_lockfile = if !options.flag_generate_lockfile.unwrap_or(false) {
    find_lockfile(
      &local_metadata.workspace_root,
      &cargo_raze_working_dir.join(settings.workspace_path.trim_start_matches("/")),
    )
  } else {
    None
  };

  let raze_metadata = metadata_fetcher.fetch_metadata(
    &local_metadata.workspace_root,
    binary_dep_info,
    reused_lockfile,
  )?;

  checks::check_metadata(&raze_metadata, &settings, &cargo_raze_working_dir)?;
  Ok(raze_metadata)
}

fn do_planning(settings: &RazeSettings, metadata: &RazeMetadata) -> Result<PlannedBuild> {
  let platform_details = match &settings.target {
    Some(target) => Some(PlatformDetails::new_using_rustc(target)?),
    None => None,
  };

  BuildPlannerImpl::new(metadata.clone(), settings.clone()).plan_build(platform_details)
}

fn render_files(
  settings: &RazeSettings,
  metadata: &RazeMetadata,
  planned_build: &PlannedBuild,
  local_metadata: &Metadata,
) -> Result<(RenderDetails, Vec<FileOutputs>)> {
  let cargo_raze_working_dir =
    find_bazel_workspace_root(&local_metadata.workspace_root).unwrap_or(env::current_dir()?);

  let mut bazel_renderer = BazelRenderer::new();
  let render_details = RenderDetails {
    cargo_root: metadata.cargo_workspace_root.clone(),
    path_prefix: PathBuf::from(&settings.workspace_path.trim_start_matches("/")),
    package_aliases_dir: settings.package_aliases_dir.clone(),
    vendored_buildfile_name: settings.output_buildfile_suffix.clone(),
    bazel_root: cargo_raze_working_dir,
    rust_rules_workspace_name: settings.rust_rules_workspace_name.clone(),
    experimental_api: settings.experimental_api,
    render_package_aliases: settings.render_package_aliases,
  };
  let bazel_file_outputs = match &settings.genmode {
    GenMode::Vendored => bazel_renderer.render_planned_build(&render_details, &planned_build)?,
    GenMode::Remote => {
      bazel_renderer.render_remote_planned_build(&render_details, &planned_build)?
    }, /* exhaustive, we control the definition */
    // There are no file outputs to produce if `genmode` is Unspecified
    GenMode::Unspecified => Vec::new(),
  };

  Ok((render_details, bazel_file_outputs))
}

fn write_files(
  bazel_file_outputs: &Vec<FileOutputs>,
  render_details: &RenderDetails,
  settings: &RazeSettings,
  options: &Options,
) -> Result<()> {
  if &settings.genmode == &GenMode::Remote {
    let remote_dir = render_details
      .bazel_root
      .join(&render_details.path_prefix)
      .join("remote");
    // Clean out the "remote" directory so users can easily see what build files are relevant
    if remote_dir.exists() {
      let build_glob = format!("{}/BUILD*.bazel", remote_dir.display());
      for entry in glob::glob(&build_glob)? {
        if let Ok(path) = entry {
          fs::remove_file(path)?;
        }
      }
    }
  }

  for output in bazel_file_outputs.iter() {
    if options.flag_dryrun.unwrap_or(false) {
      println!("{}:\n{}", output.path.display(), output.contents);
      continue;
    }
    // Ensure all parent directories exist
    if let Some(parent) = &output.path.parent() {
      fs::create_dir_all(parent)?
    }
    write_to_file(
      &output.path,
      &output.contents,
      options.flag_verbose.unwrap_or(false),
    )?;
  }

  Ok(())
}

/// Writes rendered files to filesystem.
fn write_to_file(path: &Path, contents: &str, verbose: bool) -> Result<()> {
  File::create(&path).and_then(|mut f| f.write_all(contents.as_bytes()))?;
  if verbose {
    println!("Generated {} successfully", path.display());
  }
  Ok(())
}
<|endoftext|>