<commit_before>#![feature(deque_extras)]
#![feature(box_syntax)]
#![feature(plugin)]
#![plugin(peg_syntax_ext)]

extern crate glob;

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

use self::directory_stack::DirectoryStack;
use self::input_editor::readln;
use self::peg::{parse, Job};
use self::variables::Variables;
use self::history::History;
use self::flow_control::{FlowControl, is_flow_control_command, Statement};
use self::status::{SUCCESS, NO_SUCH_COMMAND, TERMINATED};
use self::function::Function;

pub mod directory_stack;
pub mod to_num;
pub mod input_editor;
pub mod peg;
pub mod variables;
pub mod history;
pub mod flow_control;
pub mod status;
pub mod function;

/// This struct will contain all of the data structures related to this
/// instance of the shell.
pub struct Shell {
    variables: Variables,
    flow_control: FlowControl,
    directory_stack: DirectoryStack,
    history: History,
    functions: HashMap<String, Function>
}

impl Shell {
    /// Panics if DirectoryStack construction fails
    pub fn new() -> Self {
        Shell {
            variables: Variables::new(),
            flow_control: FlowControl::new(),
            directory_stack: DirectoryStack::new().expect(""),
            history: History::new(),
            functions: HashMap::new()
        }
    }

    pub fn print_prompt(&self) {
        self.print_prompt_prefix();
        match self.flow_control.current_statement {
            Statement::For(_, _) => self.print_for_prompt(),
            Statement::Function => self.print_function_prompt(),
            _ => self.print_default_prompt(),
        }
        if let Err(message) = stdout().flush() {
            println!("{}: failed to flush prompt to stdout", message);
        }

    }

    // TODO eventually this thing should be gone
    fn print_prompt_prefix(&self) {
        let prompt_prefix = self.flow_control.modes.iter().rev().fold(String::new(), |acc, mode| {
            acc +
            if mode.value {
                "+ "
            } else {
                "- "
            }
        });
        print!("{}", prompt_prefix);
    }

    fn print_for_prompt(&self) {
        print!("for> ");
    }

    fn print_function_prompt(&self) {
        print!("fn> ");
    }

    fn print_default_prompt(&self) {
        let cwd = env::current_dir().ok().map_or("?".to_string(),
                                                 |ref p| p.to_str().unwrap_or("?").to_string());
        print!("ion:{}# ", cwd);
    }

    fn on_command(&mut self, command_string: &str, commands: &HashMap<&str, Command>) {
        self.history.add(command_string.to_string());

        let mut jobs = parse(command_string);

        // Execute commands
        for job in jobs.drain(..) {
            if self.flow_control.collecting_block {
                // TODO move this logic into "end" command
                if job.command == "end" {
                    self.flow_control.collecting_block = false;
                    let block_jobs: Vec<Job> = self.flow_control
                                                   .current_block
                                                   .jobs
                                                   .drain(..)
                                                   .collect();
                    match self.flow_control.current_statement.clone() {
                        Statement::For(ref var, ref vals) => {
                            let variable = var.clone();
                            let values = vals.clone();
                            for value in values {
                                self.variables.set_var(&variable, &value);
                                for job in block_jobs.iter() {
                                    self.run_job(job, commands);
                                }
                            }
                        },
                        Statement::Function(ref name) => {
                            self.functions.insert(name.clone(), Function { name: name.clone(), jobs: block_jobs.clone() });
                        },
                        _ => {}
                    }
                    self.flow_control.current_statement = Statement::Default;
                } else {
                    self.flow_control.current_block.jobs.push(job);
                }
            } else {
                if self.flow_control.skipping() && !is_flow_control_command(&job.command) {
                    continue;
                }
                self.run_job(&job, commands);
            }
        }
    }

    fn run_job(&mut self, job: &Job, commands: &HashMap<&str, Command>) -> Option<i32> {
        let mut job = self.variables.expand_job(job);
        job.expand_globs();
        let exit_status = if let Some(command) = commands.get(job.command.as_str()) {
            Some((*command.main)(job.args.as_slice(), self))
        } else if self.functions.get(job.command.as_str()).is_some() { // Not really idiomatic but I don't know how to clone the value without borrowing self
            let function = self.functions.get(job.command.as_str()).unwrap().clone();
            let mut return_value = None;
            for function_job in function.jobs.iter() {
                return_value = self.run_job(&function_job, commands)
            }
            return_value
        } else {
            self.run_external_commmand(job)
        };
        if let Some(code) = exit_status {
            self.variables.set_var("?", &code.to_string());
            self.history.previous_status = code;
        }
        exit_status
    }

    /// Returns an exit code if a command was run
    fn run_external_commmand(&mut self, job: Job) -> Option<i32> {
        if job.background {
            thread::spawn(move || {
                let mut command = Shell::build_command(&job);
                command.stdin(process::Stdio::null());
                if let Ok(mut child) = command.spawn() {
                    Shell::wait_and_get_status(&mut child, &job.command);
                }
            });
            None
        } else {
            if let Ok(mut child) = Shell::build_command(&job).spawn() {
                Some(Shell::wait_and_get_status(&mut child, &job.command))
            } else {
                println!("ion: command not found: {}", job.command);
                Some(NO_SUCH_COMMAND)
            }
        }
    }

    fn build_command(job: &Job) -> process::Command {
        let mut command = process::Command::new(&job.command);
        for i in 1..job.args.len() {
            if let Some(arg) = job.args.get(i) {
                command.arg(arg);
            }
        }
        command
    }

    // TODO don't pass in command and do printing outside this function
    fn wait_and_get_status(child: &mut process::Child, command: &str) -> i32 {
        match child.wait() {
            Ok(status) => {
                if let Some(code) = status.code() {
                    code
                } else {
                    println!("{}: child ended by signal", command);
                    TERMINATED
                }
            }
            Err(err) => {
                println!("{}: Failed to wait: {}", command, err);
                100 // TODO what should we return here?
            }
        }
    }

    /// Evaluates the source init file in the user's home directory. If the file does not exist,
    /// the file will be created.
    fn evaluate_init_file(&mut self, commands: &HashMap<&'static str, Command>) {
        let mut source_file = std::env::home_dir().unwrap(); // Obtain home directory
        source_file.push(".ionrc");                          // Location of ion init file

        if let Ok(mut file) = File::open(source_file.clone()) {
            let mut command_list = String::new();
            if let Err(message) = file.read_to_string(&mut command_list) {
                println!("{}: Failed to read {:?}", message, source_file.clone());
            } else {
                self.on_command(&command_list, commands);
            }
        } else {
            if let Err(message) = File::create(source_file) {
                println!("{}", message);
            }
        }
    }

    /// Evaluates the given file and returns 'SUCCESS' if it succeeds.
    fn source_command(&mut self, arguments: &[String]) -> i32 {
        let commands = Command::map();
        match arguments.iter().skip(1).next() {
            Some(argument) => {
                if let Ok(mut file) = File::open(&argument) {
                    let mut command_list = String::new();
                    if let Err(message) = file.read_to_string(&mut command_list) {
                        println!("{}: Failed to read {}", message, argument);
                        return status::FAILURE;
                    } else {
                        self.on_command(&command_list, &commands);
                        return status::SUCCESS;
                    }
                } else {
                    println!("Failed to open {}", argument);
                    return status::FAILURE;
                }
            },
            None => {
                self.evaluate_init_file(&commands);
                return status::SUCCESS;
            },
        }
    }
}

/// 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], &mut Shell| -> i32 {
///         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) -> i32>,
}

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("cd",
                        Command {
                            name: "cd",
                            help: "Change the current directory\n    cd <path>",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.cd(args)
                            },
                        });

        commands.insert("dirs",
                        Command {
                            name: "dirs",
                            help: "Display the current directory stack",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.dirs(args)
                            },
                        });

        commands.insert("exit",
                        Command {
                            name: "exit",
                            help: "To exit the curent session",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                if let Some(status) = args.get(1) {
                                    if let Ok(status) = status.parse::<i32>() {
                                        process::exit(status);
                                    }
                                }
                                process::exit(shell.history.previous_status);
                            },
                        });

        commands.insert("let",
                        Command {
                            name: "let",
                            help: "View, set or unset variables",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.variables.let_(args)
                            },
                        });

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

        commands.insert("pushd",
                        Command {
                            name: "pushd",
                            help: "Push a directory to the stack",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.pushd(args)
                            },
                        });

        commands.insert("popd",
                        Command {
                            name: "popd",
                            help: "Pop a directory from the stack",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.popd(args)
                            },
                        });

        commands.insert("history",
                        Command {
                            name: "history",
                            help: "Display a log of all commands previously executed",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.history.history(args)
                            },
                        });

        commands.insert("if",
                        Command {
                            name: "if",
                            help: "Conditionally execute code",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.if_(args)
                            },
                        });

        commands.insert("else",
                        Command {
                            name: "else",
                            help: "Execute code if a previous condition was false",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.else_(args)
                            },
                        });

        commands.insert("end",
                        Command {
                            name: "end",
                            help: "End a code block",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.end(args)
                            },
                        });

        commands.insert("for",
                        Command {
                            name: "for",
                            help: "Iterate through a list",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.for_(args)
                            },
                        });

        commands.insert("source",
                        Command {
                            name: "source",
                            help: "Evaluate the file following the command or re-initialize the init file",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.source_command(args)

                            },
                        });

        commands.insert("fn",
                        Command {
                            name: "fn",
                            help: "Create a function",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.fn_(args)
                            },
                        });

        let command_helper: HashMap<&'static str, &'static str> = commands.iter()
                                                                          .map(|(k, v)| {
                                                                              (*k, v.help)
                                                                          })
                                                                          .collect();

        commands.insert("help",
                        Command {
                            name: "help",
                            help: "Display helpful information about a given command, or list \
                                   commands if none specified\n    help <command>",
                            main: box move |args: &[String], _: &mut Shell| -> i32 {
                                if let Some(command) = args.get(1) {
                                    if command_helper.contains_key(command.as_str()) {
                                        match command_helper.get(command.as_str()) {
                                            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);
                                    }
                                }
                                SUCCESS
                            },
                        });

        commands
    }
}

fn main() {
    let commands = Command::map();
    let mut shell = Shell::new();
    shell.evaluate_init_file(&commands);

    let mut dash_c = false;
    for arg in env::args().skip(1) {
        if arg == "-c" {
            dash_c = true;
        } else {
            if dash_c {
                shell.on_command(&arg, &commands);
            } else {
                match File::open(&arg) {
                    Ok(mut file) => {
                        let mut command_list = String::new();
                        match file.read_to_string(&mut command_list) {
                            Ok(_) => shell.on_command(&command_list, &commands),
                            Err(err) => println!("ion: failed to read {}: {}", arg, err)
                        }
                    },
                    Err(err) => println!("ion: failed to open {}: {}", arg, err)
                }
            }

            // Exit with the previous command's exit status.
            process::exit(shell.history.previous_status);
        }
    }

    shell.print_prompt();
    while let Some(command) = readln() {
        let command = command.trim();
        if !command.is_empty() {
            shell.on_command(command, &commands);
        }
        shell.print_prompt()
    }

    // Exit with the previous command's exit status.
    process::exit(shell.history.previous_status);
}
<commit_msg>Fix build break by providing underscore in match<commit_after>#![feature(deque_extras)]
#![feature(box_syntax)]
#![feature(plugin)]
#![plugin(peg_syntax_ext)]

extern crate glob;

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

use self::directory_stack::DirectoryStack;
use self::input_editor::readln;
use self::peg::{parse, Job};
use self::variables::Variables;
use self::history::History;
use self::flow_control::{FlowControl, is_flow_control_command, Statement};
use self::status::{SUCCESS, NO_SUCH_COMMAND, TERMINATED};
use self::function::Function;

pub mod directory_stack;
pub mod to_num;
pub mod input_editor;
pub mod peg;
pub mod variables;
pub mod history;
pub mod flow_control;
pub mod status;
pub mod function;

/// This struct will contain all of the data structures related to this
/// instance of the shell.
pub struct Shell {
    variables: Variables,
    flow_control: FlowControl,
    directory_stack: DirectoryStack,
    history: History,
    functions: HashMap<String, Function>
}

impl Shell {
    /// Panics if DirectoryStack construction fails
    pub fn new() -> Self {
        Shell {
            variables: Variables::new(),
            flow_control: FlowControl::new(),
            directory_stack: DirectoryStack::new().expect(""),
            history: History::new(),
            functions: HashMap::new()
        }
    }

    pub fn print_prompt(&self) {
        self.print_prompt_prefix();
        match self.flow_control.current_statement {
            Statement::For(_, _) => self.print_for_prompt(),
            Statement::Function(_) => self.print_function_prompt(),
            _ => self.print_default_prompt(),
        }
        if let Err(message) = stdout().flush() {
            println!("{}: failed to flush prompt to stdout", message);
        }

    }

    // TODO eventually this thing should be gone
    fn print_prompt_prefix(&self) {
        let prompt_prefix = self.flow_control.modes.iter().rev().fold(String::new(), |acc, mode| {
            acc +
            if mode.value {
                "+ "
            } else {
                "- "
            }
        });
        print!("{}", prompt_prefix);
    }

    fn print_for_prompt(&self) {
        print!("for> ");
    }

    fn print_function_prompt(&self) {
        print!("fn> ");
    }

    fn print_default_prompt(&self) {
        let cwd = env::current_dir().ok().map_or("?".to_string(),
                                                 |ref p| p.to_str().unwrap_or("?").to_string());
        print!("ion:{}# ", cwd);
    }

    fn on_command(&mut self, command_string: &str, commands: &HashMap<&str, Command>) {
        self.history.add(command_string.to_string());

        let mut jobs = parse(command_string);

        // Execute commands
        for job in jobs.drain(..) {
            if self.flow_control.collecting_block {
                // TODO move this logic into "end" command
                if job.command == "end" {
                    self.flow_control.collecting_block = false;
                    let block_jobs: Vec<Job> = self.flow_control
                                                   .current_block
                                                   .jobs
                                                   .drain(..)
                                                   .collect();
                    match self.flow_control.current_statement.clone() {
                        Statement::For(ref var, ref vals) => {
                            let variable = var.clone();
                            let values = vals.clone();
                            for value in values {
                                self.variables.set_var(&variable, &value);
                                for job in block_jobs.iter() {
                                    self.run_job(job, commands);
                                }
                            }
                        },
                        Statement::Function(ref name) => {
                            self.functions.insert(name.clone(), Function { name: name.clone(), jobs: block_jobs.clone() });
                        },
                        _ => {}
                    }
                    self.flow_control.current_statement = Statement::Default;
                } else {
                    self.flow_control.current_block.jobs.push(job);
                }
            } else {
                if self.flow_control.skipping() && !is_flow_control_command(&job.command) {
                    continue;
                }
                self.run_job(&job, commands);
            }
        }
    }

    fn run_job(&mut self, job: &Job, commands: &HashMap<&str, Command>) -> Option<i32> {
        let mut job = self.variables.expand_job(job);
        job.expand_globs();
        let exit_status = if let Some(command) = commands.get(job.command.as_str()) {
            Some((*command.main)(job.args.as_slice(), self))
        } else if self.functions.get(job.command.as_str()).is_some() { // Not really idiomatic but I don't know how to clone the value without borrowing self
            let function = self.functions.get(job.command.as_str()).unwrap().clone();
            let mut return_value = None;
            for function_job in function.jobs.iter() {
                return_value = self.run_job(&function_job, commands)
            }
            return_value
        } else {
            self.run_external_commmand(job)
        };
        if let Some(code) = exit_status {
            self.variables.set_var("?", &code.to_string());
            self.history.previous_status = code;
        }
        exit_status
    }

    /// Returns an exit code if a command was run
    fn run_external_commmand(&mut self, job: Job) -> Option<i32> {
        if job.background {
            thread::spawn(move || {
                let mut command = Shell::build_command(&job);
                command.stdin(process::Stdio::null());
                if let Ok(mut child) = command.spawn() {
                    Shell::wait_and_get_status(&mut child, &job.command);
                }
            });
            None
        } else {
            if let Ok(mut child) = Shell::build_command(&job).spawn() {
                Some(Shell::wait_and_get_status(&mut child, &job.command))
            } else {
                println!("ion: command not found: {}", job.command);
                Some(NO_SUCH_COMMAND)
            }
        }
    }

    fn build_command(job: &Job) -> process::Command {
        let mut command = process::Command::new(&job.command);
        for i in 1..job.args.len() {
            if let Some(arg) = job.args.get(i) {
                command.arg(arg);
            }
        }
        command
    }

    // TODO don't pass in command and do printing outside this function
    fn wait_and_get_status(child: &mut process::Child, command: &str) -> i32 {
        match child.wait() {
            Ok(status) => {
                if let Some(code) = status.code() {
                    code
                } else {
                    println!("{}: child ended by signal", command);
                    TERMINATED
                }
            }
            Err(err) => {
                println!("{}: Failed to wait: {}", command, err);
                100 // TODO what should we return here?
            }
        }
    }

    /// Evaluates the source init file in the user's home directory. If the file does not exist,
    /// the file will be created.
    fn evaluate_init_file(&mut self, commands: &HashMap<&'static str, Command>) {
        let mut source_file = std::env::home_dir().unwrap(); // Obtain home directory
        source_file.push(".ionrc");                          // Location of ion init file

        if let Ok(mut file) = File::open(source_file.clone()) {
            let mut command_list = String::new();
            if let Err(message) = file.read_to_string(&mut command_list) {
                println!("{}: Failed to read {:?}", message, source_file.clone());
            } else {
                self.on_command(&command_list, commands);
            }
        } else {
            if let Err(message) = File::create(source_file) {
                println!("{}", message);
            }
        }
    }

    /// Evaluates the given file and returns 'SUCCESS' if it succeeds.
    fn source_command(&mut self, arguments: &[String]) -> i32 {
        let commands = Command::map();
        match arguments.iter().skip(1).next() {
            Some(argument) => {
                if let Ok(mut file) = File::open(&argument) {
                    let mut command_list = String::new();
                    if let Err(message) = file.read_to_string(&mut command_list) {
                        println!("{}: Failed to read {}", message, argument);
                        return status::FAILURE;
                    } else {
                        self.on_command(&command_list, &commands);
                        return status::SUCCESS;
                    }
                } else {
                    println!("Failed to open {}", argument);
                    return status::FAILURE;
                }
            },
            None => {
                self.evaluate_init_file(&commands);
                return status::SUCCESS;
            },
        }
    }
}

/// 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], &mut Shell| -> i32 {
///         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) -> i32>,
}

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("cd",
                        Command {
                            name: "cd",
                            help: "Change the current directory\n    cd <path>",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.cd(args)
                            },
                        });

        commands.insert("dirs",
                        Command {
                            name: "dirs",
                            help: "Display the current directory stack",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.dirs(args)
                            },
                        });

        commands.insert("exit",
                        Command {
                            name: "exit",
                            help: "To exit the curent session",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                if let Some(status) = args.get(1) {
                                    if let Ok(status) = status.parse::<i32>() {
                                        process::exit(status);
                                    }
                                }
                                process::exit(shell.history.previous_status);
                            },
                        });

        commands.insert("let",
                        Command {
                            name: "let",
                            help: "View, set or unset variables",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.variables.let_(args)
                            },
                        });

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

        commands.insert("pushd",
                        Command {
                            name: "pushd",
                            help: "Push a directory to the stack",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.pushd(args)
                            },
                        });

        commands.insert("popd",
                        Command {
                            name: "popd",
                            help: "Pop a directory from the stack",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.directory_stack.popd(args)
                            },
                        });

        commands.insert("history",
                        Command {
                            name: "history",
                            help: "Display a log of all commands previously executed",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.history.history(args)
                            },
                        });

        commands.insert("if",
                        Command {
                            name: "if",
                            help: "Conditionally execute code",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.if_(args)
                            },
                        });

        commands.insert("else",
                        Command {
                            name: "else",
                            help: "Execute code if a previous condition was false",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.else_(args)
                            },
                        });

        commands.insert("end",
                        Command {
                            name: "end",
                            help: "End a code block",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.end(args)
                            },
                        });

        commands.insert("for",
                        Command {
                            name: "for",
                            help: "Iterate through a list",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.for_(args)
                            },
                        });

        commands.insert("source",
                        Command {
                            name: "source",
                            help: "Evaluate the file following the command or re-initialize the init file",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.source_command(args)

                            },
                        });

        commands.insert("fn",
                        Command {
                            name: "fn",
                            help: "Create a function",
                            main: box |args: &[String], shell: &mut Shell| -> i32 {
                                shell.flow_control.fn_(args)
                            },
                        });

        let command_helper: HashMap<&'static str, &'static str> = commands.iter()
                                                                          .map(|(k, v)| {
                                                                              (*k, v.help)
                                                                          })
                                                                          .collect();

        commands.insert("help",
                        Command {
                            name: "help",
                            help: "Display helpful information about a given command, or list \
                                   commands if none specified\n    help <command>",
                            main: box move |args: &[String], _: &mut Shell| -> i32 {
                                if let Some(command) = args.get(1) {
                                    if command_helper.contains_key(command.as_str()) {
                                        match command_helper.get(command.as_str()) {
                                            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);
                                    }
                                }
                                SUCCESS
                            },
                        });

        commands
    }
}

fn main() {
    let commands = Command::map();
    let mut shell = Shell::new();
    shell.evaluate_init_file(&commands);

    let mut dash_c = false;
    for arg in env::args().skip(1) {
        if arg == "-c" {
            dash_c = true;
        } else {
            if dash_c {
                shell.on_command(&arg, &commands);
            } else {
                match File::open(&arg) {
                    Ok(mut file) => {
                        let mut command_list = String::new();
                        match file.read_to_string(&mut command_list) {
                            Ok(_) => shell.on_command(&command_list, &commands),
                            Err(err) => println!("ion: failed to read {}: {}", arg, err)
                        }
                    },
                    Err(err) => println!("ion: failed to open {}: {}", arg, err)
                }
            }

            // Exit with the previous command's exit status.
            process::exit(shell.history.previous_status);
        }
    }

    shell.print_prompt();
    while let Some(command) = readln() {
        let command = command.trim();
        if !command.is_empty() {
            shell.on_command(command, &commands);
        }
        shell.print_prompt()
    }

    // Exit with the previous command's exit status.
    process::exit(shell.history.previous_status);
}
<|endoftext|>


<commit_before><commit_msg>Turn off benchmark<commit_after><|endoftext|>


<commit_before><commit_msg>Adding back dynamic building of site navigation links<commit_after><|endoftext|>


<commit_before><commit_msg>add main module<commit_after>
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(unused_variables)]
#![allow(non_upper_case_globals)]

mod util {
	pub mod vector;
	pub mod sdl {
		pub mod displaylist;
	}
}

mod ttn {
	pub mod shape;
}

fn main() {
	//call boot...
}<|endoftext|>


<commit_before>use std::any::Any;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_USIZE_INIT, Ordering};
use std::thread;

use Future;
use token::Tokens;
use slot::Slot;
use executor::{DEFAULT, Executor};

/// A structure representing one "task", or thread of execution throughout the
/// lifetime of a set of futures.
///
/// It's intended that futures are composed together to form a large "task" of
/// futures which is driven as a whole throughout its lifetime. This task is
/// persistent for the entire lifetime of the future until its completion,
/// carrying any local data and such.
///
/// Currently tasks serve two primary purposes:
///
/// * They're used to drive futures to completion, e.g. executors (more to be
///   changed here soon).
/// * They store task local data. That is, any task can contain any number of
///   pieces of arbitrary data which can be accessed at a later date. The data
///   is owned and carried in the task itself, and `TaskData` handles are used
///   to access the internals.
///
/// This structure is likely to expand more customizable functionality over
/// time! That is, it's not quite done yet...
pub struct Task {
    id: usize,
    ready: usize,
    list: Box<Any + Send>,
    handle: TaskHandle,
    tokens: Tokens,
}

/// A scoped version of a task, returned by the `Task::scoped` method.
pub struct ScopedTask<'a> {
    task: &'a mut Task,
    reset: bool,
}

/// A handle to a task that can be sent to other threads.
///
/// Created by the `Task::handle` method.
#[derive(Clone)]
pub struct TaskHandle {
    inner: Arc<Inner>,
}

struct Inner {
    slot: Slot<(Task, Box<Future<Item=(), Error=()>>)>,
    tokens: Tokens,
    registered: AtomicBool,
}

/// A reference to a piece of data that's stored inside of a `Task`.
///
/// This can be used with the `Task::get` and `Task::get_mut` methods to access
/// data inside of tasks.
pub struct TaskData {
    id: usize,
    ptr: *mut A,
}

unsafe impl Send for TaskData {}
unsafe impl Sync for TaskData {}

impl Task {
    /// Creates a new task ready to drive a future.
    ///
    /// The returned task has no internal data stored in it and considers all
    /// tokens "ready for polling" until informed otherwise.
    pub fn new() -> Task {
        static NEXT: AtomicUsize = ATOMIC_USIZE_INIT;

        // TODO: Handle this overflow not by panicking, but for now also ensure
        //       that this aborts the process.
        let id = NEXT.fetch_add(1, Ordering::SeqCst);
        if id >= usize::max_value() - 50_000 {
            panic!("overflow in number of tasks created");
        }

        Task {
            id: id,
            list: Box::new(()),
            tokens: Tokens::all(),
            ready: 0,
            handle: TaskHandle {
                inner: Arc::new(Inner {
                    slot: Slot::new(None),
                    registered: AtomicBool::new(false),
                    tokens: Tokens::all(),
                }),
            },
        }
    }

    /// Tests whether a token may be ready for polling.
    ///
    /// As events come in interest in particular tokens can be signaled through
    /// the `TaskHandle::token_ready` method. This method can then be used to
    /// see whether a token has arrive yet or not.
    ///
    /// Note that this will never return a false negative, but it can return
    /// false positives. That is, if a token has been passed to `token_ready`,
    /// that exact token will always return `true`. If a token has not been
    /// passed to `token_ready`, though, it may still return `true`. (e.g. this
    /// is a bloom filter).
    // TODO: probably want an opaque type around usize
    // TODO: needs a better name
    pub fn may_contain(&self, token: usize) -> bool {
        self.ready > 0 || self.tokens.may_contain(token)
    }

    /// Inserts a new piece of task-local data into this task, returning a
    /// reference to it.
    ///
    /// Ownership of the data will be transferred to the task, and the data will
    /// be destroyed when the task itself is destroyed. The returned value can
    /// be passed to the `Task::{get, get_mut}` methods to get a reference back
    /// to the original data.
    ///
    /// Note that the returned handle is cloneable and copyable and can be sent
    /// to other futures which will be associated with the same task. All
    /// futures will then have access to this data when passed the reference
    /// back.
    pub fn insert(&mut self, a: A) -> TaskData
        where A: Any + Send + 'static,
    {
        // Right now our list of task-local data is just stored as a linked
        // list, so allocate a new node and insert it into the list.
        struct Node<T: ?Sized> {
            _next: Box<Any + Send>,
            data: T,
        }
        let prev = mem::replace(&mut self.list, Box::new(()));
        let mut next = Box::new(Node { _next: prev, data: a });
        let ret = TaskData { id: self.id, ptr: &mut next.data };
        self.list = next;
        return ret
    }

    /// Get a reference to the task-local data inside this task.
    ///
    /// This method should be passed a handle previously returned by
    /// `Task::insert`. That handle, when passed back into this method, will
    /// retrieve a reference to the original data.
    ///
    /// # Panics
    ///
    /// This method will panic if `data` does not belong to this task. That is,
    /// if another task generated the `data` handle passed in, this method will
    /// panic.
    pub fn get(&self, data: &TaskData) -> &A {
        assert_eq!(data.id, self.id);
        unsafe { &*data.ptr }
    }

    /// Get a mutable reference to the task-local data inside this task.
    ///
    /// This method should be passed a handle previously returned by
    /// `Task::insert`. That handle, when passed back into this method, will
    /// retrieve a reference to the original data.
    ///
    /// # Panics
    ///
    /// This method will panic if `data` does not belong to this task. That is,
    /// if another task generated the `data` handle passed in, this method will
    /// panic.
    pub fn get_mut(&mut self, data: &TaskData) -> &mut A {
        assert_eq!(data.id, self.id);
        unsafe { &mut *data.ptr }
    }

    /// During the `Future::schedule` method, notify to the task that a value is
    /// immediately ready.
    ///
    /// This method, more optimized than `TaskHandle::notify`, will inform the
    /// task that the future which is being scheduled is immediately ready to be
    /// `poll`ed again.
    pub fn notify(&mut self) {
        // TODO: optimize this
        self.handle().notify()
    }

    /// Gets a handle to this task which can be cloned to a piece of
    /// `Send+'static` data.
    ///
    /// This handle returned can be used to notify the task that a future is
    /// ready to get polled again. The returned handle implements the `Clone`
    /// trait and all clones will refer to this same task.
    ///
    /// Note that if data is immediately ready then the `Task::notify` method
    /// should be preferred.
    pub fn handle(&self) -> &TaskHandle {
        &self.handle
    }

    /// Creates a new temporary "scoped task" for setting the ready tokens.
    ///
    /// A scoped task is simply a borrowed version of this task with an
    /// associated destructor that restores the ready set when it goes out of
    /// scope. This returned object can use the `ScopedTask::ready` method to
    /// indicate that all further calls to `Task::may_contain` will return true.
    ///
    /// This can be useful when one call to `poll` may poll multiple futures or
    /// streams, but after one has been resolved the others may all immediately
    /// be ready so they shouldn't use the same readiness token sets as the
    /// previous one.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use futures::Task;
    ///
    /// fn poll(task: &mut Task) {
    ///     task.may_contain(1); // may return true or false
    ///
    ///     {
    ///         let mut task = task.scoped();
    ///
    ///         task.may_contain(1); // returns the same as before
    ///
    ///         task.ready();
    ///         assert!(task.may_contain(1)); // always returns true
    ///     }
    ///
    ///     task.may_contain(1); // returns the same as the first call
    /// }
    /// ```
    // TODO: terrible name
    pub fn scoped(&mut self) -> ScopedTask {
        ScopedTask { task: self, reset: false }
    }

    /// Consumes this task to run a future to completion.
    ///
    /// This function will consume the task provided and the task will be used
    /// to execute the `future` provided until it has been completed. The future
    /// wil be `poll`'d until it is resolved, at which point the `Result<(),
    /// ()>` will be discarded.
    ///
    /// The future will be `poll`ed on the threads that events arrive on. That
    /// is, this method does not attempt to control which thread a future is
    /// polled on.
    ///
    /// # Panics
    ///
    /// Currently, if `poll` panics, then this method will propagate the panic
    /// to the thread that `poll` was called on. This is bad and it will change.
    pub fn run(self, mut future: Box<Future<Item=(), Error=()>>) {
        let mut me = self;
        loop {
            // Note that we need to poll at least once as the wake callback may
            // have received an empty set of tokens, but that's still a valid
            // reason to poll a future.
            assert_eq!(me.ready, 0);
            me.tokens = me.handle.inner.tokens.take();
            let result = catch_unwind(move || {
                (future.poll(&mut me), future, me)
            });
            match result {
                Ok((ref r, _, _)) if r.is_ready() => return,
                Ok((_, f, t)) => {
                    future = f;
                    me = t;
                }
                // TODO: do something smarter
                Err(e) => panic::resume_unwind(e),
            }
            future = match future.tailcall() {
                Some(f) => f,
                None => future,
            };
            if !me.handle.inner.tokens.any() {
                break
            }
        }

        // Ok, we've seen that there are no tokens which show interest in the
        // future. Schedule interest on the future for when something is ready
        // and then relinquish the future and the forget back to the slot, which
        // will then pick it up once a wake callback has fired.
        future.schedule(&mut me);

        let inner = me.handle.inner.clone();
        inner.slot.try_produce((me, future)).ok().unwrap();
    }
}

fn catch_unwind<F, U>(f: F) -> thread::Result
    where F: FnOnce() -> U + Send + 'static,
{
    panic::catch_unwind(panic::AssertUnwindSafe(f))
}

impl TaskHandle {
    /// Returns whether this task handle and another point to the same task.
    ///
    /// In other words, this method returns whether `notify` would end up
    /// notifying the same task. If two task handles need to be notified but
    /// they are equivalent, then only one needs to be actually notified.
    pub fn equivalent(&self, other: &TaskHandle) -> bool {
        &*self.inner as *const _ == &*other.inner as *const _
    }

    /// Inform this handle's associated task that a particular token is ready.
    ///
    /// This information will be communicated to the task in question and
    /// affects the return value of future calls to `Task::may_contain`. This
    /// can be used to optimize calls to `poll` by avoiding a polling operation
    /// if `may_contain` returns false.
    pub fn token_ready(&self, token: usize) {
        self.inner.tokens.insert(token);
    }

    /// Notify the associated task that a future is ready to get polled.
    ///
    /// Futures should use this method to ensure that when a future can make
    /// progress as `Task` is notified that it should continue to `poll` the
    /// future at a later date.
    ///
    /// Currently it's guaranteed that if `notify` is called that `poll` will be
    /// scheduled to get called at some point in the future. A `poll` may
    /// already be running on another thread, but this will ensure that a poll
    /// happens again to receive this notification.
    pub fn notify(&self) {
        // First, see if we can actually register an `on_full` callback. The
        // `Slot` requires that only one registration happens, and this flag
        // guards that.
        if self.inner.registered.swap(true, Ordering::SeqCst) {
            return
        }

        // If we won the race to register a callback, do so now. Once the slot
        // is resolve we allow another registration **before we poll again**.
        // This allows any future which may be somewhat badly behaved to be
        // compatible with this.
        self.inner.slot.on_full(|slot| {
            let (task, future) = slot.try_consume().ok().unwrap();
            task.handle.inner.registered.store(false, Ordering::SeqCst);
            DEFAULT.execute(|| task.run(future))
        });
    }
}

impl<'a> ScopedTask<'a> {
    /// Flag this scoped task as "all events are ready".
    ///
    /// In other words, once this method is called, all future calls to
    /// `may_contain` on the associated `Task` will return `true`.
    pub fn ready(&mut self) -> &mut ScopedTask<'a>{
        if !self.reset {
            self.reset = true;
            self.task.ready += 1;
        }
        self
    }
}

impl<'a> Deref for ScopedTask<'a> {
    type Target = Task;
    fn deref(&self) -> &Task {
        &*self.task
    }
}

impl<'a> DerefMut for ScopedTask<'a> {
    fn deref_mut(&mut self) -> &mut Task {
        &mut *self.task
    }
}

impl<'a> Drop for ScopedTask<'a> {
    fn drop(&mut self) {
        if self.reset {
            self.task.ready -= 1;
        }
    }
}

impl Clone for TaskData {
    fn clone(&self) -> TaskData {
        TaskData {
            id: self.id,
            ptr: self.ptr,
        }
    }
}

impl Copy for TaskData {}
<commit_msg>fixed 2 typos in documention for Task<commit_after>use std::any::Any;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_USIZE_INIT, Ordering};
use std::thread;

use Future;
use token::Tokens;
use slot::Slot;
use executor::{DEFAULT, Executor};

/// A structure representing one "task", or thread of execution throughout the
/// lifetime of a set of futures.
///
/// It's intended that futures are composed together to form a large "task" of
/// futures which is driven as a whole throughout its lifetime. This task is
/// persistent for the entire lifetime of the future until its completion,
/// carrying any local data and such.
///
/// Currently tasks serve two primary purposes:
///
/// * They're used to drive futures to completion, e.g. executors (more to be
///   changed here soon).
/// * They store task local data. That is, any task can contain any number of
///   pieces of arbitrary data which can be accessed at a later date. The data
///   is owned and carried in the task itself, and `TaskData` handles are used
///   to access the internals.
///
/// This structure is likely to expand more customizable functionality over
/// time! That is, it's not quite done yet...
pub struct Task {
    id: usize,
    ready: usize,
    list: Box<Any + Send>,
    handle: TaskHandle,
    tokens: Tokens,
}

/// A scoped version of a task, returned by the `Task::scoped` method.
pub struct ScopedTask<'a> {
    task: &'a mut Task,
    reset: bool,
}

/// A handle to a task that can be sent to other threads.
///
/// Created by the `Task::handle` method.
#[derive(Clone)]
pub struct TaskHandle {
    inner: Arc<Inner>,
}

struct Inner {
    slot: Slot<(Task, Box<Future<Item=(), Error=()>>)>,
    tokens: Tokens,
    registered: AtomicBool,
}

/// A reference to a piece of data that's stored inside of a `Task`.
///
/// This can be used with the `Task::get` and `Task::get_mut` methods to access
/// data inside of tasks.
pub struct TaskData {
    id: usize,
    ptr: *mut A,
}

unsafe impl Send for TaskData {}
unsafe impl Sync for TaskData {}

impl Task {
    /// Creates a new task ready to drive a future.
    ///
    /// The returned task has no internal data stored in it and considers all
    /// tokens "ready for polling" until informed otherwise.
    pub fn new() -> Task {
        static NEXT: AtomicUsize = ATOMIC_USIZE_INIT;

        // TODO: Handle this overflow not by panicking, but for now also ensure
        //       that this aborts the process.
        let id = NEXT.fetch_add(1, Ordering::SeqCst);
        if id >= usize::max_value() - 50_000 {
            panic!("overflow in number of tasks created");
        }

        Task {
            id: id,
            list: Box::new(()),
            tokens: Tokens::all(),
            ready: 0,
            handle: TaskHandle {
                inner: Arc::new(Inner {
                    slot: Slot::new(None),
                    registered: AtomicBool::new(false),
                    tokens: Tokens::all(),
                }),
            },
        }
    }

    /// Tests whether a token may be ready for polling.
    ///
    /// As events come in interest in particular tokens can be signaled through
    /// the `TaskHandle::token_ready` method. This method can then be used to
    /// see whether a token has arrived yet or not.
    ///
    /// Note that this will never return a false negative, but it can return
    /// false positives. That is, if a token has been passed to `token_ready`,
    /// that exact token will always return `true`. If a token has not been
    /// passed to `token_ready`, though, it may still return `true`. (e.g. this
    /// is a bloom filter).
    // TODO: probably want an opaque type around usize
    // TODO: needs a better name
    pub fn may_contain(&self, token: usize) -> bool {
        self.ready > 0 || self.tokens.may_contain(token)
    }

    /// Inserts a new piece of task-local data into this task, returning a
    /// reference to it.
    ///
    /// Ownership of the data will be transferred to the task, and the data will
    /// be destroyed when the task itself is destroyed. The returned value can
    /// be passed to the `Task::{get, get_mut}` methods to get a reference back
    /// to the original data.
    ///
    /// Note that the returned handle is cloneable and copyable and can be sent
    /// to other futures which will be associated with the same task. All
    /// futures will then have access to this data when passed the reference
    /// back.
    pub fn insert(&mut self, a: A) -> TaskData
        where A: Any + Send + 'static,
    {
        // Right now our list of task-local data is just stored as a linked
        // list, so allocate a new node and insert it into the list.
        struct Node<T: ?Sized> {
            _next: Box<Any + Send>,
            data: T,
        }
        let prev = mem::replace(&mut self.list, Box::new(()));
        let mut next = Box::new(Node { _next: prev, data: a });
        let ret = TaskData { id: self.id, ptr: &mut next.data };
        self.list = next;
        return ret
    }

    /// Get a reference to the task-local data inside this task.
    ///
    /// This method should be passed a handle previously returned by
    /// `Task::insert`. That handle, when passed back into this method, will
    /// retrieve a reference to the original data.
    ///
    /// # Panics
    ///
    /// This method will panic if `data` does not belong to this task. That is,
    /// if another task generated the `data` handle passed in, this method will
    /// panic.
    pub fn get(&self, data: &TaskData) -> &A {
        assert_eq!(data.id, self.id);
        unsafe { &*data.ptr }
    }

    /// Get a mutable reference to the task-local data inside this task.
    ///
    /// This method should be passed a handle previously returned by
    /// `Task::insert`. That handle, when passed back into this method, will
    /// retrieve a reference to the original data.
    ///
    /// # Panics
    ///
    /// This method will panic if `data` does not belong to this task. That is,
    /// if another task generated the `data` handle passed in, this method will
    /// panic.
    pub fn get_mut(&mut self, data: &TaskData) -> &mut A {
        assert_eq!(data.id, self.id);
        unsafe { &mut *data.ptr }
    }

    /// During the `Future::schedule` method, notify to the task that a value is
    /// immediately ready.
    ///
    /// This method, more optimized than `TaskHandle::notify`, will inform the
    /// task that the future which is being scheduled is immediately ready to be
    /// `poll`ed again.
    pub fn notify(&mut self) {
        // TODO: optimize this
        self.handle().notify()
    }

    /// Gets a handle to this task which can be cloned to a piece of
    /// `Send+'static` data.
    ///
    /// This handle returned can be used to notify the task that a future is
    /// ready to get polled again. The returned handle implements the `Clone`
    /// trait and all clones will refer to this same task.
    ///
    /// Note that if data is immediately ready then the `Task::notify` method
    /// should be preferred.
    pub fn handle(&self) -> &TaskHandle {
        &self.handle
    }

    /// Creates a new temporary "scoped task" for setting the ready tokens.
    ///
    /// A scoped task is simply a borrowed version of this task with an
    /// associated destructor that restores the ready set when it goes out of
    /// scope. This returned object can use the `ScopedTask::ready` method to
    /// indicate that all further calls to `Task::may_contain` will return true.
    ///
    /// This can be useful when one call to `poll` may poll multiple futures or
    /// streams, but after one has been resolved the others may all immediately
    /// be ready so they shouldn't use the same readiness token sets as the
    /// previous one.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use futures::Task;
    ///
    /// fn poll(task: &mut Task) {
    ///     task.may_contain(1); // may return true or false
    ///
    ///     {
    ///         let mut task = task.scoped();
    ///
    ///         task.may_contain(1); // returns the same as before
    ///
    ///         task.ready();
    ///         assert!(task.may_contain(1)); // always returns true
    ///     }
    ///
    ///     task.may_contain(1); // returns the same as the first call
    /// }
    /// ```
    // TODO: terrible name
    pub fn scoped(&mut self) -> ScopedTask {
        ScopedTask { task: self, reset: false }
    }

    /// Consumes this task to run a future to completion.
    ///
    /// This function will consume the task provided and the task will be used
    /// to execute the `future` provided until it has been completed. The future
    /// wil be `poll`'ed until it is resolved, at which point the `Result<(),
    /// ()>` will be discarded.
    ///
    /// The future will be `poll`ed on the threads that events arrive on. That
    /// is, this method does not attempt to control which thread a future is
    /// polled on.
    ///
    /// # Panics
    ///
    /// Currently, if `poll` panics, then this method will propagate the panic
    /// to the thread that `poll` was called on. This is bad and it will change.
    pub fn run(self, mut future: Box<Future<Item=(), Error=()>>) {
        let mut me = self;
        loop {
            // Note that we need to poll at least once as the wake callback may
            // have received an empty set of tokens, but that's still a valid
            // reason to poll a future.
            assert_eq!(me.ready, 0);
            me.tokens = me.handle.inner.tokens.take();
            let result = catch_unwind(move || {
                (future.poll(&mut me), future, me)
            });
            match result {
                Ok((ref r, _, _)) if r.is_ready() => return,
                Ok((_, f, t)) => {
                    future = f;
                    me = t;
                }
                // TODO: do something smarter
                Err(e) => panic::resume_unwind(e),
            }
            future = match future.tailcall() {
                Some(f) => f,
                None => future,
            };
            if !me.handle.inner.tokens.any() {
                break
            }
        }

        // Ok, we've seen that there are no tokens which show interest in the
        // future. Schedule interest on the future for when something is ready
        // and then relinquish the future and the forget back to the slot, which
        // will then pick it up once a wake callback has fired.
        future.schedule(&mut me);

        let inner = me.handle.inner.clone();
        inner.slot.try_produce((me, future)).ok().unwrap();
    }
}

fn catch_unwind<F, U>(f: F) -> thread::Result
    where F: FnOnce() -> U + Send + 'static,
{
    panic::catch_unwind(panic::AssertUnwindSafe(f))
}

impl TaskHandle {
    /// Returns whether this task handle and another point to the same task.
    ///
    /// In other words, this method returns whether `notify` would end up
    /// notifying the same task. If two task handles need to be notified but
    /// they are equivalent, then only one needs to be actually notified.
    pub fn equivalent(&self, other: &TaskHandle) -> bool {
        &*self.inner as *const _ == &*other.inner as *const _
    }

    /// Inform this handle's associated task that a particular token is ready.
    ///
    /// This information will be communicated to the task in question and
    /// affects the return value of future calls to `Task::may_contain`. This
    /// can be used to optimize calls to `poll` by avoiding a polling operation
    /// if `may_contain` returns false.
    pub fn token_ready(&self, token: usize) {
        self.inner.tokens.insert(token);
    }

    /// Notify the associated task that a future is ready to get polled.
    ///
    /// Futures should use this method to ensure that when a future can make
    /// progress as `Task` is notified that it should continue to `poll` the
    /// future at a later date.
    ///
    /// Currently it's guaranteed that if `notify` is called that `poll` will be
    /// scheduled to get called at some point in the future. A `poll` may
    /// already be running on another thread, but this will ensure that a poll
    /// happens again to receive this notification.
    pub fn notify(&self) {
        // First, see if we can actually register an `on_full` callback. The
        // `Slot` requires that only one registration happens, and this flag
        // guards that.
        if self.inner.registered.swap(true, Ordering::SeqCst) {
            return
        }

        // If we won the race to register a callback, do so now. Once the slot
        // is resolve we allow another registration **before we poll again**.
        // This allows any future which may be somewhat badly behaved to be
        // compatible with this.
        self.inner.slot.on_full(|slot| {
            let (task, future) = slot.try_consume().ok().unwrap();
            task.handle.inner.registered.store(false, Ordering::SeqCst);
            DEFAULT.execute(|| task.run(future))
        });
    }
}

impl<'a> ScopedTask<'a> {
    /// Flag this scoped task as "all events are ready".
    ///
    /// In other words, once this method is called, all future calls to
    /// `may_contain` on the associated `Task` will return `true`.
    pub fn ready(&mut self) -> &mut ScopedTask<'a>{
        if !self.reset {
            self.reset = true;
            self.task.ready += 1;
        }
        self
    }
}

impl<'a> Deref for ScopedTask<'a> {
    type Target = Task;
    fn deref(&self) -> &Task {
        &*self.task
    }
}

impl<'a> DerefMut for ScopedTask<'a> {
    fn deref_mut(&mut self) -> &mut Task {
        &mut *self.task
    }
}

impl<'a> Drop for ScopedTask<'a> {
    fn drop(&mut self) {
        if self.reset {
            self.task.ready -= 1;
        }
    }
}

impl Clone for TaskData {
    fn clone(&self) -> TaskData {
        TaskData {
            id: self.id,
            ptr: self.ptr,
        }
    }
}

impl Copy for TaskData {}
<|endoftext|>


<commit_before><commit_msg>feat(util): Add rexports of mio utilities to facilitate timeouts<commit_after>//! The util module rexports some tools from mio in order to facilitate handling timeouts.

/// Used to identify some timed-out event.
pub use mio::Token;
/// A handle to a specific timeout.
pub use mio::Timeout;
/// A Slab allocator for associating tokens to data.
pub use mio::util::Slab;
<|endoftext|>


<commit_before><commit_msg>draw items on map<commit_after><|endoftext|>


<commit_before><commit_msg>Codeforces 757B<commit_after>use std::io;

fn factorization(num: u32, factor_count: &mut [u32]) {
    let mut num = num;
    let upper_bound = ((num as f64).sqrt().floor()) as u32;

    for i in 2..(upper_bound + 1) {
        if num % i == 0 {
            factor_count[i as usize] += 1;
        }
        while num % i == 0 {
            num /= i;
        }
    }
    if num > 1 {
        factor_count[num as usize] += 1
    }
}

fn main() {
    const MAX_SIZE: usize = 100010;

    let mut factor_count = [0u32; MAX_SIZE];

    let mut input_line = String::new();
    io::stdin().read_line(&mut input_line).unwrap();
    let mut input_line = String::new();
    io::stdin().read_line(&mut input_line).unwrap();

    for strength in input_line.split_whitespace() {
        factorization(strength.parse().unwrap(), &mut factor_count);
    }

    let (_, max_count) = factor_count.
        into_iter().
        enumerate().
        max_by_key(|tuple| tuple.1).
        unwrap();

    println!("{}", std::cmp::max(max_count, &1));
}<|endoftext|>


<commit_before><commit_msg>simple example with sub-tree reading in separate function (#504)<commit_after>// example that separates logic for reading different top-level nodes of xml tree
// Note: for this specific data set using serde feature would simplify
//       this simple data is purely to make it easier to understand the code

use quick_xml::events::{BytesStart, Event};
use quick_xml::name::QName;
use quick_xml::reader::Reader;
use std::borrow::Cow;
use std::collections::HashMap;
use std::convert::Infallible;
use std::str;

const XML: &str = r#"
<?xml version="1.0" encoding="utf-8"?>
  <DefaultSettings Language="es" Greeting="HELLO"/>
  <Localization>
    <Translation Tag="HELLO" Language="ja">
      <Text>こんにちは</Text>
    </Translation>
    <Translation Tag="BYE" Language="ja">
      <Text>さようなら</Text>
    </Translation>
    <Translation Tag="HELLO" Language="es">
      <Text>Hola</Text>
    </Translation>
    <Translation Tag="BYE" Language="es">
      <Text>Adiós</Text>
    </Translation>
  </Localization>
"#;

#[derive(Debug)]
struct Translation {
    tag: String,
    lang: String,
    text: String,
}

impl Translation {
    fn new_from_element(
        reader: &mut Reader<&[u8]>,
        element: BytesStart,
    ) -> Result<Translation, quick_xml::Error> {
        let mut tag = Cow::Borrowed("");
        let mut lang = Cow::Borrowed("");

        for attr_result in element.attributes() {
            let a = attr_result?;
            match a.key.as_ref() {
                b"Language" => lang = a.decode_and_unescape_value(reader)?,
                b"Tag" => tag = a.decode_and_unescape_value(reader)?,
                _ => (),
            }
        }
        let mut element_buf = Vec::new();
        let event = reader.read_event_into(&mut element_buf)?;

        if let Event::Start(ref e) = event {
            let name = e.name();
            if name == QName(b"Text") {
                // note: `read_text` does not support content as CDATA
                let text_content = reader.read_text(e.name())?;
                Ok(Translation {
                    tag: tag.into(),
                    lang: lang.into(),
                    text: text_content.into(),
                })
            } else {
                dbg!("Expected Event::Start for Text, got: {:?}", &event);
                let name_string = reader.decoder().decode(name.as_ref())?;
                Err(quick_xml::Error::UnexpectedToken(name_string.into()))
            }
        } else {
            let event_string = format!("{:?}", event);
            Err(quick_xml::Error::UnexpectedToken(event_string))
        }
    }
}

fn main() -> Result<(), quick_xml::Error> {
    // In a real-world use case, Settings would likely be a struct
    // HashMap here is just to make the sample code short
    let mut settings: HashMap<String, String>;
    let mut translations: Vec<Translation> = Vec::new();

    let mut reader = Reader::from_str(XML);
    reader.trim_text(true);

    // == Handling empty elements ==
    // To simply our processing code
    // we want the same events for empty elements, like:
    //   <DefaultSettings Language="es" Greeting="HELLO"/>
    //   <Text/>
    reader.expand_empty_elements(true);
    let mut buf = Vec::new();

    loop {
        let event = reader.read_event_into(&mut buf)?;

        match event {
            Event::Start(element) => match element.name().as_ref() {
                b"DefaultSettings" => {
                    // Note: real app would handle errors with good defaults or halt program with nice message
                    // This illustrates decoding an attribute's key and value with error handling
                    settings = element
                        .attributes()
                        .map(|attr_result| {
                            match attr_result {
                                Ok(a) => {
                                    let key = reader.decoder().decode(a.key.local_name().as_ref())
                                        .or_else(|err| {
                                            dbg!("unable to read key in DefaultSettings attribute {:?}, utf8 error {:?}", &a, err);
                                            Ok::<Cow<'_, str>, Infallible>(std::borrow::Cow::from(""))
                                        })
                                        .unwrap().to_string();
                                    let value = a.decode_and_unescape_value(&reader).or_else(|err| {
                                            dbg!("unable to read key in DefaultSettings attribute {:?}, utf8 error {:?}", &a, err);
                                            Ok::<Cow<'_, str>, Infallible>(std::borrow::Cow::from(""))
                                    }).unwrap().to_string();
                                    (key, value)
                                },
                                Err(err) => {
                                     dbg!("unable to read key in DefaultSettings, err = {:?}", err);
                                    (String::new(), String::new())
                                }
                            }
                        })
                        .collect();
                    assert_eq!(settings["Language"], "es");
                    assert_eq!(settings["Greeting"], "HELLO");
                    reader.read_to_end(element.name())?;
                }
                b"Translation" => {
                    translations.push(Translation::new_from_element(&mut reader, element)?);
                }
                _ => (),
            },

            Event::Eof => break, // exits the loop when reaching end of file
            _ => (),             // There are `Event` types not considered here
        }
    }
    dbg!("{:?}", &translations);
    assert_eq!(translations.len(), 4);
    assert_eq!(translations[2].tag, "HELLO");
    assert_eq!(translations[2].text, "Hola");
    assert_eq!(translations[2].lang, "es");

    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>Add another test for !<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(never_type)]

trait StringifyType {
    fn stringify_type() -> &'static str;
}

impl StringifyType for ! {
    fn stringify_type() -> &'static str {
        "!"
    }
}

fn maybe_stringify<T: StringifyType>(opt: Option<T>) -> &'static str {
    match opt {
        Some(_) => T::stringify_type(),
        None => "none",
    }
}

fn main() {
    println!("! is {}", <!>::stringify_type());
    println!("None is {}", maybe_stringify(None::<!>));
}

<|endoftext|>


<commit_before><commit_msg>sample program<commit_after><|endoftext|>


<commit_before><commit_msg>Document sinter<commit_after><|endoftext|>


<commit_before><commit_msg>Adding back the glm file.<commit_after>use linalg::vector::Vector;
use linalg::matrix::Matrix;

use learning::SupModel;

pub struct GenLinearModel<C: Criterion> {
    parameters: Option<Vector<f64>>,
    criterion: C,
}

impl<C: Criterion> GenLinearModel<C> {
	pub fn new(criterion: C) -> GenLinearModel<C> {
		GenLinearModel {
			parameters: None,
			criterion: criterion,
		}
	}
}

impl<C: Criterion> SupModel<Matrix<f64>, Vector<f64>> for GenLinearModel<C> {
    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let Some(ref v) = self.parameters {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            self.criterion.apply_link_inv(full_inputs * v)
        } else {
            panic!("The model has not been trained.");
        }
    }

    /// Train the model using inputs and targets.
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let n = inputs.rows();

        assert!(n == targets.size(),
                "Training data do not have the same dimensions.");

        // Construct mu as a non-zero estimate of targets.
        let mut mu_data = Vec::with_capacity(n);
        for y in targets.data() {
        	mu_data.push(0.5);//if *y > 0f64 { *y } else { 1e-3 })
        }

        let mut mu = Vector::new(mu_data);
        let mut z = mu.clone();
        let mut beta : Vector<f64> = Vector::new(vec![]);

        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);
        let x_t = full_inputs.transpose();

        // Iterate to convergence
        for k in 0..15 {
            let mut w_diag = Vec::with_capacity(n);
            let mut y_bar_data = Vec::with_capacity(n);

            for (idx, m) in mu.data().iter().enumerate() {
                y_bar_data.push(self.criterion.compute_y_bar(targets[idx], *m));
                w_diag.push(self.criterion.compute_working_weight(*m));
            }

            let i = 5;

            println!("-------- Iteration {0} --------", k+1);
            println!("mu[{0}] = {1}", i, mu[i]);
            println!("y[{0}] = {1}", i, targets[i]);
            println!("y_bar[{0}] = {1}", i, y_bar_data[i]);
            println!("w[{0}] = {1}", i, w_diag[i]);

            let w = Matrix::from_diag(&w_diag);
            let y_bar = Vector::new(y_bar_data);

            let x_t_w = &x_t * w;
            beta = (&x_t_w * &full_inputs).inverse() * x_t_w * z;

            //println!("Beta = {:?}", beta.data());

            // Update z and mu
            let fitted = &full_inputs * β
            z = y_bar + &fitted;
            mu = self.criterion.apply_link_inv(fitted);
        }

        self.parameters = Some(beta);
    }
}

/// Should include the link function and the variance from the distribution
pub trait Criterion {
	type Link : LinkFunc;

    fn model_variance(&self, mu: f64) -> f64;

    fn compute_working_weight(&self, mu: f64) -> f64 {
        1f64 / (self.model_variance(mu) * self.link_grad(mu) * self.link_grad(mu))
    }

    fn compute_y_bar(&self, y:f64, mu: f64) -> f64 {
        self.link_grad(mu) * (y - mu)
    }

    fn apply_link_func(&self, vec: Vector<f64>) -> Vector<f64> {
        vec.apply(&Self::Link::func)
    }

    fn apply_link_inv(&self, vec: Vector<f64>) -> Vector<f64> {
    	vec.apply(&Self::Link::func_inv)
    }

    fn link_grad(&self, mu: f64) -> f64 {
        Self::Link::func_grad(mu)
    }
}

pub trait LinkFunc {
    /// The link function.
    fn func(x: f64) -> f64;

    /// The gradient of the link function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the link function.
    /// Often called the 'mean' function.
    fn func_inv(x: f64) -> f64;
}

/// Sigmoid activation function.
pub struct Logit;

impl LinkFunc for Logit {
    /// Logit function.
    ///
    /// Returns ln(x / (1 - x)).
    fn func(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }

    /// Gradient of logit function.
    ///
    /// Returns 1 / (x * (1-x))
    fn func_grad(x: f64) -> f64 {
        1f64 / (x * (1f64 - x))
    }

    fn func_inv(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }
}

pub struct Bernoulli;

impl Criterion for Bernoulli {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        mu * (1f64 - mu)
    }

    fn compute_working_weight(&self, mu: f64) -> f64 {
        self.model_variance(mu)
    }

    fn compute_y_bar(&self, y:f64, mu: f64) -> f64 {
        let target_diff = y - mu;

        if target_diff.abs() < 1e-15 {
            0f64
        }
        else {
            self.link_grad(mu) * target_diff
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Don't assume there is an existing DB.<commit_after><|endoftext|>


<commit_before>extern crate redox;

//To use this, please install zfs-fuse
use redox::*;

use core::ptr;

mod nvpair;
mod nvstream;
mod xdr;

pub struct ZFS {
    disk: File,
}

impl ZFS {
    pub fn new(disk: File) -> Self {
        ZFS { disk: disk }
    }

    //TODO: Error handling
    pub fn read(&mut self, start: usize, length: usize) -> Vec<u8> {
        let mut ret: Vec<u8> = vec![0; length*512];

        self.disk.seek(Seek::Start(start * 512));
        self.disk.read(&mut ret);

        return ret;
    }

    pub fn write(&mut self, block: usize, data: &[u8; 512]) {
        self.disk.seek(Seek::Start(block * 512));
        self.disk.write(data);
    }
}

#[repr(packed)]
pub struct VdevLabel {
    pub blank: [u8; 8 * 1024],
    pub boot_header: [u8; 8 * 1024],
    pub nv_pairs: [u8; 112 * 1024],
    pub uberblocks: [Uberblock; 128],
}

impl VdevLabel {
    pub fn from(data: &[u8]) -> Option<Self> {
        if data.len() >= 262144 {
            let vdev_label = unsafe { ptr::read(data.as_ptr() as *const VdevLabel) };
            Some(vdev_label)
        } else {
            Option::None
        }
    }
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Uberblock {
    pub magic: u64,
    pub version: u64,
    pub txg: u64,
    pub guid_sum: u64,
    pub timestamp: u64,
    pub rootbp: BlockPtr,
}

impl Uberblock {
    pub fn magic_little() -> u64 {
        return 0x0cb1ba00;
    }

    pub fn magic_big() -> u64 {
        return 0x00bab10c;
    }

    pub fn from(data: &Vec<u8>) -> Option<Self> {
        if data.len() >= 1024 {
            let uberblock = unsafe { ptr::read(data.as_ptr() as *const Uberblock) };
            if uberblock.magic == Uberblock::magic_little() {
                println!("Little Magic");
                return Option::Some(uberblock);
            } else if uberblock.magic == Uberblock::magic_big() {
                println!("Big Magic");
                return Option::Some(uberblock);
            } else if uberblock.magic > 0 {
                println!("Unknown Magic: {:X}", uberblock.magic as usize);
            }
        }

        Option::None
    }
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct DVAddr {
    pub vdev: u64,
    pub offset: u64,
}

impl DVAddr {
    /// Sector address is the offset plus two vdev labels and one boot block (4 MB, or 8192 sectors)
    pub fn sector(&self) -> u64 {
        self.offset + 0x2000
    }
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct BlockPtr {
    pub dvas: [DVAddr; 3],
    pub flags_size: u64,
    pub padding: [u64; 3],
    pub birth_txg: u64,
    pub fill_count: u64,
    pub checksum: [u64; 4],
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Gang {
    pub bps: [BlockPtr; 3],
    pub padding: [u64; 14],
    pub magic: u64,
    pub checksum: u64,
}

impl Gang {
    pub fn magic() -> u64 {
        return 0x117a0cb17ada1002;
    }
}

//TODO: Find a way to remove all the to_string's
pub fn main() {
    console_title(&"ZFS".to_string());

    let red = [255, 127, 127, 255];
    let green = [127, 255, 127, 255];
    let blue = [127, 127, 255, 255];

    println!("Type open zfs.img to open the image file");
    println!("This may take up to 30 seconds");

    let mut zfs_option: Option<ZFS> = Option::None;

    while let Option::Some(line) = readln!() {
        let mut args: Vec<String> = Vec::new();
        for arg in line.split(' ') {
            args.push(arg.to_string());
        }

        if let Option::Some(command) = args.get(0) {
            println!("# {}", line);

            let mut close = false;
            match zfs_option {
                Option::Some(ref mut zfs) => {
                    if *command == "uber".to_string() {
                        //128 KB of ubers after 128 KB of other stuff
                        let mut newest_uberblock: Option<Uberblock> = Option::None;
                        for i in 0..128 {
                            match Uberblock::from(&zfs.read(256 + i * 2, 2)) {
                                Option::Some(uberblock) => {
                                    let mut newest = false;
                                    match newest_uberblock {
                                        Option::Some(previous) => {
                                            if uberblock.txg > previous.txg {
                                                newest = true;
                                            }
                                        }
                                        Option::None => newest = true,
                                    }

                                    if newest {
                                        newest_uberblock = Option::Some(uberblock);
                                    }
                                }
                                Option::None => (), //Invalid uberblock
                            }
                        }

                        match newest_uberblock {
                            Option::Some(uberblock) => {
                                println_color!(green, "Newest Uberblock");
                                //TODO: Do not use as usize
                                println!("Magic: {:X}", uberblock.magic as usize);
                                println!("Version: {}", uberblock.version as usize);
                                println!("TXG: {}", uberblock.txg as usize);
                                println!("Timestamp: {}", uberblock.timestamp as usize);
                                println!("MOS: {}",
                                         uberblock.rootbp.dvas[0].sector() as usize);
                            }
                            Option::None => println_color!(red, "No valid uberblock found!"),
                        }
                    } else if *command == "vdev_label".to_string() {
                        let mut vdev_label = VdevLabel::from(&zfs.read(0, 256 * 2)); // 256KB of vdev label
                        match vdev_label {
                            Some(ref mut vdev_label) => {
                                let mut xdr = xdr::MemOps::new(&mut vdev_label.nv_pairs);
                                let nv_list = nvstream::decode_nv_list(&mut xdr);
                                println_color!(green, "Successfully read nv_list");
                                //readln!();
                                //println_color!(green, "Got nv_list:\n{:?}", nv_list);
                            },
                            None => { println_color!(red, "Couldn't read vdev_label"); },
                        }
                    } else if *command == "list".to_string() {
                        println_color!(green, "List volumes");
                    } else if *command == "dump".to_string() {
                        match args.get(1) {
                            Option::Some(arg) => {
                                let sector = arg.to_num();
                                println_color!(green, "Dump sector: {}", sector);

                                let data = zfs.read(sector, 1);
                                for i in 0..data.len() {
                                    if i % 32 == 0 {
                                        print!("\n{:X}:", i);
                                    }
                                    if let Option::Some(byte) = data.get(i) {
                                        print!(" {:X}", *byte);
                                    } else {
                                        println!(" !");
                                    }
                                }
                                print!("\n");
                            }
                            Option::None => println_color!(red, "No sector specified!"),
                        }
                    } else if *command == "close".to_string() {
                        println_color!(red, "Closing");
                        close = true;
                    } else {
                        println_color!(blue, "Commands: uber list dump close");
                    }
                }
                Option::None => {
                    if *command == "open".to_string() {
                        match args.get(1) {
                            Option::Some(arg) => {
                                println_color!(green, "Open: {}", arg);
                                zfs_option = Option::Some(ZFS::new(File::open(arg)));
                            }
                            Option::None => println_color!(red, "No file specified!"),
                        }
                    } else {
                        println_color!(blue, "Commands: open");
                    }
                }
            }
            if close {
                zfs_option = Option::None;
            }
        }
    }
}
<commit_msg>Add vdev_label to command list<commit_after>extern crate redox;

//To use this, please install zfs-fuse
use redox::*;

use core::ptr;

mod nvpair;
mod nvstream;
mod xdr;

pub struct ZFS {
    disk: File,
}

impl ZFS {
    pub fn new(disk: File) -> Self {
        ZFS { disk: disk }
    }

    //TODO: Error handling
    pub fn read(&mut self, start: usize, length: usize) -> Vec<u8> {
        let mut ret: Vec<u8> = vec![0; length*512];

        self.disk.seek(Seek::Start(start * 512));
        self.disk.read(&mut ret);

        return ret;
    }

    pub fn write(&mut self, block: usize, data: &[u8; 512]) {
        self.disk.seek(Seek::Start(block * 512));
        self.disk.write(data);
    }
}

#[repr(packed)]
pub struct VdevLabel {
    pub blank: [u8; 8 * 1024],
    pub boot_header: [u8; 8 * 1024],
    pub nv_pairs: [u8; 112 * 1024],
    pub uberblocks: [Uberblock; 128],
}

impl VdevLabel {
    pub fn from(data: &[u8]) -> Option<Self> {
        if data.len() >= 262144 {
            let vdev_label = unsafe { ptr::read(data.as_ptr() as *const VdevLabel) };
            Some(vdev_label)
        } else {
            Option::None
        }
    }
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Uberblock {
    pub magic: u64,
    pub version: u64,
    pub txg: u64,
    pub guid_sum: u64,
    pub timestamp: u64,
    pub rootbp: BlockPtr,
}

impl Uberblock {
    pub fn magic_little() -> u64 {
        return 0x0cb1ba00;
    }

    pub fn magic_big() -> u64 {
        return 0x00bab10c;
    }

    pub fn from(data: &Vec<u8>) -> Option<Self> {
        if data.len() >= 1024 {
            let uberblock = unsafe { ptr::read(data.as_ptr() as *const Uberblock) };
            if uberblock.magic == Uberblock::magic_little() {
                println!("Little Magic");
                return Option::Some(uberblock);
            } else if uberblock.magic == Uberblock::magic_big() {
                println!("Big Magic");
                return Option::Some(uberblock);
            } else if uberblock.magic > 0 {
                println!("Unknown Magic: {:X}", uberblock.magic as usize);
            }
        }

        Option::None
    }
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct DVAddr {
    pub vdev: u64,
    pub offset: u64,
}

impl DVAddr {
    /// Sector address is the offset plus two vdev labels and one boot block (4 MB, or 8192 sectors)
    pub fn sector(&self) -> u64 {
        self.offset + 0x2000
    }
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct BlockPtr {
    pub dvas: [DVAddr; 3],
    pub flags_size: u64,
    pub padding: [u64; 3],
    pub birth_txg: u64,
    pub fill_count: u64,
    pub checksum: [u64; 4],
}

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Gang {
    pub bps: [BlockPtr; 3],
    pub padding: [u64; 14],
    pub magic: u64,
    pub checksum: u64,
}

impl Gang {
    pub fn magic() -> u64 {
        return 0x117a0cb17ada1002;
    }
}

//TODO: Find a way to remove all the to_string's
pub fn main() {
    console_title("ZFS");

    let red = [255, 127, 127, 255];
    let green = [127, 255, 127, 255];
    let blue = [127, 127, 255, 255];

    println!("Type open zfs.img to open the image file");

    let mut zfs_option: Option<ZFS> = Option::None;

    while let Option::Some(line) = readln!() {
        let mut args: Vec<String> = Vec::new();
        for arg in line.split(' ') {
            args.push(arg.to_string());
        }

        if let Option::Some(command) = args.get(0) {
            println!("# {}", line);

            let mut close = false;
            match zfs_option {
                Option::Some(ref mut zfs) => {
                    if *command == "uber".to_string() {
                        //128 KB of ubers after 128 KB of other stuff
                        let mut newest_uberblock: Option<Uberblock> = Option::None;
                        for i in 0..128 {
                            match Uberblock::from(&zfs.read(256 + i * 2, 2)) {
                                Option::Some(uberblock) => {
                                    let mut newest = false;
                                    match newest_uberblock {
                                        Option::Some(previous) => {
                                            if uberblock.txg > previous.txg {
                                                newest = true;
                                            }
                                        }
                                        Option::None => newest = true,
                                    }

                                    if newest {
                                        newest_uberblock = Option::Some(uberblock);
                                    }
                                }
                                Option::None => (), //Invalid uberblock
                            }
                        }

                        match newest_uberblock {
                            Option::Some(uberblock) => {
                                println_color!(green, "Newest Uberblock");
                                //TODO: Do not use as usize
                                println!("Magic: {:X}", uberblock.magic as usize);
                                println!("Version: {}", uberblock.version as usize);
                                println!("TXG: {}", uberblock.txg as usize);
                                println!("Timestamp: {}", uberblock.timestamp as usize);
                                println!("MOS: {}",
                                         uberblock.rootbp.dvas[0].sector() as usize);
                            }
                            Option::None => println_color!(red, "No valid uberblock found!"),
                        }
                    } else if *command == "vdev_label".to_string() {
                        let mut vdev_label = VdevLabel::from(&zfs.read(0, 256 * 2)); // 256KB of vdev label
                        match vdev_label {
                            Some(ref mut vdev_label) => {
                                let mut xdr = xdr::MemOps::new(&mut vdev_label.nv_pairs);
                                let nv_list = nvstream::decode_nv_list(&mut xdr);
                                println_color!(green, "Successfully read nv_list");
                                //readln!();
                                //println_color!(green, "Got nv_list:\n{:?}", nv_list);
                            },
                            None => { println_color!(red, "Couldn't read vdev_label"); },
                        }
                    } else if *command == "list".to_string() {
                        println_color!(green, "List volumes");
                    } else if *command == "dump".to_string() {
                        match args.get(1) {
                            Option::Some(arg) => {
                                let sector = arg.to_num();
                                println_color!(green, "Dump sector: {}", sector);

                                let data = zfs.read(sector, 1);
                                for i in 0..data.len() {
                                    if i % 32 == 0 {
                                        print!("\n{:X}:", i);
                                    }
                                    if let Option::Some(byte) = data.get(i) {
                                        print!(" {:X}", *byte);
                                    } else {
                                        println!(" !");
                                    }
                                }
                                print!("\n");
                            }
                            Option::None => println_color!(red, "No sector specified!"),
                        }
                    } else if *command == "close".to_string() {
                        println_color!(red, "Closing");
                        close = true;
                    } else {
                        println_color!(blue, "Commands: uber vdev_label list dump close");
                    }
                }
                Option::None => {
                    if *command == "open".to_string() {
                        match args.get(1) {
                            Option::Some(arg) => {
                                println_color!(green, "Open: {}", arg);
                                zfs_option = Option::Some(ZFS::new(File::open(arg)));
                            }
                            Option::None => println_color!(red, "No file specified!"),
                        }
                    } else {
                        println_color!(blue, "Commands: open");
                    }
                }
            }
            if close {
                zfs_option = Option::None;
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>add particles mod<commit_after><|endoftext|>


<commit_before><commit_msg>Ctrl+C Clear's Multi-line Prompts<commit_after><|endoftext|>