<commit_before>use dirs;
use std::fs;
use std::io::ErrorKind;
use std::process::Command;

pub fn run() {
    // Environment (Unix)

    let password_manager_status = match Command::new("brew")
        .arg("cask")
        .arg("list")
        .arg("1password")
        .output()
    {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if password_manager_status.success() {
        println!("Password manager is already installed.")
    } else {
        println!("Installing password manager.");
        match Command::new("brew")
            .arg("cask")
            .arg("install")
            .arg("1password")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let search_tool_status = match Command::new("brew").arg("list").arg("ripgrep").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if search_tool_status.success() {
        println!("Search tool is already installed.")
    } else {
        println!("Installing search tool.");
        match Command::new("brew").arg("install").arg("ripgrep").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Version control (Git)

    let version_control_status = match Command::new("brew").arg("list").arg("git").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if version_control_status.success() {
        println!("Version control is already installed.")
    } else {
        println!("Installing version control.");
        match Command::new("brew").arg("install").arg("git").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let repos_path = home_path.join("repos");

    if repos_path.exists() {
        println!("Repos directory already exists.")
    } else {
        println!("Creating repos directory.");
        match fs::create_dir_all(&repos_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&repos_path) {
        Ok(_) => println!("Repos are already installed."),
        Err(_) => {
            println!("Cloning scripts repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/scripts")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Cloning study repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/study")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Cloning trevordmiller.github.io repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/trevordmiller.github.io")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Editor (Vim)

    let editor_status = match Command::new("brew").arg("list").arg("vim").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if editor_status.success() {
        println!("Editor is already installed.")
    } else {
        println!("Installing editor.");
        match Command::new("brew").arg("install").arg("vim").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let editor_plugins_path = home_path
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    if editor_plugins_path.exists() {
        println!("Editor plugins directory already exists.")
    } else {
        println!("Creating editor plugins directory.");
        match fs::create_dir_all(&editor_plugins_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    let editor_configuration_path = home_path.join(".vimrc");

    if editor_configuration_path.exists() {
        println!("Editor configuration file already exists.")
    } else {
        println!("Creating editor configuration file.");
        match fs::File::create(&editor_configuration_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&editor_plugins_path) {
        Ok(_) => println!("Editor plugins are already installed."),
        Err(_) => {
            println!("Installing editor plugin to normalize editor defaults.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sensible")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor indentation.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sleuth")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor languages.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/sheerun/vim-polyglot")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor ignore patterns.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/octref/RootIgnore")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor static analysis.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/dense-analysis/ale")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor search.");

            match fs::write(&editor_configuration_path, "set grepprg=rg\\ --vimgrep") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            match fs::write(&editor_configuration_path, "set grepformat=%f:%l:%c:%m") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor colors.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/arcticicestudio/nord-vim")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor colors.");

            match fs::write(editor_configuration_path, "colorscheme nord") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Application programming (JavaScript)

    let application_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("node").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if application_programming_toolchain_status.success() {
        println!("Application programming toolchain is already installed.")
    } else {
        println!("Installing application programming toolchain.");
        match Command::new("brew").arg("install").arg("node").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Systems programming (Rust)

    let systems_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("rustup-init").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if systems_programming_toolchain_status.success() {
        println!("Systems programming toolchain is already installed.")
    } else {
        println!("Installing systems programming toolchain.");
        match Command::new("brew")
            .arg("install")
            .arg("rustup-init")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }

        match Command::new("rustup-init").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `rustup-init` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }
}
<commit_msg>Make sure directory is only created if home directory exists<commit_after>use dirs;
use std::fs;
use std::io::ErrorKind;
use std::process::Command;

pub fn run() {
    // Environment (Unix)

    let password_manager_status = match Command::new("brew")
        .arg("cask")
        .arg("list")
        .arg("1password")
        .output()
    {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if password_manager_status.success() {
        println!("Password manager is already installed.")
    } else {
        println!("Installing password manager.");
        match Command::new("brew")
            .arg("cask")
            .arg("install")
            .arg("1password")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let search_tool_status = match Command::new("brew").arg("list").arg("ripgrep").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if search_tool_status.success() {
        println!("Search tool is already installed.")
    } else {
        println!("Installing search tool.");
        match Command::new("brew").arg("install").arg("ripgrep").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Version control (Git)

    let version_control_status = match Command::new("brew").arg("list").arg("git").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if version_control_status.success() {
        println!("Version control is already installed.")
    } else {
        println!("Installing version control.");
        match Command::new("brew").arg("install").arg("git").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let repos_path = home_path.join("repos");

    if repos_path.exists() {
        println!("Repos directory already exists.")
    } else {
        println!("Creating repos directory.");
        match fs::create_dir(&repos_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&repos_path) {
        Ok(_) => println!("Repos are already installed."),
        Err(_) => {
            println!("Cloning scripts repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/scripts")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Cloning study repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/study")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Cloning trevordmiller.github.io repo.");

            match Command::new("git")
                .current_dir(&repos_path)
                .arg("clone")
                .arg("https://github.com/trevordmiller/trevordmiller.github.io")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Editor (Vim)

    let editor_status = match Command::new("brew").arg("list").arg("vim").output() {
        Ok(output) => output.status,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The `brew` command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    };

    if editor_status.success() {
        println!("Editor is already installed.")
    } else {
        println!("Installing editor.");
        match Command::new("brew").arg("install").arg("vim").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    let editor_plugins_path = home_path
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    if editor_plugins_path.exists() {
        println!("Editor plugins directory already exists.")
    } else {
        println!("Creating editor plugins directory.");
        match fs::create_dir_all(&editor_plugins_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    let editor_configuration_path = home_path.join(".vimrc");

    if editor_configuration_path.exists() {
        println!("Editor configuration file already exists.")
    } else {
        println!("Creating editor configuration file.");
        match fs::File::create(&editor_configuration_path) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }

    match fs::read_dir(&editor_plugins_path) {
        Ok(_) => println!("Editor plugins are already installed."),
        Err(_) => {
            println!("Installing editor plugin to normalize editor defaults.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sensible")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor indentation.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/tpope/vim-sleuth")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor languages.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/sheerun/vim-polyglot")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor ignore patterns.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/octref/RootIgnore")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor static analysis.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/dense-analysis/ale")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor search.");

            match fs::write(&editor_configuration_path, "set grepprg=rg\\ --vimgrep") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            match fs::write(&editor_configuration_path, "set grepformat=%f:%l:%c:%m") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Installing editor plugin to enhance editor colors.");

            match Command::new("git")
                .current_dir(&editor_plugins_path)
                .arg("clone")
                .arg("https://github.com/arcticicestudio/nord-vim")
                .output()
            {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            println!("Adding editor configuration to enhance editor colors.");

            match fs::write(editor_configuration_path, "colorscheme nord") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Application programming (JavaScript)

    let application_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("node").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if application_programming_toolchain_status.success() {
        println!("Application programming toolchain is already installed.")
    } else {
        println!("Installing application programming toolchain.");
        match Command::new("brew").arg("install").arg("node").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }

    // Systems programming (Rust)

    let systems_programming_toolchain_status =
        match Command::new("brew").arg("list").arg("rustup-init").output() {
            Ok(output) => output.status,
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        };

    if systems_programming_toolchain_status.success() {
        println!("Systems programming toolchain is already installed.")
    } else {
        println!("Installing systems programming toolchain.");
        match Command::new("brew")
            .arg("install")
            .arg("rustup-init")
            .output()
        {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `brew` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }

        match Command::new("rustup-init").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The `rustup-init` command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use std::cmp::*;

use types::WashArgs::*;

use constants::*;
use types::*;
use util::*;
use env::*;

use self::HandlerResult::*;

// Note with handlers: Err means Stop, not necessarily Fail
// return semi-redundant result type because try! is so damn useful
pub type WashHandler = fn(&mut Vec<WashArgs>, &mut Vec<InputValue>, &mut ShellState) -> Result<HandlerResult, String>;

pub type HandlerTable = HashMap<String, WashHandler>;

pub enum HandlerResult {
    Continue,
    Stop,
    More(WashBlock)
}

#[derive(Clone)]
pub struct WashBlock {
    pub start: String,
    pub next: Vec<InputValue>,
    pub close: Vec<InputValue>,
    pub content: Vec<InputValue>
}

pub struct ShellState {
    pub env: WashEnv,
    blocks: Vec<WashBlock>,
    handlers: HandlerTable,
    last: Option<Result<WashArgs, String>>
}

impl ShellState {
    pub fn new() -> ShellState {
        ShellState {
            handlers: HashMap::new(),
            env: WashEnv::new(),
            blocks: vec![],
            last: None
        }
    }

    pub fn in_block(&self) -> bool {
        return !self.blocks.is_empty();
    }

    pub fn has_handler(&self, word:&String) -> bool {
        return self.handlers.contains_key(word);
    }

    pub fn insert_handler(&mut self, word:&str, func:WashHandler) -> Result<WashArgs, String> {
        self.handlers.insert(word.to_string(), func);
        return Ok(Empty);
    }

    pub fn run_handler(&mut self, word:&String, pre:&mut Vec<WashArgs>, next:&mut Vec<InputValue>) -> Result<HandlerResult, String> {
        let func = match self.handlers.get(word) {
            None => return Err("Handler not found".to_string()),
            Some(func) => func.clone()
        };
        return func(pre, next, self);
    }

    pub fn process_command(&mut self, args:Vec<WashArgs>) -> Result<WashArgs, String> {
        if args.is_empty() {
            // this happens when a handler ends a line and passes nothing on
            return Ok(Empty);
        } else if self.env.hasf(&args[0].flatten()) {
            // run as a function instead
            return self.env.runf(&args[0].flatten(), &Long(args[min(1, args.len())..].to_vec()));
        } else {
            let out = try!(self.process_function("run".to_string(), args));
            return self.env.describe_process_output(&out);
        }
    }

    pub fn process_function(&mut self, name:String, args:Vec<WashArgs>) -> Result<WashArgs, String> {
        let out = try!(self.env.runf(&name, &WashArgs::Long(args)));
        return Ok(out);
    }

    pub fn process_lines<'a, T:Iterator<Item=&'a InputValue>>(&mut self, mut lines:T) -> Result<WashArgs, String> {
        let mut out = Flat(String::new());
        let reset_sigint;
        if self.env.catch_sigint {
            reset_sigint = true;
            // handle sigint
            self.env.handle_sigint();
            // prevent env from unsetting that handler
            self.env.catch_sigint = false;
        } else {
            reset_sigint = false;
        }
        for line in lines {
            // check for stop
            try!(self.env.func_stop());
            out = match self.process_line(line.clone()) {
                Err(ref e) if *e == STOP => Empty,
                Err(e) => {
                    if reset_sigint {
                        self.env.catch_sigint = true;
                        self.env.unhandle_sigint();
                    }
                    return Err(e);
                },
                Ok(v) => v
            }
        }
        if reset_sigint {
            self.env.catch_sigint = true;
            self.env.unhandle_sigint();
        }
        return Ok(out);
    }

    pub fn process_block(&mut self) -> Result<WashArgs, String> {
        if self.blocks.is_empty() {
            return Err("No block defined".to_string());
        }
        let block = self.blocks.pop().unwrap();
        if block.start == "act" {
            return self.process_lines(block.content.iter());
        } else if block.start == "if" || block.start == "else" {
            let mut cond = self.last.clone().unwrap_or(Err("No last value".to_string()));
            let next_empty = block.next.is_empty();
            if block.start == "else" && cond.is_ok() {
                // return early in the else case
                return Err(STOP.to_string());
            }
            if !next_empty {
                cond = self.process_line(InputValue::Long(block.next));
            }
            if cond.is_ok() || (block.start == "else" && next_empty) {
                return self.process_lines(block.content.iter());
            } else {
                return Err(STOP.to_string());
            }
        } else if block.start == "loop" {
            let mut cond;
            if block.next.is_empty() {
                cond = Ok(Flat(String::new()));
            } else {
                cond = self.process_line(InputValue::Long(block.next.clone()));
            }
            let mut out = Err(STOP.to_string());
            // handle sigint
            self.env.handle_sigint();
            // prevent env from unsetting that handler
            self.env.catch_sigint = false;
            while cond.is_ok() {
                // check for stop
                match self.env.func_stop() {
                    Err(e) => {
                        self.env.catch_sigint = true;
                        self.env.unhandle_sigint();
                        return Err(e);
                    },
                    _ => {/* nothing */}
                }
                out = match self.process_lines(block.content.iter()) {
                    Err(ref e) if *e == STOP => Ok(Empty),
                    Err(e) => {
                        self.env.catch_sigint = true;
                        self.env.unhandle_sigint();
                        return Err(e);
                    },
                    v => v
                };
                if block.next.is_empty() {
                    cond = Ok(Flat(String::new()));
                } else {
                    cond = self.process_line(InputValue::Long(block.next.clone()));
                }
            }
            self.env.catch_sigint = true;
            self.env.unhandle_sigint();
            return out;
        } else {
            return Err(format!("Don't know how to handle block: {}", block.start));
        }
    }

    pub fn process_line(&mut self, line:InputValue) -> Result<WashArgs, String> {
        let out = self.process_line_inner(line);
        self.last = Some(out.clone());
        return out;
    }

    pub fn process_line_inner(&mut self, line:InputValue) -> Result<WashArgs, String> {
        if self.blocks.is_empty() {
            match line {
                InputValue::Function(n, a) => {
                    let vec = try!(self.input_to_vec(a));
                    return self.process_function(n, vec);
                },
                InputValue::Long(a) => {
                    // run as command
                    let vec = try!(self.input_to_vec(a));
                    if vec.is_empty() {
                        if self.blocks.is_empty() {
                            return Ok(Empty);
                        } else if !self.blocks[0].close.is_empty() {
                            return Ok(Empty);
                        } else {
                            return self.process_block();
                        }
                    } else {
                        return self.process_command(vec);
                    }
                },
                InputValue::Short(ref s) if VAR_PATH_REGEX.is_match(s.as_slice()) => {
                    let out = try!(self.input_to_args(InputValue::Short(s.clone())));
                    return Ok(Flat(format!("{}\n", out.flatten_with_inner("\n", "="))));
                },
                InputValue::Short(ref s) if VAR_REGEX.is_match(s.as_slice()) => {
                    let out = try!(self.input_to_args(InputValue::Short(s.clone())));
                    return Ok(Flat(format!("{}\n", out.flatten())));
                },
                InputValue::Short(s) | InputValue::Literal(s) => {
                    // run command without args
                    return self.process_command(vec![Flat(s)]);
                },
                _ => {
                    // do nothing
                    return Ok(Flat(String::new()));
                }
            }
        } else {
            if self.blocks[0].close.is_empty() {
                return self.process_block();
            } else if self.blocks[0].close[0] == line.clone() {
                self.blocks[0].close.pop();
                if self.blocks[0].close.is_empty() {
                    return self.process_block();
                } else {
                    self.blocks[0].content.push(line);
                    return Ok(Empty);
                }
            } else {
                match line {
                    InputValue::Long(ref v) =>
                        if create_content(&mut v.clone()) == Ok(vec![]) {
                            self.blocks[0].close.push(InputValue::Short("}".to_string()));
                        },
                    _ => {}
                }
                self.blocks[0].content.push(line);
                // continue block
                return Ok(Empty);
            }
        }
    }

    pub fn input_to_vec(&mut self, input:Vec<InputValue>) -> Result<Vec<WashArgs>, String> {
        let mut out = vec![];
        // avoid O(n^2) situation
        let mut iter = reverse(input);
        let mut scope = vec![];
        let mut last_empty = false;
        loop {
            match iter.pop() {
                None => break,
                Some(InputValue::Short(ref name)) if self.has_handler(name) => {
                    while match get_nm_index(&iter, iter.len() - 1) {
                        Some(&InputValue::Split(_)) => true,
                        _ => false
                    } {
                        // skip any splits after the handle sequence
                        iter.pop();
                    }
                    // produce a correct scope for the handler
                    scope.clear();
                    while match get_nm_index(&iter, iter.len() - 1) {
                        None => false,
                        Some(&InputValue::Split(ref ns)) if self.has_handler(ns) => false,
                        Some(_) => true
                    } {
                        // doing this means scope will be in the same order as input
                        scope.push(iter.pop().unwrap());
                    }
                    // this can change out and scope, be careful
                    match self.run_handler(name, &mut out, &mut scope) {
                        Ok(Stop) => return Err(STOP.to_string()),
                        Ok(More(block)) => {
                            // start of a block
                            self.blocks.push(block);
                            return Ok(vec![]);
                        },
                        Ok(Continue) => {/* continue */},
                        Err(e) => return Err(e) // this is an error
                    }
                    // push remaining scope back onto iter
                    loop {
                        match scope.pop() {
                            None => break,
                            Some(v) => iter.push(v)
                        }
                    }
                },
                Some(v) => {
                    match try!(self.input_to_args(v.clone())) {
                        Empty if !last_empty => last_empty = true,
                        Empty => out.push(Empty),
                        new => {
                            out.push(new);
                            last_empty = false;
                        }
                    }
                }
            };
        }
        return Ok(out);
    }

    pub fn input_to_args(&mut self, input:InputValue) -> Result<WashArgs, String> {
        match input {
            InputValue::Function(n, a) => {
                let vec = try!(self.input_to_vec(a));
                return self.process_function(n, vec);
            },
            InputValue::Long(a) => {
                return Ok(Long(try!(self.input_to_vec(a))));
            },
            // the special cases with regex make for more informative errors
            InputValue::Short(ref s) if VAR_PATH_REGEX.is_match(s.as_slice()) => {
                let caps = VAR_PATH_REGEX.captures(s.as_slice()).unwrap();
                let path = caps.at(1).unwrap().to_string();
                let name = caps.at(2).unwrap().to_string();
                if name.is_empty() {
                    if path.is_empty() {
                        return self.env.getall();
                    } else {
                        return self.env.getallp(&path);
                    }
                } else {
                    return self.env.getvp(&name, &path);
                }
            },
            InputValue::Short(ref s) if VAR_REGEX.is_match(s.as_slice()) => {
                let caps = VAR_REGEX.captures(s.as_slice()).unwrap();
                let name = caps.at(1).unwrap().to_string();
                return self.env.getv(&name);
            },
            InputValue::Short(ref s) if s.is_empty() => return Ok(Empty),
            InputValue::Short(s) | InputValue::Literal(s) => return Ok(Flat(s)),
            InputValue::Split(_) => return Ok(Empty)
        }
    }
}
<commit_msg>Update for rust nightly<commit_after>use std::collections::HashMap;

use std::cmp::*;

use types::WashArgs::*;

use constants::*;
use types::*;
use util::*;
use env::*;

use self::HandlerResult::*;

// Note with handlers: Err means Stop, not necessarily Fail
// return semi-redundant result type because try! is so damn useful
pub type WashHandler = fn(&mut Vec<WashArgs>, &mut Vec<InputValue>, &mut ShellState) -> Result<HandlerResult, String>;

pub type HandlerTable = HashMap<String, WashHandler>;

pub enum HandlerResult {
    Continue,
    Stop,
    More(WashBlock)
}

#[derive(Clone)]
pub struct WashBlock {
    pub start: String,
    pub next: Vec<InputValue>,
    pub close: Vec<InputValue>,
    pub content: Vec<InputValue>
}

pub struct ShellState {
    pub env: WashEnv,
    blocks: Vec<WashBlock>,
    handlers: HandlerTable,
    last: Option<Result<WashArgs, String>>
}

impl ShellState {
    pub fn new() -> ShellState {
        ShellState {
            handlers: HashMap::new(),
            env: WashEnv::new(),
            blocks: vec![],
            last: None
        }
    }

    pub fn in_block(&self) -> bool {
        return !self.blocks.is_empty();
    }

    pub fn has_handler(&self, word:&String) -> bool {
        return self.handlers.contains_key(word);
    }

    pub fn insert_handler(&mut self, word:&str, func:WashHandler) -> Result<WashArgs, String> {
        self.handlers.insert(word.to_string(), func);
        return Ok(Empty);
    }

    pub fn run_handler(&mut self, word:&String, pre:&mut Vec<WashArgs>, next:&mut Vec<InputValue>) -> Result<HandlerResult, String> {
        let func = match self.handlers.get(word) {
            None => return Err("Handler not found".to_string()),
            Some(func) => func.clone()
        };
        return func(pre, next, self);
    }

    pub fn process_command(&mut self, args:Vec<WashArgs>) -> Result<WashArgs, String> {
        if args.is_empty() {
            // this happens when a handler ends a line and passes nothing on
            return Ok(Empty);
        } else if self.env.hasf(&args[0].flatten()) {
            // run as a function instead
            return self.env.runf(&args[0].flatten(), &Long(args[min(1, args.len())..].to_vec()));
        } else {
            let out = try!(self.process_function("run".to_string(), args));
            return self.env.describe_process_output(&out);
        }
    }

    pub fn process_function(&mut self, name:String, args:Vec<WashArgs>) -> Result<WashArgs, String> {
        let out = try!(self.env.runf(&name, &WashArgs::Long(args)));
        return Ok(out);
    }

    pub fn process_lines<'a, T:Iterator<Item=&'a InputValue>>(&mut self, lines:T) -> Result<WashArgs, String> {
        let mut out = Flat(String::new());
        let reset_sigint;
        if self.env.catch_sigint {
            reset_sigint = true;
            // handle sigint
            self.env.handle_sigint();
            // prevent env from unsetting that handler
            self.env.catch_sigint = false;
        } else {
            reset_sigint = false;
        }
        for line in lines {
            // check for stop
            try!(self.env.func_stop());
            out = match self.process_line(line.clone()) {
                Err(ref e) if *e == STOP => Empty,
                Err(e) => {
                    if reset_sigint {
                        self.env.catch_sigint = true;
                        self.env.unhandle_sigint();
                    }
                    return Err(e);
                },
                Ok(v) => v
            }
        }
        if reset_sigint {
            self.env.catch_sigint = true;
            self.env.unhandle_sigint();
        }
        return Ok(out);
    }

    pub fn process_block(&mut self) -> Result<WashArgs, String> {
        if self.blocks.is_empty() {
            return Err("No block defined".to_string());
        }
        let block = self.blocks.pop().unwrap();
        if block.start == "act" {
            return self.process_lines(block.content.iter());
        } else if block.start == "if" || block.start == "else" {
            let mut cond = self.last.clone().unwrap_or(Err("No last value".to_string()));
            let next_empty = block.next.is_empty();
            if block.start == "else" && cond.is_ok() {
                // return early in the else case
                return Err(STOP.to_string());
            }
            if !next_empty {
                cond = self.process_line(InputValue::Long(block.next));
            }
            if cond.is_ok() || (block.start == "else" && next_empty) {
                return self.process_lines(block.content.iter());
            } else {
                return Err(STOP.to_string());
            }
        } else if block.start == "loop" {
            let mut cond;
            if block.next.is_empty() {
                cond = Ok(Flat(String::new()));
            } else {
                cond = self.process_line(InputValue::Long(block.next.clone()));
            }
            let mut out = Err(STOP.to_string());
            // handle sigint
            self.env.handle_sigint();
            // prevent env from unsetting that handler
            self.env.catch_sigint = false;
            while cond.is_ok() {
                // check for stop
                match self.env.func_stop() {
                    Err(e) => {
                        self.env.catch_sigint = true;
                        self.env.unhandle_sigint();
                        return Err(e);
                    },
                    _ => {/* nothing */}
                }
                out = match self.process_lines(block.content.iter()) {
                    Err(ref e) if *e == STOP => Ok(Empty),
                    Err(e) => {
                        self.env.catch_sigint = true;
                        self.env.unhandle_sigint();
                        return Err(e);
                    },
                    v => v
                };
                if block.next.is_empty() {
                    cond = Ok(Flat(String::new()));
                } else {
                    cond = self.process_line(InputValue::Long(block.next.clone()));
                }
            }
            self.env.catch_sigint = true;
            self.env.unhandle_sigint();
            return out;
        } else {
            return Err(format!("Don't know how to handle block: {}", block.start));
        }
    }

    pub fn process_line(&mut self, line:InputValue) -> Result<WashArgs, String> {
        let out = self.process_line_inner(line);
        self.last = Some(out.clone());
        return out;
    }

    pub fn process_line_inner(&mut self, line:InputValue) -> Result<WashArgs, String> {
        if self.blocks.is_empty() {
            match line {
                InputValue::Function(n, a) => {
                    let vec = try!(self.input_to_vec(a));
                    return self.process_function(n, vec);
                },
                InputValue::Long(a) => {
                    // run as command
                    let vec = try!(self.input_to_vec(a));
                    if vec.is_empty() {
                        if self.blocks.is_empty() {
                            return Ok(Empty);
                        } else if !self.blocks[0].close.is_empty() {
                            return Ok(Empty);
                        } else {
                            return self.process_block();
                        }
                    } else {
                        return self.process_command(vec);
                    }
                },
                InputValue::Short(ref s) if VAR_PATH_REGEX.is_match(s.as_slice()) => {
                    let out = try!(self.input_to_args(InputValue::Short(s.clone())));
                    return Ok(Flat(format!("{}\n", out.flatten_with_inner("\n", "="))));
                },
                InputValue::Short(ref s) if VAR_REGEX.is_match(s.as_slice()) => {
                    let out = try!(self.input_to_args(InputValue::Short(s.clone())));
                    return Ok(Flat(format!("{}\n", out.flatten())));
                },
                InputValue::Short(s) | InputValue::Literal(s) => {
                    // run command without args
                    return self.process_command(vec![Flat(s)]);
                },
                _ => {
                    // do nothing
                    return Ok(Flat(String::new()));
                }
            }
        } else {
            if self.blocks[0].close.is_empty() {
                return self.process_block();
            } else if self.blocks[0].close[0] == line.clone() {
                self.blocks[0].close.pop();
                if self.blocks[0].close.is_empty() {
                    return self.process_block();
                } else {
                    self.blocks[0].content.push(line);
                    return Ok(Empty);
                }
            } else {
                match line {
                    InputValue::Long(ref v) =>
                        if create_content(&mut v.clone()) == Ok(vec![]) {
                            self.blocks[0].close.push(InputValue::Short("}".to_string()));
                        },
                    _ => {}
                }
                self.blocks[0].content.push(line);
                // continue block
                return Ok(Empty);
            }
        }
    }

    pub fn input_to_vec(&mut self, input:Vec<InputValue>) -> Result<Vec<WashArgs>, String> {
        let mut out = vec![];
        // avoid O(n^2) situation
        let mut iter = reverse(input);
        let mut scope = vec![];
        let mut last_empty = false;
        loop {
            match iter.pop() {
                None => break,
                Some(InputValue::Short(ref name)) if self.has_handler(name) => {
                    while match get_nm_index(&iter, iter.len() - 1) {
                        Some(&InputValue::Split(_)) => true,
                        _ => false
                    } {
                        // skip any splits after the handle sequence
                        iter.pop();
                    }
                    // produce a correct scope for the handler
                    scope.clear();
                    while match get_nm_index(&iter, iter.len() - 1) {
                        None => false,
                        Some(&InputValue::Split(ref ns)) if self.has_handler(ns) => false,
                        Some(_) => true
                    } {
                        // doing this means scope will be in the same order as input
                        scope.push(iter.pop().unwrap());
                    }
                    // this can change out and scope, be careful
                    match self.run_handler(name, &mut out, &mut scope) {
                        Ok(Stop) => return Err(STOP.to_string()),
                        Ok(More(block)) => {
                            // start of a block
                            self.blocks.push(block);
                            return Ok(vec![]);
                        },
                        Ok(Continue) => {/* continue */},
                        Err(e) => return Err(e) // this is an error
                    }
                    // push remaining scope back onto iter
                    loop {
                        match scope.pop() {
                            None => break,
                            Some(v) => iter.push(v)
                        }
                    }
                },
                Some(v) => {
                    match try!(self.input_to_args(v.clone())) {
                        Empty if !last_empty => last_empty = true,
                        Empty => out.push(Empty),
                        new => {
                            out.push(new);
                            last_empty = false;
                        }
                    }
                }
            };
        }
        return Ok(out);
    }

    pub fn input_to_args(&mut self, input:InputValue) -> Result<WashArgs, String> {
        match input {
            InputValue::Function(n, a) => {
                let vec = try!(self.input_to_vec(a));
                return self.process_function(n, vec);
            },
            InputValue::Long(a) => {
                return Ok(Long(try!(self.input_to_vec(a))));
            },
            // the special cases with regex make for more informative errors
            InputValue::Short(ref s) if VAR_PATH_REGEX.is_match(s.as_slice()) => {
                let caps = VAR_PATH_REGEX.captures(s.as_slice()).unwrap();
                let path = caps.at(1).unwrap().to_string();
                let name = caps.at(2).unwrap().to_string();
                if name.is_empty() {
                    if path.is_empty() {
                        return self.env.getall();
                    } else {
                        return self.env.getallp(&path);
                    }
                } else {
                    return self.env.getvp(&name, &path);
                }
            },
            InputValue::Short(ref s) if VAR_REGEX.is_match(s.as_slice()) => {
                let caps = VAR_REGEX.captures(s.as_slice()).unwrap();
                let name = caps.at(1).unwrap().to_string();
                return self.env.getv(&name);
            },
            InputValue::Short(ref s) if s.is_empty() => return Ok(Empty),
            InputValue::Short(s) | InputValue::Literal(s) => return Ok(Flat(s)),
            InputValue::Split(_) => return Ok(Empty)
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::sync::RWLock;
use std::collections::HashMap;
use collections::hash::Hash;
use core::cmp::Eq;
use super::SessionStore;

type Store<K, V> = RWLock<HashMap<K, RWLock<V>>>;

/// A default implementation of `SessionStore`.
///
/// Session store implemented as a read-write-locked `HashMap`.
///
/// #### To use:
/// ```ignore
/// // When defining your server:
/// server.link(Sessions::new(key_gen_fn, Session::<KeyType, ValueType>::new()));
///
/// // When accessing from your middleware:
/// let session = alloy.find_mut::<Session<KeyType, ValueType>>().unwrap();
/// ```
pub struct Session<K, V>{
    key: Option<K>,
    store: Arc<Store<K, V>>
}

impl<K: Clone + Send, V: Send> Clone for Session<K, V> {
    fn clone(&self) -> Session<K, V> {
        Session {
            key: self.key.clone(),
            store: self.store.clone()
        }
    }
}

impl<K: Hash + Eq + Send + Share, V: Send + Share> Session<K, V> {
    /// Create a new instance of the session store
    pub fn new() -> Session<K, V> {
        Session {
            key: None,
            store: Arc::new(RWLock::new(HashMap::<K, RWLock<V>>::new()))
        }
    }
}

/* A note on clones:
 *
 * Those values hidden behind a RWLock are owned behind that lock.
 * In order for them to be accessed, a reference to the two gating locks
 * (the HashMap and the keyed V) must be kept alive.
 *
 * Instead, all values returned are copies.
 */
impl<K: Hash + Eq + Send + Share + Clone, V: Send + Share + Clone> SessionStore<K, V> for Session<K, V> {
    fn select_session(&mut self, key: K) { self.key = Some(key); }
    fn insert(&self, val: V) {
        let key = self.key.as_ref().unwrap();
        // Avoid a WriteLock if possible
        if !self.store.read().contains_key(key) {
            // Inserting consumes a key => clone()
            self.store.write().insert(key.clone(), RWLock::new(val));
        }
    }
    fn find(&self) -> Option<V> {
        let key = self.key.as_ref().unwrap();
        match self.store.read().find(key) {
            Some(lock) => Some(lock.read().clone()),
            None => None
        }
    }
    fn swap(&self, value: V) -> Option<V> {
        let key = self.key.as_ref().unwrap();
        match self.store.read().find(key) {
            // Instead of using swap, which requires a write lock on the HashMap,
            // only take the write locks when the key does not yet exist
            Some(lock) => {
                let old_v = lock.read().clone();
                *lock.write() = value;
                Some(old_v)
            },
            None       => {
                self.insert(value);
                None
            }
        }
    }
    fn upsert(&self, value: V, mutator: |&mut V|) -> V {
        let key = self.key.as_ref().unwrap();
        match self.store.read().find(key) {
            Some(lock) => {
                let old_v = &mut *lock.write();
                mutator(old_v);
                old_v.clone()
            },
            None => {
                self.insert(value.clone());
                value
            }
        }
    }
    fn remove(&self) -> bool {
        let key = self.key.as_ref().unwrap();
        self.store.write().remove(key)
    }
}
<commit_msg>(test) Default Session.<commit_after>use std::sync::{Arc, RWLock};
use std::collections::HashMap;
use collections::hash::Hash;
use core::cmp::Eq;
use super::SessionStore;

type Store<K, V> = RWLock<HashMap<K, RWLock<V>>>;

/// A default implementation of `SessionStore`.
///
/// Session store implemented as a read-write-locked `HashMap`.
///
/// #### To use:
/// ```ignore
/// // When defining your server:
/// server.link(Sessions::new(key_gen_fn, Session::<KeyType, ValueType>::new()));
///
/// // When accessing from your middleware:
/// let session = alloy.find_mut::<Session<KeyType, ValueType>>().unwrap();
/// ```
pub struct Session<K, V>{
    key: Option<K>,
    store: Arc<Store<K, V>>
}

impl<K: Clone + Send, V: Send> Clone for Session<K, V> {
    fn clone(&self) -> Session<K, V> {
        Session {
            key: self.key.clone(),
            store: self.store.clone()
        }
    }
}

impl<K: Hash + Eq + Send + Share, V: Send + Share> Session<K, V> {
    /// Create a new instance of the session store
    pub fn new() -> Session<K, V> {
        Session {
            key: None,
            store: Arc::new(RWLock::new(HashMap::<K, RWLock<V>>::new()))
        }
    }
}

/* A note on clones:
 *
 * Those values hidden behind a RWLock are owned behind that lock.
 * In order for them to be accessed, a reference to the two gating locks
 * (the HashMap and the keyed V) must be kept alive.
 *
 * Instead, all values returned are copies.
 */
impl<K: Hash + Eq + Send + Share + Clone, V: Send + Share + Clone> SessionStore<K, V> for Session<K, V> {
    fn select_session(&mut self, key: K) { self.key = Some(key); }
    fn insert(&self, val: V) {
        let key = self.key.as_ref().unwrap();
        // Avoid a WriteLock if possible
        if !self.store.read().contains_key(key) {
            // Inserting consumes a key => clone()
            self.store.write().insert(key.clone(), RWLock::new(val));
        }
    }
    fn find(&self) -> Option<V> {
        let key = self.key.as_ref().unwrap();
        match self.store.read().find(key) {
            Some(lock) => Some(lock.read().clone()),
            None => None
        }
    }
    fn swap(&self, value: V) -> Option<V> {
        let key = self.key.as_ref().unwrap();
        match self.store.read().find(key) {
            // Instead of using swap, which requires a write lock on the HashMap,
            // only take the write locks when the key does not yet exist
            Some(lock) => {
                let old_v = lock.read().clone();
                *lock.write() = value;
                return Some(old_v)
            },
            None => ()
        }
        self.insert(value);
        None
    }
    fn upsert(&self, value: V, mutator: |&mut V|) -> V {
        let key = self.key.as_ref().unwrap();
        match self.store.read().find(key) {
            Some(lock) => {
                let old_v = &mut *lock.write();
                mutator(old_v);
                return old_v.clone()
            },
            None => ()
        }
        self.insert(value.clone());
        value
    }
    fn remove(&self) -> bool {
        let key = self.key.as_ref().unwrap();
        self.store.write().remove(key)
    }
}

#[cfg(test)]
mod test {
    pub use super::*;
    pub use super::super::*;
    pub use super::super::super::sessions::*;
    pub use iron::*;
    pub use iron::middleware::*;
    pub use std::mem::uninitialized;

    pub fn set_server() -> ServerT {
        let mut test_server: ServerT = Iron::new();
        test_server.link(Sessions::new(get_session_id, Session::<char, char>::new()));
        test_server
    }
    pub fn run_server(mut server: ServerT) {
        unsafe {
            let _ = server.chain.dispatch(
                uninitialized(),
                uninitialized(),
                None
            );
        }
    }

    pub fn get_session_id(_: &Request, _: &Alloy) -> char {'a'}

    pub fn set_session_to_a(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        session.insert('a');
    }
    pub fn set_session_to_b(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        session.insert('b');
    }
    pub fn swap_session_to_b(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        session.swap('b');
    }
    pub fn upsert_session(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        let _ = session.upsert('b', |c: &mut char| *c = 'a');
    }
    pub fn remove_session(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        session.remove();
    }
    pub fn check_session_is_not_set(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        assert_eq!(session.find(), None)
    }
    pub fn check_session_is_set_to_a(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        assert_eq!(session.find(), Some('a'))
    }
    pub fn check_session_is_set_to_b(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
        let session = alloy.find::<Session<char, char>>().unwrap();
        assert_eq!(session.find(), Some('b'))
    }

    mod enter {
        pub use super::*;

        #[test]
        fn starts_with_empty_session() {
            let mut test_server = set_server();
            test_server.link(check_session_is_not_set);
            run_server(test_server);
        }

        #[test]
        fn finds_session() {
            let mut test_server = set_server();
            test_server.link(set_session_to_a);
            test_server.link(check_session_is_set_to_a);
            run_server(test_server);
        }

        mod swap {
            use super::*;

            #[test]
            fn swaps_session_when_empty() {
                let mut test_server = set_server();
                test_server.link(swap_session_to_b);
                test_server.link(check_session_is_set_to_b);
                run_server(test_server);
            }

            #[test]
            fn swaps_session_when_non_empty() {
                let mut test_server = set_server();
                test_server.link(set_session_to_a);
                test_server.link(swap_session_to_b);
                test_server.link(check_session_is_set_to_b);
                run_server(test_server);
            }

            #[test]
            fn swaps_session_when_same_valued() {
                let mut test_server = set_server();
                test_server.link(set_session_to_b);
                test_server.link(swap_session_to_b);
                test_server.link(check_session_is_set_to_b);
                run_server(test_server);
            }
        }

        mod upsert {
            use super::*;

            #[test]
            fn inserts_session_when_empty() {
                let mut test_server = set_server();
                test_server.link(upsert_session);
                test_server.link(check_session_is_set_to_b);
                run_server(test_server);
            }

            #[test]
            fn mutates_session_when_non_empty() {
                let mut test_server = set_server();
                test_server.link(set_session_to_b);
                test_server.link(upsert_session);
                test_server.link(check_session_is_set_to_a);
                run_server(test_server);
            }
        }

        #[test]
        fn removes_session() {
            let mut test_server = set_server();
            test_server.link(set_session_to_a);
            test_server.link(check_session_is_set_to_a);
            test_server.link(remove_session);
            test_server.link(check_session_is_not_set);
            run_server(test_server);
        }
    }
}
<|endoftext|>


<commit_before>extern crate base64;

use self::base64::encode;
use http::retrieve_asset;
use regex::Regex;
use std::collections::HashMap;
use url::{ParseError, Url};

/// This monster of a regex is used to match any kind of URL found in a CSS
/// stylesheet.
///
/// There's roughly three different categories that a found url could fit into:
///    - Font       [found after a src: property in an @font-family rule]
///    - Stylesheet [denoted by an @import before the url
///    - Image      [covers all other uses of the url() function]
///
/// This regex aims to extract the following information:
///    - What type of URL is it (font/image/css)
///    - Where is the part that needs to be replaced (incl any wrapping quotes)
///    - What is the URL (excl any wrapping quotes)
///
/// For understandablility, the regex can be broken down into two parts:
///
/// `(?:(?P<import>@import)|(?P<font>src\s*:)\s+)?`
/// This matches the precursor to a font or css url, and fills in a match under
/// either `<import>` (if it's a css url) or `<font>` (if it's a font).
/// Determining whether or not it's an image can be done by the negation of both
/// of these.  Either zero or one of these can match.
///
/// `url\((?P<to_repl>['"]?(?P<url>[^"'\)]+)['"]?)\)`
/// This matches the actual URL part of the url, and must always match.  It also
/// sets `<to_repl>` and `<url>` which correspond to everything within
/// `url(...)` and a usable URL, respectively.
///
/// Note, however, that this does not perform any validation of the found URL.
/// Malformed CSS could lead to an invalid URL being present.  It is therefor
/// recomended that the URL is manually validated.
const CSS_URL_REGEX_STR: &str =
    r###"(?:(?:(?P


<commit_before>#![macro_use]

use std::ffi::CStr;
use std::mem;
use std::time::{Duration, Instant};

use gl;
use gl::types::GLubyte;

use log::{debug, info, error};

pub fn elapsed(start_time: Instant) -> String {
    let elapsed = start_time.elapsed();
    format_duration(elapsed)
}

fn format_duration(duration: Duration) -> String {
    let secs = duration.as_secs();
    let nanos = duration.subsec_nanos();
    let ms = f64::from(nanos) / 1_000_000.0;
    if secs > 0 {
        let secs = secs as f64 + ms / 1000.0;
        format!("{:<4.*} s", 1, secs)
    }
    else {
        let places =
            if ms >= 20.0      { 0 }
            else if ms >= 1.0  { 1 }
            else {
                let micros = f64::from(nanos) / 1000.0;
                let places = if micros >= 10.0 { 0 } else { 2 };
                return format!("{:>3.*} µs", places, micros)
            };
        format!("{:>3.*} ms", places, ms)
    }
}

pub fn print_elapsed(message: &str, start_time: Instant) {
    info!("{:<25}{}", message, elapsed(start_time));
}

pub struct FrameTimer {
    message: String,
    averaging_window: usize,
    current_frame_start: Instant,
    pub frame_times: Vec<Duration>,
}

/// Timing helper that averages timings over `averaging_window`
// frames and then prints avg/min/max
impl FrameTimer {
    pub fn new(message: &str, averaging_window: usize) -> FrameTimer {
        FrameTimer {
            message: message.to_owned(),
            averaging_window,
            current_frame_start: Instant::now(),
            frame_times: Vec::with_capacity(averaging_window),
        }
    }

    pub fn start(&mut self) {
        self.current_frame_start = Instant::now();
    }

    pub fn end(&mut self) {
        self.frame_times.push(self.current_frame_start.elapsed());
        if self.frame_times.len() == self.averaging_window {
            self.print_and_reset();
        }
    }

    pub fn print_and_reset(&mut self) {
        {
            let avg = self.frame_times.iter().sum::<Duration>() / self.frame_times.len() as u32;
            let min = self.frame_times.iter().min().unwrap();
            let max = self.frame_times.iter().max().unwrap();
            info!("{:<15}{} (min: {}, max: {})", self.message,
                format_duration(avg), format_duration(*min), format_duration(*max));
        }
        self.frame_times.clear();
    }
}

pub unsafe fn gl_check_error(file: &str, line: u32) -> u32 {
    let mut error_code = gl::GetError();
    while error_code != gl::NO_ERROR {
        let error = match error_code {
            gl::INVALID_ENUM => "INVALID_ENUM",
            gl::INVALID_VALUE => "INVALID_VALUE",
            gl::INVALID_OPERATION => "INVALID_OPERATION",
            gl::STACK_OVERFLOW => "STACK_OVERFLOW",
            gl::STACK_UNDERFLOW => "STACK_UNDERFLOW",
            gl::OUT_OF_MEMORY => "OUT_OF_MEMORY",
            gl::INVALID_FRAMEBUFFER_OPERATION => "INVALID_FRAMEBUFFER_OPERATION",
            _ => "unknown GL error code"
        };

        error!("{} | {} ({})", error, file, line);

        error_code = gl::GetError();
    }
    error_code
}

#[allow(unused_macros)]
macro_rules! gl_check_error {
    () => (
        gl_check_error(file!(), line!())
    )
}

/// Prints information about the current OpenGL context
/// Based on glium's `context::capabilities::get_capabilities`
pub unsafe fn print_context_info() {
    debug!("Renderer     : {}", gl_string(gl::GetString(gl::RENDERER)));
    debug!("Vendor       : {}", gl_string(gl::GetString(gl::VENDOR)));
    debug!("Version      : {}", gl_string(gl::GetString(gl::VERSION)));
    debug!("GLSL         : {}", gl_string(gl::GetString(gl::SHADING_LANGUAGE_VERSION)));

    let mut val = mem::MaybeUninit::uninit();
    gl::GetIntegerv(gl::CONTEXT_PROFILE_MASK, val.as_mut_ptr());
    let val = val.assume_init() as gl::types::GLenum;
    let profile = if (val & gl::CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0 {
        "Compatibility"
    } else if (val & gl::CONTEXT_CORE_PROFILE_BIT) != 0 {
        "Core"
    } else {
        "None"
    };
    debug!("Profile      : {}", profile);

    let (debug, forward_compatible) = {
        let mut val = mem::MaybeUninit::uninit();
        gl::GetIntegerv(gl::CONTEXT_FLAGS, val.as_mut_ptr());
        let val = val.assume_init() as gl::types::GLenum;
        ((val & gl::CONTEXT_FLAG_DEBUG_BIT) != 0,
         (val & gl::CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) != 0)
    };
    debug!("Context Flags: Debug: {}, Forward Compatible: {}", debug, forward_compatible);

    let mut num_extensions = 0;
    gl::GetIntegerv(gl::NUM_EXTENSIONS, &mut num_extensions);
    let extensions: Vec<_> = (0 .. num_extensions).map(|num| {
        gl_string(gl::GetStringi(gl::EXTENSIONS, num as gl::types::GLuint))
    }).collect();
    debug!("Extensions   : {}", extensions.join(", "))
}

pub unsafe fn gl_string(raw_string: *const GLubyte) -> String {
    if raw_string.is_null() { return "(NULL)".into() }
    String::from_utf8(CStr::from_ptr(raw_string as *const _).to_bytes().to_vec())
                                .expect("gl_string: non-UTF8 string")
}
<commit_msg>remove use of MaybeUninit<commit_after>#![macro_use]

use std::ffi::CStr;
use std::time::{Duration, Instant};

use gl;
use gl::types::GLubyte;

use log::{debug, info, error};

pub fn elapsed(start_time: Instant) -> String {
    let elapsed = start_time.elapsed();
    format_duration(elapsed)
}

fn format_duration(duration: Duration) -> String {
    let secs = duration.as_secs();
    let nanos = duration.subsec_nanos();
    let ms = f64::from(nanos) / 1_000_000.0;
    if secs > 0 {
        let secs = secs as f64 + ms / 1000.0;
        format!("{:<4.*} s", 1, secs)
    }
    else {
        let places =
            if ms >= 20.0      { 0 }
            else if ms >= 1.0  { 1 }
            else {
                let micros = f64::from(nanos) / 1000.0;
                let places = if micros >= 10.0 { 0 } else { 2 };
                return format!("{:>3.*} µs", places, micros)
            };
        format!("{:>3.*} ms", places, ms)
    }
}

pub fn print_elapsed(message: &str, start_time: Instant) {
    info!("{:<25}{}", message, elapsed(start_time));
}

pub struct FrameTimer {
    message: String,
    averaging_window: usize,
    current_frame_start: Instant,
    pub frame_times: Vec<Duration>,
}

/// Timing helper that averages timings over `averaging_window`
// frames and then prints avg/min/max
impl FrameTimer {
    pub fn new(message: &str, averaging_window: usize) -> FrameTimer {
        FrameTimer {
            message: message.to_owned(),
            averaging_window,
            current_frame_start: Instant::now(),
            frame_times: Vec::with_capacity(averaging_window),
        }
    }

    pub fn start(&mut self) {
        self.current_frame_start = Instant::now();
    }

    pub fn end(&mut self) {
        self.frame_times.push(self.current_frame_start.elapsed());
        if self.frame_times.len() == self.averaging_window {
            self.print_and_reset();
        }
    }

    pub fn print_and_reset(&mut self) {
        {
            let avg = self.frame_times.iter().sum::<Duration>() / self.frame_times.len() as u32;
            let min = self.frame_times.iter().min().unwrap();
            let max = self.frame_times.iter().max().unwrap();
            info!("{:<15}{} (min: {}, max: {})", self.message,
                format_duration(avg), format_duration(*min), format_duration(*max));
        }
        self.frame_times.clear();
    }
}

pub unsafe fn gl_check_error(file: &str, line: u32) -> u32 {
    let mut error_code = gl::GetError();
    while error_code != gl::NO_ERROR {
        let error = match error_code {
            gl::INVALID_ENUM => "INVALID_ENUM",
            gl::INVALID_VALUE => "INVALID_VALUE",
            gl::INVALID_OPERATION => "INVALID_OPERATION",
            gl::STACK_OVERFLOW => "STACK_OVERFLOW",
            gl::STACK_UNDERFLOW => "STACK_UNDERFLOW",
            gl::OUT_OF_MEMORY => "OUT_OF_MEMORY",
            gl::INVALID_FRAMEBUFFER_OPERATION => "INVALID_FRAMEBUFFER_OPERATION",
            _ => "unknown GL error code"
        };

        error!("{} | {} ({})", error, file, line);

        error_code = gl::GetError();
    }
    error_code
}

#[allow(unused_macros)]
macro_rules! gl_check_error {
    () => (
        gl_check_error(file!(), line!())
    )
}

/// Prints information about the current OpenGL context
/// Based on glium's `context::capabilities::get_capabilities`
pub unsafe fn print_context_info() {
    debug!("Renderer     : {}", gl_string(gl::GetString(gl::RENDERER)));
    debug!("Vendor       : {}", gl_string(gl::GetString(gl::VENDOR)));
    debug!("Version      : {}", gl_string(gl::GetString(gl::VERSION)));
    debug!("GLSL         : {}", gl_string(gl::GetString(gl::SHADING_LANGUAGE_VERSION)));

    let mut val = 0;
    gl::GetIntegerv(gl::CONTEXT_PROFILE_MASK, &mut val);
    let val = val as gl::types::GLenum;
    let profile = if (val & gl::CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0 {
        "Compatibility"
    } else if (val & gl::CONTEXT_CORE_PROFILE_BIT) != 0 {
        "Core"
    } else {
        "None"
    };
    debug!("Profile      : {}", profile);

    let (debug, forward_compatible) = {
        let mut val = 0;
        gl::GetIntegerv(gl::CONTEXT_FLAGS, &mut val);
        let val = val as gl::types::GLenum;
        ((val & gl::CONTEXT_FLAG_DEBUG_BIT) != 0,
         (val & gl::CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) != 0)
    };
    debug!("Context Flags: Debug: {}, Forward Compatible: {}", debug, forward_compatible);

    let mut num_extensions = 0;
    gl::GetIntegerv(gl::NUM_EXTENSIONS, &mut num_extensions);
    let extensions: Vec<_> = (0 .. num_extensions).map(|num| {
        gl_string(gl::GetStringi(gl::EXTENSIONS, num as gl::types::GLuint))
    }).collect();
    debug!("Extensions   : {}", extensions.join(", "))
}

pub unsafe fn gl_string(raw_string: *const GLubyte) -> String {
    if raw_string.is_null() { return "(NULL)".into() }
    String::from_utf8(CStr::from_ptr(raw_string as *const _).to_bytes().to_vec())
                                .expect("gl_string: non-UTF8 string")
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::ops::Deref;
use libusb::{
    LogLevel,
    Context,
    DeviceHandle,
    AsyncGroup,
    Result as UsbResult,
    Error,
};

use consts;

pub struct UsbWrapper {
    context: &'static Context,
    pub handle: &'static DeviceHandle<'static>,
    has_kernel_driver0: bool,
    has_kernel_driver1: bool,
    pub async_group: &'static mut AsyncGroup<'static>,
}

impl UsbWrapper {
    pub fn new() -> UsbResult<UsbWrapper> {
        // We must leak both context and handle and async_group, as rust does not allow sibling structs.
        // Leaking them gives us a &'static reference, which we can then use without
        // lifetime bounds, as it outlives everything.
        // We must make sure though, that the leaked memory is freed afterwards,
        // which is done in Drop.
        let context = try!(get_context());
        let context_ptr = Box::into_raw(Box::new(context));
        let context_ref = unsafe { &*context_ptr as &'static Context };
        let (handle, driver0, driver1) = try!(get_handle(context_ref));
        let async_group = AsyncGroup::new(context_ref);
        let handle_ptr = Box::into_raw(Box::new(handle));
        let async_ptr = Box::into_raw(Box::new(async_group));
        unsafe {
            Ok(UsbWrapper {
                context: context_ref,
                handle: &mut *handle_ptr as &'static mut DeviceHandle<'static>,
                has_kernel_driver0: driver0,
                has_kernel_driver1: driver1,
                async_group: &mut *async_ptr as &'static mut AsyncGroup<'static>,
            })
        }
    }
}

impl Drop for UsbWrapper {
    fn drop(&mut self) {
        // make sure handle_mut is dropped before dropping it's refering content
        // this assures that there will be no dangling pointers
        {
            let handle_mut = unsafe { &mut *(self.handle as *const _ as *mut DeviceHandle<'static>) };
            handle_mut.release_interface(1).unwrap();
            handle_mut.release_interface(0).unwrap();
            if self.has_kernel_driver1 {
                handle_mut.attach_kernel_driver(1).unwrap();
            }
            if self.has_kernel_driver0 {
                handle_mut.attach_kernel_driver(0).unwrap();
            }
        }
        // first, drop async_group to release all captured references to the DeviceHandle
        let async_ptr = &mut *self.async_group as *mut AsyncGroup<'static>;
        drop(unsafe { Box::from_raw(async_ptr) });
        // then, drop the DeviceHandle to release Context
        let handle_ptr = &*self.handle as *const _ as *mut DeviceHandle<'static>;
        drop(unsafe { Box::from_raw(handle_ptr) });
        let context_ptr = self.context as *const _ as *mut Context;
        drop(unsafe { Box::from_raw(context_ptr) });
    }
}

impl Borrow<DeviceHandle<'static>> for UsbWrapper {
    fn borrow(&self) -> &DeviceHandle<'static> {
        self.handle
    }
}

impl Deref for UsbWrapper {
    type Target = DeviceHandle<'static>;
    fn deref(&self) -> &DeviceHandle<'static> {
        &self.handle
    }
}

fn get_context() -> UsbResult<Context> {
    let mut context = try!(Context::new());
    context.set_log_level(LogLevel::Debug);
    context.set_log_level(LogLevel::Info);
    context.set_log_level(LogLevel::Warning);
    context.set_log_level(LogLevel::Error);
    context.set_log_level(LogLevel::None);
    return Ok(context);
}

fn get_handle<'a>(context: &'a Context) -> UsbResult<(DeviceHandle<'a>, bool, bool)> {
    let devices = try!(context.devices());
    for d in devices.iter() {
        let dd = match d.device_descriptor() {
            Ok(dd) => dd,
            Err(_) => continue
        };
        if dd.vendor_id() == consts::VENDOR_ID && dd.product_id() == consts::PRODUCT_ID {
            let mut handle = try!(d.open());
            // for some reason we cannot claim interface 2 as it doesn't exist
            // but we will be able to read from it, if we claim interface 1
            // detch kernel driver
            let has_kernel_driver0 = try!(detach(&mut handle, 0));
            let has_kernel_driver1 = try!(detach(&mut handle, 1));
            // claim interfaces
            try!(handle.claim_interface(0));
            try!(handle.claim_interface(1));
            // reset keyboard to get clean status
            try!(handle.reset());
            return Ok((handle, has_kernel_driver0, has_kernel_driver1));
        }
    }
    return Err(Error::NoDevice);
}

fn detach(handle: &mut DeviceHandle, iface: u8) -> UsbResult<bool> {
    match handle.kernel_driver_active(iface) {
        Ok(true) => {
            try!(handle.detach_kernel_driver(iface));
            Ok(true)
        },
        _ => Ok(false)
    }

}

<commit_msg>ref(utils): Remove unnessecary Borrow and Deref and add unwrap_safe! for unwrap in drop<commit_after>use libusb::{
    LogLevel,
    Context,
    DeviceHandle,
    AsyncGroup,
    Result as UsbResult,
    Error,
};

use consts;

pub struct UsbWrapper {
    context: &'static Context,
    pub handle: &'static DeviceHandle<'static>,
    has_kernel_driver0: bool,
    has_kernel_driver1: bool,
    pub async_group: &'static mut AsyncGroup<'static>,
}

impl UsbWrapper {
    pub fn new() -> UsbResult<UsbWrapper> {
        // We must leak both context and handle and async_group, as rust does not allow sibling structs.
        // Leaking them gives us a &'static reference, which we can then use without
        // lifetime bounds, as it outlives everything.
        // We must make sure though, that the leaked memory is freed afterwards,
        // which is done in Drop.
        let context = try!(get_context());
        let context_ptr = Box::into_raw(Box::new(context));
        let context_ref = unsafe { &*context_ptr as &'static Context };
        let (handle, driver0, driver1) = try!(get_handle(context_ref));
        let async_group = AsyncGroup::new(context_ref);
        let handle_ptr = Box::into_raw(Box::new(handle));
        let async_ptr = Box::into_raw(Box::new(async_group));
        unsafe {
            Ok(UsbWrapper {
                context: context_ref,
                handle: &mut *handle_ptr as &'static mut DeviceHandle<'static>,
                has_kernel_driver0: driver0,
                has_kernel_driver1: driver1,
                async_group: &mut *async_ptr as &'static mut AsyncGroup<'static>,
            })
        }
    }
}

macro_rules! unwrap_safe {
    ($e:expr) => {
        if ::std::thread::panicking() {
            match $e {
                Ok(_) => {},
                Err(e) => println!("Error while dropping UsbWrapper during another panic: {:?}", e),
            }
        } else {
            $e.unwrap();
        }
    }
}

impl Drop for UsbWrapper {
    fn drop(&mut self) {
        // make sure handle_mut is dropped before dropping it's refering content
        // this assures that there will be no dangling pointers
        {
            let handle_mut = unsafe { &mut *(self.handle as *const _ as *mut DeviceHandle<'static>) };
            unwrap_safe!(handle_mut.release_interface(1));
            unwrap_safe!(handle_mut.release_interface(0));
            if self.has_kernel_driver1 {
                unwrap_safe!(handle_mut.attach_kernel_driver(1));
            }
            if self.has_kernel_driver0 {
                unwrap_safe!(handle_mut.attach_kernel_driver(0));
            }
        }
        // first, drop async_group to release all captured references to the DeviceHandle
        let async_ptr = &mut *self.async_group as *mut AsyncGroup<'static>;
        drop(unsafe { Box::from_raw(async_ptr) });
        // then, drop the DeviceHandle to release Context
        let handle_ptr = &*self.handle as *const _ as *mut DeviceHandle<'static>;
        drop(unsafe { Box::from_raw(handle_ptr) });
        let context_ptr = self.context as *const _ as *mut Context;
        drop(unsafe { Box::from_raw(context_ptr) });
    }
}

fn get_context() -> UsbResult<Context> {
    let mut context = try!(Context::new());
    context.set_log_level(LogLevel::Debug);
    context.set_log_level(LogLevel::Info);
    context.set_log_level(LogLevel::Warning);
    context.set_log_level(LogLevel::Error);
    context.set_log_level(LogLevel::None);
    Ok(context)
}

fn get_handle<'a>(context: &'a Context) -> UsbResult<(DeviceHandle<'a>, bool, bool)> {
    let devices = try!(context.devices());
    for d in devices.iter() {
        let dd = match d.device_descriptor() {
            Ok(dd) => dd,
            Err(_) => continue
        };
        if dd.vendor_id() == consts::VENDOR_ID && dd.product_id() == consts::PRODUCT_ID {
            let mut handle = try!(d.open());
            // for some reason we cannot claim interface 2 as it doesn't exist
            // but we will be able to read from it, if we claim interface 1
            // detch kernel driver
            let has_kernel_driver0 = try!(detach(&mut handle, 0));
            let has_kernel_driver1 = try!(detach(&mut handle, 1));
            // claim interfaces
            try!(handle.claim_interface(0));
            try!(handle.claim_interface(1));
            // reset keyboard to get clean status
            try!(handle.reset());
            return Ok((handle, has_kernel_driver0, has_kernel_driver1));
        }
    }
    Err(Error::NoDevice)
}

fn detach(handle: &mut DeviceHandle, iface: u8) -> UsbResult<bool> {
    match handle.kernel_driver_active(iface) {
        Ok(true) => {
            try!(handle.detach_kernel_driver(iface));
            Ok(true)
        },
        _ => Ok(false)
    }

}

<|endoftext|>


<commit_before>
extern crate net2;
extern crate byteorder;

use std::net::TcpStream;
use self::byteorder::WriteBytesExt;
use self::net2::TcpStreamExt;

use fcall::*;
use error;
use serialize;
use std::time::Duration;

pub type Result<T> = ::std::result::Result<T, error::Error>;

#[macro_export]
macro_rules! io_error {
    ($kind:ident, $msg:expr) => {
        Err(::std::io::Error::new(::std::io::ErrorKind::$kind, $msg))
    }
}

// return: (proto, addr:port)
pub fn parse_proto(arg: &str) -> ::std::result::Result<(&str, String), ()> {
    let mut split = arg.split("!");
    let proto = try!(split.nth(0).ok_or(()));
    let addr  = try!(split.nth(0).ok_or(()));
    let port  = try!(split.nth(0).ok_or(()));
    Ok((proto, addr.to_owned() + ":" + port))
}

// See also: diod/libdiod/diod_sock.c
pub fn setup_tcp_stream(stream: &TcpStream) -> ::std::io::Result<()> {
    try!(TcpStreamExt::set_nodelay(stream, true));
    TcpStreamExt::set_keepalive(stream, Some(Duration::from_secs(120)))
}

pub fn respond<WExt: WriteBytesExt>(stream: &mut WExt, res: Fcall, tag: u16) -> Result<MsgType> {
    let msg_type = match res {
        // 9P2000.L
        Fcall::Rlerror { .. }       => MsgType::Rlerror,
        Fcall::Rstatfs { .. }       => MsgType::Rstatfs,
        Fcall::Rlopen { .. }        => MsgType::Rlopen,
        Fcall::Rlcreate { .. }      => MsgType::Rlcreate,
        Fcall::Rsymlink { .. }      => MsgType::Rsymlink,
        Fcall::Rmknod { .. }        => MsgType::Rmknod,
        Fcall::Rrename              => MsgType::Rrename,
        Fcall::Rreadlink { .. }     => MsgType::Rreadlink,
        Fcall::Rgetattr { .. }      => MsgType::Rgetattr,
        Fcall::Rsetattr             => MsgType::Rsetattr,
        Fcall::Rxattrwalk { .. }    => MsgType::Rxattrwalk,
        Fcall::Rxattrcreate         => MsgType::Rxattrcreate,
        Fcall::Rreaddir { .. }      => MsgType::Rreaddir,
        Fcall::Rfsync               => MsgType::Rfsync,
        Fcall::Rlock { .. }         => MsgType::Rlock,
        Fcall::Rgetlock { .. }      => MsgType::Rgetlock,
        Fcall::Rlink                => MsgType::Rlink,
        Fcall::Rmkdir { .. }        => MsgType::Rmkdir,
        Fcall::Rrenameat            => MsgType::Rrenameat,
        Fcall::Runlinkat            => MsgType::Runlinkat,

        // 9P2000.u
        Fcall::Rauth { .. }         => MsgType::Rauth,
        Fcall::Rattach { .. }       => MsgType::Rattach,

        // 9P2000
        Fcall::Rversion { .. }      => MsgType::Rversion,
        Fcall::Rflush               => MsgType::Rflush,
        Fcall::Rwalk { .. }         => MsgType::Rwalk,
        Fcall::Rread { .. }         => MsgType::Rread,
        Fcall::Rwrite { .. }        => MsgType::Rwrite,
        Fcall::Rclunk               => MsgType::Rclunk,
        Fcall::Rremove              => MsgType::Rremove,
        _ => return try!(io_error!(Other, "Invalid 9P message in this context")),
    };

    let msg = Msg { typ: msg_type, tag: tag, body: res };
    try!(serialize::write_msg(stream, &msg));

    Ok(msg_type)
}
<commit_msg>Temporary bug fix refusing connections<commit_after>
extern crate net2;
extern crate byteorder;

use std::net::TcpStream;
use self::byteorder::WriteBytesExt;
use self::net2::TcpStreamExt;

use fcall::*;
use error;
use serialize;
use std::time::Duration;

pub type Result<T> = ::std::result::Result<T, error::Error>;

#[macro_export]
macro_rules! io_error {
    ($kind:ident, $msg:expr) => {
        Err(::std::io::Error::new(::std::io::ErrorKind::$kind, $msg))
    }
}

// return: (proto, addr:port)
pub fn parse_proto(arg: &str) -> ::std::result::Result<(&str, String), ()> {
    let mut split = arg.split("!");
    let proto = try!(split.nth(0).ok_or(()));
    let addr  = try!(split.nth(0).ok_or(()));
    let port  = try!(split.nth(0).ok_or(()));
    Ok((proto, addr.to_owned() + ":" + port))
}

// See also: diod/libdiod/diod_sock.c
pub fn setup_tcp_stream(stream: &TcpStream) -> ::std::io::Result<()> {
    //try!(TcpStreamExt::set_nodelay(stream, true));
    //TcpStreamExt::set_keepalive(stream, Some(Duration::from_secs(120)))
    TcpStreamExt::set_nodelay(stream, true)
}

pub fn respond<WExt: WriteBytesExt>(stream: &mut WExt, res: Fcall, tag: u16) -> Result<MsgType> {
    let msg_type = match res {
        // 9P2000.L
        Fcall::Rlerror { .. }       => MsgType::Rlerror,
        Fcall::Rstatfs { .. }       => MsgType::Rstatfs,
        Fcall::Rlopen { .. }        => MsgType::Rlopen,
        Fcall::Rlcreate { .. }      => MsgType::Rlcreate,
        Fcall::Rsymlink { .. }      => MsgType::Rsymlink,
        Fcall::Rmknod { .. }        => MsgType::Rmknod,
        Fcall::Rrename              => MsgType::Rrename,
        Fcall::Rreadlink { .. }     => MsgType::Rreadlink,
        Fcall::Rgetattr { .. }      => MsgType::Rgetattr,
        Fcall::Rsetattr             => MsgType::Rsetattr,
        Fcall::Rxattrwalk { .. }    => MsgType::Rxattrwalk,
        Fcall::Rxattrcreate         => MsgType::Rxattrcreate,
        Fcall::Rreaddir { .. }      => MsgType::Rreaddir,
        Fcall::Rfsync               => MsgType::Rfsync,
        Fcall::Rlock { .. }         => MsgType::Rlock,
        Fcall::Rgetlock { .. }      => MsgType::Rgetlock,
        Fcall::Rlink                => MsgType::Rlink,
        Fcall::Rmkdir { .. }        => MsgType::Rmkdir,
        Fcall::Rrenameat            => MsgType::Rrenameat,
        Fcall::Runlinkat            => MsgType::Runlinkat,

        // 9P2000.u
        Fcall::Rauth { .. }         => MsgType::Rauth,
        Fcall::Rattach { .. }       => MsgType::Rattach,

        // 9P2000
        Fcall::Rversion { .. }      => MsgType::Rversion,
        Fcall::Rflush               => MsgType::Rflush,
        Fcall::Rwalk { .. }         => MsgType::Rwalk,
        Fcall::Rread { .. }         => MsgType::Rread,
        Fcall::Rwrite { .. }        => MsgType::Rwrite,
        Fcall::Rclunk               => MsgType::Rclunk,
        Fcall::Rremove              => MsgType::Rremove,
        _ => return try!(io_error!(Other, "Invalid 9P message in this context")),
    };

    let msg = Msg { typ: msg_type, tag: tag, body: res };
    try!(serialize::write_msg(stream, &msg));

    Ok(msg_type)
}
<|endoftext|>