<commit_before>use itertools::{multipeek,MultiPeek};
use std::str;

#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug)]
pub struct TokenWithContext {
    token: Token,
    // Takes a copy. Tokens can outlive the file they came from
    lexeme: String,
    line: usize,
}

struct Scanner<'a>{
    current: usize,
    current_lexeme: String,
    line: usize,
    source: MultiPeek<str::Chars<'a>>,
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl<'a> Scanner<'a> {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            current: 0,
            current_lexeme: "".into(),
            line: 1, // 1-indexed,
            source: multipeek(source.chars()),
        }
    }

    fn is_at_end(&mut self) -> bool {
        self.source.reset_peek();
        match self.source.peek(){
            Some(_) => false,
            None => true,
        }
    }

    fn peek(&mut self) -> char() {
        self.source.reset_peek();
        //TODO: this is dubious
        match self.source.peek(){
            Some(&c) => c,
            None => '\0',
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        //TODO: handle None!
        let c = self.source.next().unwrap();
        self.current_lexeme.push(c);
        if c == '\n' {
            self.line += 1;
        }
        c
    }

    fn is_match(&mut self, expected: char) -> bool {
        self.source.reset_peek();
        match self.source.peek(){
            Some(&c) => {
                if c == expected {
                    let _ = self.source.next();
                    self.current += 1;
                    true
                }
                else{
                    false
                }
            }
            None => false,
        }
    }

    fn add_context(&mut self, token: Token) -> TokenWithContext {
        let result = TokenWithContext {
            token: token,
            lexeme: self.current_lexeme.clone(),
            line: self.line,
        };
        self.current_lexeme = "".into();
        result
    }

    fn string(&mut self) -> Result<Token, String> {
        let initial_line = self.line;
        while self.peek() != '"' && !self.is_at_end() {
            self.advance();
        }
        if self.is_at_end() {
            return Err(format!("Unterminated string at line {}", initial_line));
        }
        self.advance();
        let literal_length = self.current_lexeme.len() - 2;
        // Trims delimiters
        let literal = self.current_lexeme.chars().skip(1).take(literal_length).collect();
        Ok(Token::StringLiteral(literal))
    }

    fn number(&mut self) -> Token {
        while is_digit(self.peek()) {
            self.advance();
        }
        // Here we do double lookahead
        self.source.reset_peek();
        match self.source.peek(){
            Some(&p1) =>{
                match self.source.peek() {
                    Some(&p2) => if p1 == '.' && is_digit(p2){
                        self.advance(); // Consume the .
                        while is_digit(self.peek()) {
                            self.advance();
                        }
                    },
                    None => (),
                }
            }
            None => (),
        }
        let value = self.current_lexeme.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        while is_alphanumeric(self.peek()) {
            self.advance();
        }
        // TODO: take a ref in the first place
        match self.current_lexeme.as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        let token = match self.advance() {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.is_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.is_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.is_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.is_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.is_match('/') {
                    // Comments go on till the end of the line
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Token::Comment
                } else {
                    Token::Slash
                }
            }
            '"' => try!(self.string()),
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                return Err(format!("Unexpected character {} at line {}, pos {}",
                                   c,
                                   self.line,
                                   self.current - 1));
            }
        };
        Ok(self.add_context(token))
    }
}

pub fn scan(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        let token_with_context = try!(scanner.scan_next());
        match token_with_context.token {
            // Ignoring tokens we don't care about
            Token::Comment => {}
            Token::Whitespace => {}
            _ => tokens.push(token_with_context),
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

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

    #[test]
    fn single_token() {
        let tokens = scan(&"+".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let tokens = scan(&"1+2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn expression_with_whitespaces() {
        let tokens = scan(&"1 + 2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn assignement_with_comment() {
        let tokens = scan(&"var a = 1.0; // A comment".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Eof);
    }

    #[test]
    fn multiline_statements() {
        let tokens = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
                .into())
            .unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[10].token, Token::Eof);
        assert_eq!(tokens[1].line, 1);
        assert_eq!(tokens[9].line, 2);
    }
}
<commit_msg>Using peek_check everywhere<commit_after>use itertools::{multipeek, MultiPeek};
use std::str;

#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug)]
pub struct TokenWithContext {
    token: Token,
    // Takes a copy. Tokens can outlive the file they came from
    lexeme: String,
    line: usize,
}

struct Scanner<'a> {
    current: usize,
    current_lexeme: String,
    line: usize,
    source: MultiPeek<str::Chars<'a>>,
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl<'a> Scanner<'a> {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            current: 0,
            current_lexeme: "".into(),
            line: 1, // 1-indexed,
            source: multipeek(source.chars()),
        }
    }

    fn is_at_end(&mut self) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(_) => false,
            None => true,
        }
    }

    fn peek_check(&mut self, check: &Fn(char) -> bool) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(&c) => check(c),
            None => false,
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        // TODO: handle None!
        let c = self.source.next().unwrap();
        self.current_lexeme.push(c);
        if c == '\n' {
            self.line += 1;
        }
        c
    }

    fn is_match(&mut self, expected: char) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(&c) => {
                if c == expected {
                    let _ = self.source.next();
                    self.current += 1;
                    true
                } else {
                    false
                }
            }
            None => false,
        }
    }

    fn add_context(&mut self, token: Token) -> TokenWithContext {
        let result = TokenWithContext {
            token: token,
            lexeme: self.current_lexeme.clone(),
            line: self.line,
        };
        self.current_lexeme = "".into();
        result
    }

    fn string(&mut self) -> Result<Token, String> {
        let initial_line = self.line;
        self.source.reset_peek();
        while match self.source.peek() {
            Some(&p) => p != '"',
            None => false,
        } {
            self.advance();
        }
        if self.is_at_end() {
            return Err(format!("Unterminated string at line {}", initial_line));
        }
        self.advance();
        let literal_length = self.current_lexeme.len() - 2;
        // Trims delimiters
        let literal = self.current_lexeme.chars().skip(1).take(literal_length).collect();
        Ok(Token::StringLiteral(literal))
    }

    fn number(&mut self) -> Token {
        while self.peek_check(&is_digit) {
            self.advance();
        }
        // Here we do double lookahead
        self.source.reset_peek();
        match self.source.peek() {
            Some(&p1) => {
                match self.source.peek() {
                    Some(&p2) => {
                        if p1 == '.' && is_digit(p2) {
                            self.advance(); // Consume the .
                            while self.peek_check(&is_digit) {
                                self.advance();
                            }
                        }
                    }
                    None => (),
                }
            }
            None => (),
        }
        let value = self.current_lexeme.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        while self.peek_check(&is_alphanumeric) {
            self.advance();
        }
        // TODO: take a ref in the first place
        match self.current_lexeme.as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        let token = match self.advance() {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.is_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.is_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.is_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.is_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.is_match('/') {
                    // Comments go on till the end of the line
                    while self.peek_check(&|c| c != '\n') {
                        self.advance();
                    }
                    Token::Comment
                } else {
                    Token::Slash
                }
            }
            '"' => try!(self.string()),
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                return Err(format!("Unexpected character {} at line {}, pos {}",
                                   c,
                                   self.line,
                                   self.current - 1));
            }
        };
        Ok(self.add_context(token))
    }
}

pub fn scan(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        let token_with_context = try!(scanner.scan_next());
        match token_with_context.token {
            // Ignoring tokens we don't care about
            Token::Comment => {}
            Token::Whitespace => {}
            _ => tokens.push(token_with_context),
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

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

    #[test]
    fn single_token() {
        let tokens = scan(&"+".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let tokens = scan(&"1+2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn expression_with_whitespaces() {
        let tokens = scan(&"1 + 2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn assignement_with_comment() {
        let tokens = scan(&"var a = 1.0; // A comment".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Eof);
    }

    #[test]
    fn multiline_statements() {
        let tokens = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
                .into())
            .unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[10].token, Token::Eof);
        assert_eq!(tokens[1].line, 1);
        assert_eq!(tokens[9].line, 2);
    }
}
<|endoftext|>


<commit_before>extern crate git2;
const TMP_NAME: &'static str = "refs/centralgit/tmp_fd2db5f8_bac2_4a1e_9487_4ac3414788aa";

use git2::*;
use std::process::Command;
use std::path::Path;
use shell::Shell;
use super::RepoHost;
use std::collections::HashMap;

pub struct Scratch<'a>
{
    pub repo: Repository,
    pub host: &'a RepoHost,
}

impl<'a> Scratch<'a>
{
    pub fn new(path: &Path, host: &'a RepoHost) -> Scratch<'a>
    {
        Scratch {
            repo: Repository::init_bare(&path).expect("could not init scratch"),
            host: host,
        }
    }

    pub fn tracking(&self, module: &str, branch: &str) -> Option<Object>
    {
        let remote_name = format!("{}", module);
        let fetch_url = self.host.local_path(&module);
        let mut remote = if let Ok(remote) = self.repo.find_remote(&remote_name) {
            remote
        }
        else {
            debug!("==== create remote (remote_name:{}, remote_url:{})",
                   &remote_name,
                   &fetch_url);
            self.repo.remote(&remote_name, &fetch_url).expect("can't create remote")
        };

        let rs = remote.get_refspec(0).unwrap().str().unwrap().to_string();
        if let Ok(_) = remote.fetch(&[&rs], None, None) {
            return self.repo
                .revparse_single(&format!("remotes/{}/{}", module, branch))
                .ok();
        }
        else {
            return None;
        }
    }

    // force push of the new revision-object to temp repo
    pub fn transfer(&self, rev: &str, source: &Path) -> Object
    {
        // TODO: implement using libgit
        let target = &self.repo.path();
        let shell = Shell { cwd: source.to_path_buf() };
        shell.command(&format!("git update-ref {} {}", TMP_NAME, rev));
        shell.command(&format!("git push --force {} {}",
                               &target.to_string_lossy(),
                               TMP_NAME));

        let obj = self.repo.revparse_single(rev).expect("can't find transfered ref");
        return obj;
    }

    // takes everything from base except it's tree and replaces it with the tree
    // given
    pub fn rewrite(&self, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid
    {
        if parents.len() == 0 {
            ::std::fs::remove_file(self.repo.path().join("HEAD")).expect("can't remove HEAD");
        }
        else {
            self.repo.set_head_detached(parents[0].id()).expect("rewrite: can't detach head");
        }
        self.repo
            .commit(Some("HEAD"),
                    &base.author(),
                    &base.committer(),
                    &base.message().unwrap_or("no message"),
                    tree,
                    parents)
            .expect("rewrite: can't commit")
    }

    pub fn push(&self, oid: Oid, module: &str, target: &str) -> String
    {
        let commit = &self.repo.find_commit(oid).expect("can't find commit");
        self.repo.set_head_detached(commit.id()).expect("can't detach HEAD");
        let cmd = format!("git push {} HEAD:{}", self.host.remote_url(module), target);
        let shell = Shell { cwd: self.repo.path().to_path_buf() };
        let output = shell.command(&cmd);
        debug!("push: {}\n{}", cmd, output);
        format!("{}", output)
    }

    fn subtree(&self, tree: &Tree, path: &Path) -> Option<Tree>
    {
        if let Some(oid) = tree.get_path(path).map(|x| x.id()).ok() {
            return self.repo.find_tree(oid).ok();
        }
        else {
            return None;
        }
    }

    fn replace_child(&self, child: &Path, subtree: Oid, full_tree: &Tree) -> Tree
    {
        let full_tree_id = {
            let mut builder = self.repo
                .treebuilder(Some(&full_tree))
                .expect("replace_child: can't create treebuilder");
            builder.insert(child, subtree, 0o0040000) // GIT_FILEMODE_TREE
                .expect("replace_child: can't insert tree");
            builder.write().expect("replace_child: can't write tree")
        };
        return self.repo.find_tree(full_tree_id).expect("replace_child: can't find new tree");
    }

    pub fn replace_subtree(&self, path: &Path, subtree: Oid, full_tree: &Tree) -> Tree
    {
        if path.components().count() == 1 {
            return self.replace_child(path, subtree, full_tree);
        }
        else {
            let name = Path::new(path.file_name().expect("no module name"));
            let path = path.parent().expect("module not in subdir");

            let st = self.subtree(&full_tree, path).unwrap();
            let tree = self.replace_child(name, subtree, &st);

            return self.replace_subtree(path, tree.id(), full_tree);
        }
    }

    pub fn split_subdir(&self, module: &str, newrev: Oid) -> Option<Oid>
    {
        let walk = {
            let mut walk = self.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(newrev).expect("walk.push");
            walk
        };

        let mut map = HashMap::<Oid, Oid>::new();

        'walk: for commit in walk {
            let commit = self.repo.find_commit(commit.unwrap()).unwrap();
            let tree = commit.tree().expect("commit has no tree");

            let new_tree = if let Ok(tree_entry) = tree.get_path(&Path::new(&module)) {
                self.repo.find_tree(tree_entry.id()).expect("central_submit: can't find tree")
            }
            else {
                continue 'walk;
            };

            match commit.parents().count() {
                2 => {
                    let parent1 = commit.parents().nth(0).unwrap().id();
                    let parent2 = commit.parents().nth(1).unwrap().id();
                    if let (Some(&parent1), Some(&parent2)) = (map.get(&parent1),
                                                               map.get(&parent2)) {
                        let parent1 = self.repo.find_commit(parent1).unwrap();
                        let parent2 = self.repo.find_commit(parent2).unwrap();
                        map.insert(commit.id(),
                                   self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        continue 'walk;
                    }
                    if let (Some(&parent), None) = (map.get(&parent1), map.get(&parent2)) {
                        let parent = self.repo.find_commit(parent).unwrap();
                        if new_tree.id() == parent.tree().unwrap().id() {
                            map.insert(commit.id(), parent.id());
                            continue 'walk;
                        }
                        map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                        continue 'walk;
                    }
                    if let (None, Some(&parent)) = (map.get(&parent1), map.get(&parent2)) {
                        let parent = self.repo.find_commit(parent).unwrap();
                        if new_tree.id() == parent.tree().unwrap().id() {
                            map.insert(commit.id(), parent.id());
                            continue 'walk;
                        }
                        map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                        continue 'walk;
                    }
                }
                1 => {
                    let parent = commit.parents().nth(0).unwrap().id();
                    if let Some(&parent) = map.get(&parent) {
                        let parent = self.repo.find_commit(parent).unwrap();
                        if new_tree.id() == parent.tree().unwrap().id() {
                            map.insert(commit.id(), parent.id());
                            continue 'walk;
                        }
                        map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                        continue 'walk;
                    }
                }
                _ => {}
            }

            map.insert(commit.id(), self.rewrite(&commit, &[], &new_tree));
        }

        return map.get(&newrev).map(|&id| id);
    }

    pub fn find_all_subdirs(&self, tree: &Tree) -> Vec<String>
    {
        let mut sd = vec![];
        for item in tree {
            if let Ok(st) = self.repo.find_tree(item.id()) {
                let name = item.name().unwrap();
                if !name.starts_with(".") {
                    sd.push(name.to_string());
                    for r in self.find_all_subdirs(&st) {
                        sd.push(format!("{}/{}", name, r));
                    }
                }
            }
        }
        return sd;
    }

    pub fn join(&self, dst: Oid, path: &Path, src: Oid) -> Oid
    {
        let dst = self.repo.find_commit(dst).unwrap();
        let src = self.repo.find_commit(src).unwrap();

        let signature = Signature::new("CentralGit", "cg@cg.com", &dst.committer().when()).unwrap();

        let walk = {
            let mut walk = self.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(src.id()).expect("walk.push");
            walk
        };

        let empty =
            self.repo.find_tree(self.repo.treebuilder(None).unwrap().write().unwrap()).unwrap();
        let mut map = HashMap::<Oid, Oid>::new();

        'walk: for commit in walk {
            let commit = self.repo.find_commit(commit.unwrap()).unwrap();
            let tree = commit.tree().expect("commit has no tree");
            let new_tree = self.replace_subtree(path, tree.id(), &empty);

            match commit.parents().count() {
                2 => {
                    let parent1 = commit.parents().nth(0).unwrap().id();
                    let parent2 = commit.parents().nth(1).unwrap().id();
                    if let (Some(&parent1), Some(&parent2)) = (map.get(&parent1),
                                                               map.get(&parent2)) {
                        let parent1 = self.repo.find_commit(parent1).unwrap();
                        let parent2 = self.repo.find_commit(parent2).unwrap();

                        let new = new_tree.id();
                        let p1 = parent1.tree().unwrap().id();
                        let p2 = parent2.tree().unwrap().id();

                        map.insert(commit.id(),
                                   self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        continue 'walk;
                    }
                }
                1 => {
                    let parent = commit.parents().nth(0).unwrap().id();
                    let parent = *map.get(&parent).unwrap();
                    let parent = self.repo.find_commit(parent).unwrap();
                    map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                    continue 'walk;
                }
                _ => {}
            }

            map.insert(commit.id(), self.rewrite(&commit, &[], &new_tree));
        }

        let final_tree = self.replace_subtree(path, src.tree().unwrap().id(), &dst.tree().unwrap());

        let parents = [&dst, &self.repo.find_commit(map[&src.id()]).unwrap()];
        self.repo.set_head_detached(parents[0].id()).expect("join: can't detach head");
        let join_commit = self.repo
            .commit(Some("HEAD"),
                    &signature,
                    &signature,
                    "repo_join",
                    &final_tree,
                    &parents)
            .unwrap();
        return join_commit;

    }
}
<commit_msg>cleanup<commit_after>extern crate git2;
const TMP_NAME: &'static str = "refs/centralgit/tmp_fd2db5f8_bac2_4a1e_9487_4ac3414788aa";

use git2::*;
use std::process::Command;
use std::path::Path;
use shell::Shell;
use super::RepoHost;
use std::collections::HashMap;

pub struct Scratch<'a>
{
    pub repo: Repository,
    pub host: &'a RepoHost,
}

enum CommitKind
{
    Normal(Oid),
    Merge(Oid, Oid),
    Orphan,
}

impl<'a> Scratch<'a>
{
    pub fn new(path: &Path, host: &'a RepoHost) -> Scratch<'a>
    {
        Scratch {
            repo: Repository::init_bare(&path).expect("could not init scratch"),
            host: host,
        }
    }

    pub fn tracking(&self, module: &str, branch: &str) -> Option<Object>
    {
        let remote_name = format!("{}", module);
        let fetch_url = self.host.local_path(&module);
        let mut remote = if let Ok(remote) = self.repo.find_remote(&remote_name) {
            remote
        }
        else {
            debug!("==== create remote (remote_name:{}, remote_url:{})",
                   &remote_name,
                   &fetch_url);
            self.repo.remote(&remote_name, &fetch_url).expect("can't create remote")
        };

        let rs = remote.get_refspec(0).unwrap().str().unwrap().to_string();
        if let Ok(_) = remote.fetch(&[&rs], None, None) {
            return self.repo
                .revparse_single(&format!("remotes/{}/{}", module, branch))
                .ok();
        }
        else {
            return None;
        }
    }

    // force push of the new revision-object to temp repo
    pub fn transfer(&self, rev: &str, source: &Path) -> Object
    {
        // TODO: implement using libgit
        let target = &self.repo.path();
        let shell = Shell { cwd: source.to_path_buf() };
        shell.command(&format!("git update-ref {} {}", TMP_NAME, rev));
        shell.command(&format!("git push --force {} {}",
                               &target.to_string_lossy(),
                               TMP_NAME));

        let obj = self.repo.revparse_single(rev).expect("can't find transfered ref");
        return obj;
    }

    // takes everything from base except it's tree and replaces it with the tree
    // given
    pub fn rewrite(&self, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid
    {
        if parents.len() == 0 {
            ::std::fs::remove_file(self.repo.path().join("HEAD")).expect("can't remove HEAD");
        }
        else {
            self.repo.set_head_detached(parents[0].id()).expect("rewrite: can't detach head");
        }
        self.repo
            .commit(Some("HEAD"),
                    &base.author(),
                    &base.committer(),
                    &base.message().unwrap_or("no message"),
                    tree,
                    parents)
            .expect("rewrite: can't commit")
    }

    pub fn push(&self, oid: Oid, module: &str, target: &str) -> String
    {
        let commit = &self.repo.find_commit(oid).expect("can't find commit");
        self.repo.set_head_detached(commit.id()).expect("can't detach HEAD");
        let cmd = format!("git push {} HEAD:{}", self.host.remote_url(module), target);
        let shell = Shell { cwd: self.repo.path().to_path_buf() };
        let output = shell.command(&cmd);
        debug!("push: {}\n{}", cmd, output);
        format!("{}", output)
    }

    fn subtree(&self, tree: &Tree, path: &Path) -> Option<Tree>
    {
        if let Some(oid) = tree.get_path(path).map(|x| x.id()).ok() {
            return self.repo.find_tree(oid).ok();
        }
        else {
            return None;
        }
    }

    fn replace_child(&self, child: &Path, subtree: Oid, full_tree: &Tree) -> Tree
    {
        let full_tree_id = {
            let mut builder = self.repo
                .treebuilder(Some(&full_tree))
                .expect("replace_child: can't create treebuilder");
            builder.insert(child, subtree, 0o0040000) // GIT_FILEMODE_TREE
                .expect("replace_child: can't insert tree");
            builder.write().expect("replace_child: can't write tree")
        };
        return self.repo.find_tree(full_tree_id).expect("replace_child: can't find new tree");
    }

    pub fn replace_subtree(&self, path: &Path, subtree: Oid, full_tree: &Tree) -> Tree
    {
        if path.components().count() == 1 {
            return self.replace_child(path, subtree, full_tree);
        }
        else {
            let name = Path::new(path.file_name().expect("no module name"));
            let path = path.parent().expect("module not in subdir");

            let st = self.subtree(&full_tree, path).unwrap();
            let tree = self.replace_child(name, subtree, &st);

            return self.replace_subtree(path, tree.id(), full_tree);
        }
    }

    pub fn split_subdir(&self, module: &str, newrev: Oid) -> Option<Oid>
    {
        let walk = {
            let mut walk = self.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(newrev).expect("walk.push");
            walk
        };

        let mut map = HashMap::<Oid, Oid>::new();

        'walk: for commit in walk {
            let commit = self.repo.find_commit(commit.unwrap()).unwrap();
            let tree = commit.tree().expect("commit has no tree");

            let new_tree = if let Ok(tree_entry) = tree.get_path(&Path::new(&module)) {
                self.repo.find_tree(tree_entry.id()).expect("central_submit: can't find tree")
            }
            else {
                continue 'walk;
            };

            match match commit.parents().count() {
                2 => {
                    let parent1 = commit.parents().nth(0).unwrap().id();
                    let parent2 = commit.parents().nth(1).unwrap().id();
                    match (map.get(&parent1), map.get(&parent2)) {
                        (Some(&parent1), Some(&parent2)) => CommitKind::Merge(parent1, parent2),
                        (Some(&parent), None) => CommitKind::Normal(parent),
                        (None, Some(&parent)) => CommitKind::Normal(parent),
                        _ => CommitKind::Orphan,
                    }
                }
                1 => {
                    let parent = commit.parents().nth(0).unwrap().id();
                    match map.get(&parent) {
                        Some(&parent) => CommitKind::Normal(parent),
                        _ => CommitKind::Orphan,
                    }
                }
                _ => CommitKind::Orphan,
            } {
                CommitKind::Merge(parent1, parent2) => {
                    let parent1 = self.repo.find_commit(parent1).unwrap();
                    let parent2 = self.repo.find_commit(parent2).unwrap();
                    map.insert(commit.id(),
                               self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                    continue 'walk;
                }
                CommitKind::Normal(parent) => {
                    let parent = self.repo.find_commit(parent).unwrap();
                    if new_tree.id() == parent.tree().unwrap().id() {
                        map.insert(commit.id(), parent.id());
                        continue 'walk;
                    }
                    map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                    continue 'walk;
                }
                CommitKind::Orphan => {
                    map.insert(commit.id(), self.rewrite(&commit, &[], &new_tree));
                }
            }
        }

        return map.get(&newrev).map(|&id| id);
    }

    pub fn find_all_subdirs(&self, tree: &Tree) -> Vec<String>
    {
        let mut sd = vec![];
        for item in tree {
            if let Ok(st) = self.repo.find_tree(item.id()) {
                let name = item.name().unwrap();
                if !name.starts_with(".") {
                    sd.push(name.to_string());
                    for r in self.find_all_subdirs(&st) {
                        sd.push(format!("{}/{}", name, r));
                    }
                }
            }
        }
        return sd;
    }

    pub fn join(&self, dst: Oid, path: &Path, src: Oid) -> Oid
    {
        let dst = self.repo.find_commit(dst).unwrap();
        let src = self.repo.find_commit(src).unwrap();

        let signature = Signature::new("CentralGit", "cg@cg.com", &dst.committer().when()).unwrap();

        let walk = {
            let mut walk = self.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(src.id()).expect("walk.push");
            walk
        };

        let empty =
            self.repo.find_tree(self.repo.treebuilder(None).unwrap().write().unwrap()).unwrap();
        let mut map = HashMap::<Oid, Oid>::new();

        'walk: for commit in walk {
            let commit = self.repo.find_commit(commit.unwrap()).unwrap();
            let tree = commit.tree().expect("commit has no tree");
            let new_tree = self.replace_subtree(path, tree.id(), &empty);

            match commit.parents().count() {
                2 => {
                    let parent1 = commit.parents().nth(0).unwrap().id();
                    let parent2 = commit.parents().nth(1).unwrap().id();
                    if let (Some(&parent1), Some(&parent2)) = (map.get(&parent1),
                                                               map.get(&parent2)) {
                        let parent1 = self.repo.find_commit(parent1).unwrap();
                        let parent2 = self.repo.find_commit(parent2).unwrap();

                        let new = new_tree.id();
                        let p1 = parent1.tree().unwrap().id();
                        let p2 = parent2.tree().unwrap().id();

                        map.insert(commit.id(),
                                   self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        continue 'walk;
                    }
                }
                1 => {
                    let parent = commit.parents().nth(0).unwrap().id();
                    let parent = *map.get(&parent).unwrap();
                    let parent = self.repo.find_commit(parent).unwrap();
                    map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                    continue 'walk;
                }
                _ => {}
            }

            map.insert(commit.id(), self.rewrite(&commit, &[], &new_tree));
        }

        let final_tree = self.replace_subtree(path, src.tree().unwrap().id(), &dst.tree().unwrap());

        let parents = [&dst, &self.repo.find_commit(map[&src.id()]).unwrap()];
        self.repo.set_head_detached(parents[0].id()).expect("join: can't detach head");
        let join_commit = self.repo
            .commit(Some("HEAD"),
                    &signature,
                    &signature,
                    "repo_join",
                    &final_tree,
                    &parents)
            .unwrap();
        return join_commit;

    }
}
<|endoftext|>


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

//! Session structure definition.
//!
//! The Session object serves as a wrapper around an HTTP(s) client, handling
//! authentication, accessing the service catalog and token refresh.

use std::cell::RefCell;

use hyper::{Client, Url};
use hyper::client::{IntoUrl, RequestBuilder, Response};
use hyper::method::Method;

use super::ApiError;
use super::auth::base::{AuthMethod, AuthToken, AuthTokenHeader};
use super::utils;

/// Request builder with authentication.
#[allow(missing_debug_implementations)]
pub struct AuthenticatedRequestBuilder<'a, A: AuthMethod + 'a> {
    parent: &'a Session<A>,
    inner: RequestBuilder<'a>
}

/// An OpenStack API session.
///
/// Owns a token and an underlying client.
#[derive(Debug)]
pub struct Session<A: AuthMethod> {
    auth_method: A,
    client: Client,
    cached_token: RefCell<Option<AuthToken>>
}

impl<'a, A: AuthMethod> AuthenticatedRequestBuilder<'a, A> {
    /// Send this request.
    pub fn send(self) -> Result<Response, ApiError> {
        let token_value = try!(self.parent.token_value());
        let hdr = AuthTokenHeader(token_value);
        self.inner.header(hdr).send().map_err(From::from)
    }
}

impl<'a, A: AuthMethod + 'a> Session<A> {
    /// Create a new session with a given authentication plugin.
    pub fn new(auth_method: A) -> Session<A> {
        Session {
            auth_method: auth_method,
            client: utils::http_client(),
            cached_token: RefCell::new(None)
        }
    }

    /// Get a clone of the authentication token.
    pub fn auth_token(&self) -> Result<AuthToken, ApiError> {
        try!(self.refresh_token());
        Ok(self.cached_token.borrow().clone().unwrap())
    }

    /// Get an endpoint URL.
    pub fn get_endpoint(&self, service_type: &str,
                        endpoint_interface: Option<&str>,
                        region: Option<&str>) -> Result<Url, ApiError> {
        self.auth_method.get_endpoint(service_type, endpoint_interface,
                                      region, &self)
    }

    /// A wrapper for HTTP request.
    pub fn request<U: IntoUrl>(&'a self, method: Method, url: U)
            -> AuthenticatedRequestBuilder<'a, A> {
        AuthenticatedRequestBuilder {
            parent: self,
            inner: self.client.request(method, url)
        }
    }

    // Private and test-only

    #[cfg(test)]
    pub fn new_with_params(auth_method: A, client: Client,
                       token: AuthToken) -> Session<A> {
        Session {
            auth_method: auth_method,
            client: client,
            cached_token: RefCell::new(Some(token))
        }
    }

    fn refresh_token(&self) -> Result<(), ApiError> {
        let mut cached_token = self.cached_token.borrow_mut();
        if cached_token.is_some() {
            return Ok(())
        }

        // TODO: check expires_at

        let new_token = try!(self.auth_method.get_token(&self.client));
        *cached_token = Some(new_token);
        Ok(())
    }

    fn token_value(&self) -> Result<String, ApiError> {
        try!(self.refresh_token());
        Ok(self.cached_token.borrow().clone().unwrap().token)
    }
}

#[cfg(test)]
pub mod test {
    use super::super::auth::base::{AuthToken, NoAuth};
    use super::super::utils;

    use super::Session;

    pub fn new_session(token: &str) -> Session<NoAuth> {
        let token = AuthToken {
            token: String::from(token),
            expires_at: None
        };

        Session::new_with_params(NoAuth::new("http://127.0.0.1/").unwrap(),
                                 utils::http_client(), token)
    }

    #[test]
    fn test_session_new() {
        let s = new_session("foo");
        assert_eq!(&s.token_value().unwrap(), "foo");
    }
}
<commit_msg>Add missing methods to AuthenticatedRequestBuilder<commit_after>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Session structure definition.
//!
//! The Session object serves as a wrapper around an HTTP(s) client, handling
//! authentication, accessing the service catalog and token refresh.

use std::cell::RefCell;

use hyper::{Client, Url};
use hyper::client::{Body, IntoUrl, RequestBuilder, Response};
use hyper::header::{Header, Headers, HeaderFormat};
use hyper::method::Method;

use super::ApiError;
use super::auth::base::{AuthMethod, AuthToken, AuthTokenHeader};
use super::utils;

/// Request builder with authentication.
///
/// Essentially copies the interface of hyper::client::RequestBuilder.
#[allow(missing_debug_implementations)]
pub struct AuthenticatedRequestBuilder<'a, A: AuthMethod + 'a> {
    parent: &'a Session<A>,
    inner: RequestBuilder<'a>
}

/// An OpenStack API session.
///
/// Owns a token and an underlying client.
#[derive(Debug)]
pub struct Session<A: AuthMethod> {
    auth_method: A,
    client: Client,
    cached_token: RefCell<Option<AuthToken>>
}

impl<'a, A: AuthMethod> AuthenticatedRequestBuilder<'a, A> {
    /// Send this request.
    pub fn send(self) -> Result<Response, ApiError> {
        let token_value = try!(self.parent.token_value());
        let hdr = AuthTokenHeader(token_value);
        self.inner.header(hdr).send().map_err(From::from)
    }

    /// Add body to the request.
    pub fn body<B: Into<Body<'a>>>(self, body: B)
            -> AuthenticatedRequestBuilder<'a, A> {
        AuthenticatedRequestBuilder {
            inner: self.inner.body(body),
            .. self
        }
    }

    /// Add additional headers to the request.
    pub fn headers(self, headers: Headers)
            -> AuthenticatedRequestBuilder<'a, A> {
        AuthenticatedRequestBuilder {
            inner: self.inner.headers(headers),
            .. self
        }
    }

    /// Add an individual header to the request.
    ///
    /// Note that X-Auth-Token is always overwritten with a token in use.
    pub fn header<H: Header + HeaderFormat>(self, header: H)
            -> AuthenticatedRequestBuilder<'a, A> {
        AuthenticatedRequestBuilder {
            inner: self.inner.header(header),
            .. self
        }
    }
}

impl<'a, A: AuthMethod + 'a> Session<A> {
    /// Create a new session with a given authentication plugin.
    pub fn new(auth_method: A) -> Session<A> {
        Session {
            auth_method: auth_method,
            client: utils::http_client(),
            cached_token: RefCell::new(None)
        }
    }

    /// Get a clone of the authentication token.
    pub fn auth_token(&self) -> Result<AuthToken, ApiError> {
        try!(self.refresh_token());
        Ok(self.cached_token.borrow().clone().unwrap())
    }

    /// Get an endpoint URL.
    pub fn get_endpoint(&self, service_type: &str,
                        endpoint_interface: Option<&str>,
                        region: Option<&str>) -> Result<Url, ApiError> {
        self.auth_method.get_endpoint(service_type, endpoint_interface,
                                      region, &self)
    }

    /// A wrapper for HTTP request.
    pub fn request<U: IntoUrl>(&'a self, method: Method, url: U)
            -> AuthenticatedRequestBuilder<'a, A> {
        AuthenticatedRequestBuilder {
            parent: self,
            inner: self.client.request(method, url)
        }
    }

    // Private and test-only

    #[cfg(test)]
    pub fn new_with_params(auth_method: A, client: Client,
                       token: AuthToken) -> Session<A> {
        Session {
            auth_method: auth_method,
            client: client,
            cached_token: RefCell::new(Some(token))
        }
    }

    fn refresh_token(&self) -> Result<(), ApiError> {
        let mut cached_token = self.cached_token.borrow_mut();
        if cached_token.is_some() {
            return Ok(())
        }

        // TODO: check expires_at

        let new_token = try!(self.auth_method.get_token(&self.client));
        *cached_token = Some(new_token);
        Ok(())
    }

    fn token_value(&self) -> Result<String, ApiError> {
        try!(self.refresh_token());
        Ok(self.cached_token.borrow().clone().unwrap().token)
    }
}

#[cfg(test)]
pub mod test {
    use super::super::auth::base::{AuthToken, NoAuth};
    use super::super::utils;

    use super::Session;

    pub fn new_session(token: &str) -> Session<NoAuth> {
        let token = AuthToken {
            token: String::from(token),
            expires_at: None
        };

        Session::new_with_params(NoAuth::new("http://127.0.0.1/").unwrap(),
                                 utils::http_client(), token)
    }

    #[test]
    fn test_session_new() {
        let s = new_session("foo");
        assert_eq!(&s.token_value().unwrap(), "foo");
    }
}
<|endoftext|>


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

/*
    Note that this is NOT Ken Perlin's simplex noise, as that is patent encumbered.
    Instead, these functions use the OpenSimplex algorithm, as detailed here:
    http://uniblock.tumblr.com/post/97868843242/noise
*/

use std::num::{cast, Float};

use seed::Seed;
use gradients::GRADIENT2;

const STRETCH_CONSTANT_2D: f64 = -0.211324865405187; //(1/sqrt(2+1)-1)/2;
const SQUISH_CONSTANT_2D: f64 = 0.366025403784439; //(sqrt(2+1)-1)/2;

const NORM_CONSTANT_2D: f32 = 14.0;

fn get_simplex2_gradient<T: Float>(seed: &Seed, xs_floor: T, ys_floor: T, dx: T, dy: T) -> T {
    let two: T = cast(2.0f32).unwrap();
    let attn = two - dx * dx - dy * dy;
    if attn > cast(0.0f32).unwrap() {
        let index = seed.get2(xs_floor.to_int().unwrap(), ys_floor.to_int().unwrap()) % GRADIENT2.len();
        let vec = GRADIENT2[index];
        let attn2 = attn * attn;
        return attn2 * attn2 * (dx * cast(vec[0]).unwrap() + dy * cast(vec[1]).unwrap());
    }
    return cast(0.0f32).unwrap();
}

pub fn simplex2<T: Float>(seed: &Seed, point: &::Point2<T>) -> f32 {
    let zero: T = cast(0.0f32).unwrap();
    let one: T = cast(1.0f32).unwrap();
    let two: T = cast(2.0f32).unwrap();
    let squish_constant: T = cast(SQUISH_CONSTANT_2D).unwrap();

    //Place input coordinates onto grid.
    let stretch_offset = (point[0] + point[1]) * cast(STRETCH_CONSTANT_2D).unwrap();
    let xs = point[0] + stretch_offset;
    let ys = point[1] + stretch_offset;

    //Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
    let mut xs_floor = xs.floor();
    let mut ys_floor = ys.floor();

    //Skew out to get actual coordinates of rhombus origin. We'll need these later.
    let squish_offset = (xs_floor + ys_floor) * squish_constant;
    let x_floor = xs_floor + squish_offset;
    let y_floor = ys_floor + squish_offset;

    //Compute grid coordinates relative to rhombus origin.
    let xs_frac = xs - xs_floor;
    let ys_frac = ys - ys_floor;

    //Sum those together to get a value that determines which region we're in.
    let frac_sum = xs_frac + ys_frac;

    //Positions relative to origin point.
    let mut dx0 = point[0] - x_floor;
    let mut dy0 = point[1] - y_floor;

    let mut value = zero;

    //Contribution (1,0)
    let dx1 = dx0 - one - squish_constant;
    let dy1 = dy0 - zero - squish_constant;
    value = value + get_simplex2_gradient(seed, xs_floor + one, ys_floor + zero, dx1, dy1);

    //Contribution (0,1)
    let dx2 = dx0 - zero - squish_constant;
    let dy2 = dy0 - one - squish_constant;
    value = value + get_simplex2_gradient(seed, xs_floor + zero, ys_floor + one, dx2, dy2);

    let (dx_ext, dy_ext, xsv_ext, ysv_ext) = if frac_sum <= one {
        //We're inside the triangle (2-Simplex) at (0,0)
        let z_frac = one - frac_sum;
        if z_frac > xs_frac || z_frac > ys_frac { //(0,0) is one of the closest two triangular vertices
            if xs_frac > ys_frac {
                (dx0 - one, dy0 + one, xs_floor + one, ys_floor - one)
            } else {
                (dx0 + one, dy0 - one, xs_floor - one, ys_floor + one)
            }
        } else { //(1,0) and (0,1) are the closest two vertices.
            (dx0 - one - two * squish_constant, dy0 - one - two * squish_constant, xs_floor + one, ys_floor + one)
        }
    } else {
        //We're inside the triangle (2-Simplex) at (1,1)
        let z_frac = two - frac_sum;
        if z_frac < xs_frac || z_frac < ys_frac { //(0,0) is one of the closest two triangular vertices
            if xs_frac > ys_frac {
                (dx0 - two - two * squish_constant, dy0 + zero - two * squish_constant, xs_floor + two, ys_floor + zero)
            } else {
                (dx0 + zero - two * squish_constant, dy0 - two - two * squish_constant, xs_floor + zero, ys_floor + two)
            }
        } else { //(1,0) and (0,1) are the closest two vertices.
            (dx0, dy0, xs_floor, ys_floor)
        }
    };

    if frac_sum > one {
        xs_floor = xs_floor + one;
        ys_floor = ys_floor + one;
        dx0 = dx0 - one - two * squish_constant;
        dy0 = dy0 - one - two * squish_constant;
    }

    //Contribution (0,0) or (1,1)
    value = value + get_simplex2_gradient(seed, xs_floor, ys_floor, dx0, dy0);

    //Extra Vertex
    value = value + get_simplex2_gradient(seed, xsv_ext, ysv_ext, dx_ext, dy_ext);

    return value.to_f32().unwrap() / NORM_CONSTANT_2D;
}

#[cfg(test)]
mod tests {
    use std::rand;
    use seed::Seed;
    use simplex::simplex2;

    const EPSILON: f32 = 0.000001;

    #[test]
    fn test_simplex2() {
        let mut rng: rand::XorShiftRng = rand::SeedableRng::from_seed([42, 37, 26, 8]);
        let seed = Seed::from_rng(&mut rng);

        assert_approx_eq!( 0.000000, simplex2(&seed, &[0.0f32, 0.0]), EPSILON);
        assert_approx_eq!(-0.073360, simplex2(&seed, &[0.5f32, 0.0]), EPSILON);
        assert_approx_eq!(-0.163874, simplex2(&seed, &[1.0f32, 0.0]), EPSILON);
        assert_approx_eq!( 0.110803, simplex2(&seed, &[1.5f32, 0.0]), EPSILON);
        assert_approx_eq!(-0.038814, simplex2(&seed, &[2.0f32, 0.0]), EPSILON);

        assert_approx_eq!(-0.352936, simplex2(&seed, &[0.0f32, 0.5]), EPSILON);
        assert_approx_eq!(-0.301287, simplex2(&seed, &[0.5f32, 0.5]), EPSILON);
        assert_approx_eq!(-0.292849, simplex2(&seed, &[1.0f32, 0.5]), EPSILON);
        assert_approx_eq!( 0.144342, simplex2(&seed, &[1.5f32, 0.5]), EPSILON);
        assert_approx_eq!( 0.208945, simplex2(&seed, &[2.0f32, 0.5]), EPSILON);

        assert_approx_eq!(-0.235302, simplex2(&seed, &[0.0f32, 1.0]), EPSILON);
        assert_approx_eq!( 0.057028, simplex2(&seed, &[0.5f32, 1.0]), EPSILON);
        assert_approx_eq!( 0.142835, simplex2(&seed, &[1.0f32, 1.0]), EPSILON);
        assert_approx_eq!( 0.261979, simplex2(&seed, &[1.5f32, 1.0]), EPSILON);
        assert_approx_eq!( 0.252710, simplex2(&seed, &[2.0f32, 1.0]), EPSILON);

        assert_approx_eq!(-0.305799, simplex2(&seed, &[0.0f32, 1.5]), EPSILON);
        assert_approx_eq!( 0.142413, simplex2(&seed, &[0.5f32, 1.5]), EPSILON);
        assert_approx_eq!( 0.470566, simplex2(&seed, &[1.0f32, 1.5]), EPSILON);
        assert_approx_eq!( 0.321834, simplex2(&seed, &[1.5f32, 1.5]), EPSILON);
        assert_approx_eq!( 0.013222, simplex2(&seed, &[2.0f32, 1.5]), EPSILON);

        assert_approx_eq!(-0.383105, simplex2(&seed, &[0.0f32, 2.0]), EPSILON);
        assert_approx_eq!(-0.140743, simplex2(&seed, &[0.5f32, 2.0]), EPSILON);
        assert_approx_eq!( 0.092702, simplex2(&seed, &[1.0f32, 2.0]), EPSILON);
        assert_approx_eq!(-0.022101, simplex2(&seed, &[1.5f32, 2.0]), EPSILON);
        assert_approx_eq!(-0.301222, simplex2(&seed, &[2.0f32, 2.0]), EPSILON);
    }
}
<commit_msg>Remove the Simplex test. Will replace with image tests later.<commit_after>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
    Note that this is NOT Ken Perlin's simplex noise, as that is patent encumbered.
    Instead, these functions use the OpenSimplex algorithm, as detailed here:
    http://uniblock.tumblr.com/post/97868843242/noise
*/

use std::num::{cast, Float};

use seed::Seed;
use gradients::GRADIENT2;

const STRETCH_CONSTANT_2D: f64 = -0.211324865405187; //(1/sqrt(2+1)-1)/2;
const SQUISH_CONSTANT_2D: f64 = 0.366025403784439; //(sqrt(2+1)-1)/2;

const NORM_CONSTANT_2D: f32 = 14.0;

fn get_simplex2_gradient<T: Float>(seed: &Seed, xs_floor: T, ys_floor: T, dx: T, dy: T) -> T {
    let two: T = cast(2.0f32).unwrap();
    let attn = two - dx * dx - dy * dy;
    if attn > cast(0.0f32).unwrap() {
        let index = seed.get2(xs_floor.to_int().unwrap(), ys_floor.to_int().unwrap()) % GRADIENT2.len();
        let vec = GRADIENT2[index];
        let attn2 = attn * attn;
        return attn2 * attn2 * (dx * cast(vec[0]).unwrap() + dy * cast(vec[1]).unwrap());
    }
    return cast(0.0f32).unwrap();
}

pub fn simplex2<T: Float>(seed: &Seed, point: &::Point2<T>) -> f32 {
    let zero: T = cast(0.0f32).unwrap();
    let one: T = cast(1.0f32).unwrap();
    let two: T = cast(2.0f32).unwrap();
    let squish_constant: T = cast(SQUISH_CONSTANT_2D).unwrap();

    //Place input coordinates onto grid.
    let stretch_offset = (point[0] + point[1]) * cast(STRETCH_CONSTANT_2D).unwrap();
    let xs = point[0] + stretch_offset;
    let ys = point[1] + stretch_offset;

    //Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
    let mut xs_floor = xs.floor();
    let mut ys_floor = ys.floor();

    //Skew out to get actual coordinates of rhombus origin. We'll need these later.
    let squish_offset = (xs_floor + ys_floor) * squish_constant;
    let x_floor = xs_floor + squish_offset;
    let y_floor = ys_floor + squish_offset;

    //Compute grid coordinates relative to rhombus origin.
    let xs_frac = xs - xs_floor;
    let ys_frac = ys - ys_floor;

    //Sum those together to get a value that determines which region we're in.
    let frac_sum = xs_frac + ys_frac;

    //Positions relative to origin point.
    let mut dx0 = point[0] - x_floor;
    let mut dy0 = point[1] - y_floor;

    let mut value = zero;

    //Contribution (1,0)
    let dx1 = dx0 - one - squish_constant;
    let dy1 = dy0 - zero - squish_constant;
    value = value + get_simplex2_gradient(seed, xs_floor + one, ys_floor + zero, dx1, dy1);

    //Contribution (0,1)
    let dx2 = dx0 - zero - squish_constant;
    let dy2 = dy0 - one - squish_constant;
    value = value + get_simplex2_gradient(seed, xs_floor + zero, ys_floor + one, dx2, dy2);

    let (dx_ext, dy_ext, xsv_ext, ysv_ext) = if frac_sum <= one {
        //We're inside the triangle (2-Simplex) at (0,0)
        let z_frac = one - frac_sum;
        if z_frac > xs_frac || z_frac > ys_frac { //(0,0) is one of the closest two triangular vertices
            if xs_frac > ys_frac {
                (dx0 - one, dy0 + one, xs_floor + one, ys_floor - one)
            } else {
                (dx0 + one, dy0 - one, xs_floor - one, ys_floor + one)
            }
        } else { //(1,0) and (0,1) are the closest two vertices.
            (dx0 - one - two * squish_constant, dy0 - one - two * squish_constant, xs_floor + one, ys_floor + one)
        }
    } else {
        //We're inside the triangle (2-Simplex) at (1,1)
        let z_frac = two - frac_sum;
        if z_frac < xs_frac || z_frac < ys_frac { //(0,0) is one of the closest two triangular vertices
            if xs_frac > ys_frac {
                (dx0 - two - two * squish_constant, dy0 + zero - two * squish_constant, xs_floor + two, ys_floor + zero)
            } else {
                (dx0 + zero - two * squish_constant, dy0 - two - two * squish_constant, xs_floor + zero, ys_floor + two)
            }
        } else { //(1,0) and (0,1) are the closest two vertices.
            (dx0, dy0, xs_floor, ys_floor)
        }
    };

    if frac_sum > one {
        xs_floor = xs_floor + one;
        ys_floor = ys_floor + one;
        dx0 = dx0 - one - two * squish_constant;
        dy0 = dy0 - one - two * squish_constant;
    }

    //Contribution (0,0) or (1,1)
    value = value + get_simplex2_gradient(seed, xs_floor, ys_floor, dx0, dy0);

    //Extra Vertex
    value = value + get_simplex2_gradient(seed, xsv_ext, ysv_ext, dx_ext, dy_ext);

    return value.to_f32().unwrap() / NORM_CONSTANT_2D;
}
<|endoftext|>


<commit_before>use hyper;
use serde_json;
use std;
use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
use toml;

#[derive(Deserialize, Debug, Clone)]
pub struct Config {
    pub token: String,
    pub org: String,
    #[serde(default = "default_team")]
    pub team: Vec<TeamConfig>,
    #[serde(default = "default_repo")]
    pub repo: Vec<RepoConfig>,
    #[serde(default = "default_endpoint")]
    pub endpoint: String,
    #[serde(default = "default_home")]
    pub home: String,
    #[serde(default = "default_sh")]
    pub sh: String,
    #[serde(default = "default_cache_duration")]
    pub cache_duration: u64,
    #[serde(default = "default_cert_path")]
    pub cert_path: String,
    #[serde(default = "default_user_conf_path")]
    pub user_conf_path: String,
    pub proxy_url: Option<String>,
}

fn default_team() -> Vec<TeamConfig> { Vec::new() }
fn default_repo() -> Vec<RepoConfig> { Vec::new() }
fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }
fn default_user_conf_path() -> String { String::from(".config/sectora.toml") }

impl Config {
    pub fn new(configpath: &std::path::Path) -> Result<Self, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(toml::from_str::<Config>(&contents)?)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserConfig {
    pub sh: Option<String>,
    pub pass: Option<String>,
}

impl UserConfig {
    #[allow(dead_code)]
    pub fn new(configpath: &std::path::Path) -> Result<Self, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(toml::from_str::<UserConfig>(&contents)?)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Team {
    pub id: u64,
    pub name: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TeamConfig {
    pub name: String,
    pub gid: Option<u64>,
    pub group: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Repo {
    pub id: u64,
    pub name: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoConfig {
    pub name: String,
    pub gid: Option<u64>,
    pub group: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SectorType {
    Team,
    Repo,
}

impl fmt::Display for SectorType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &SectorType::Team => write!(f, "T"),
            &SectorType::Repo => write!(f, "R"),
        }
    }
}

impl FromStr for SectorType {
    type Err = std::io::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "T" => Ok(SectorType::Team),
            "R" => Ok(SectorType::Repo),
            _ => Err(std::io::Error::new(std::io::ErrorKind::Other, "unknown sector type")),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Sector {
    pub id: u64,
    pub name: String,
    pub sector_type: SectorType,
}

impl From<Team> for Sector {
    fn from(team: Team) -> Self {
        Self { id: team.id,
               name: team.name,
               sector_type: SectorType::Team, }
    }
}

impl From<Repo> for Sector {
    fn from(repo: Repo) -> Self {
        Self { id: repo.id,
               name: repo.name,
               sector_type: SectorType::Repo, }
    }
}

impl fmt::Display for Sector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}:{}", self.id, self.name, self.sector_type) }
}

pub enum ParseSectorError {
    Id(std::num::ParseIntError),
    Type(std::io::Error),
}

impl FromStr for Sector {
    type Err = ParseSectorError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split(":").collect::<Vec<&str>>();
        Ok(Self { id: parts[0].parse().map_err(|e| ParseSectorError::Id(e))?,
                  name: String::from(parts[1]),
                  sector_type: parts[2].parse().map_err(|e| ParseSectorError::Type(e))?, })
    }
}

#[derive(Debug, Clone)]
pub struct SectorGroup {
    pub sector: Sector,
    pub gid: Option<u64>,
    pub group: Option<String>,
    pub members: HashMap<String, Member>,
}

impl SectorGroup {
    #[allow(dead_code)]
    pub fn get_gid(&self) -> u64 { self.gid.unwrap_or(self.sector.id) }
    #[allow(dead_code)]
    pub fn get_group(&self) -> String { self.group.clone().unwrap_or(self.sector.name.clone()) }
}

impl fmt::Display for SectorGroup {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let members_str = self.members.values()
                              .map(|v| v.to_string())
                              .collect::<Vec<_>>()
                              .join(" ");
        write!(f,
               "{}\t{}\t{}\t{}",
               self.sector,
               self.gid.and_then(|i| Some(i.to_string())).unwrap_or(String::new()),
               self.group.clone().unwrap_or(String::new()),
               members_str)
    }
}

pub enum ParseSectorGroupError {
    Sector(ParseSectorError),
    Gid(std::num::ParseIntError),
    Member(std::num::ParseIntError),
}

impl FromStr for SectorGroup {
    type Err = ParseSectorGroupError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split("\t").collect::<Vec<&str>>();
        let sector = parts[0].parse().map_err(|e| ParseSectorGroupError::Sector(e))?;
        let gid: Option<u64> = match parts[1] {
            "" => None,
            s => Some(s.parse::<u64>().map_err(|e| ParseSectorGroupError::Gid(e))?),
        };
        let group: Option<String> = match parts[2] {
            "" => None,
            s => Some(String::from(s)),
        };
        let members = parts[3].split(" ")
                              .map(|s| s.parse::<Member>().map_err(|e| ParseSectorGroupError::Member(e)))
                              .collect::<Result<Vec<Member>, _>>()?
                              .into_iter()
                              .map(|m| (m.login.clone(), m))
                              .collect::<HashMap<_, _>>();
        Ok(Self { sector,
                  gid,
                  group,
                  members, })
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Member {
    pub id: u64,
    pub login: String,
}

impl fmt::Display for Member {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}", self.id, self.login) }
}

impl FromStr for Member {
    type Err = std::num::ParseIntError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split(":").collect::<Vec<&str>>();
        Ok(Self { id: parts[0].parse()?,
                  login: String::from(parts[1]), })
    }
}

#[allow(dead_code)]
pub struct MemberGid {
    pub member: Member,
    pub gid: u64,
}

impl fmt::Display for MemberGid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}|{}", self.member, self.gid) }
}

impl FromStr for MemberGid {
    type Err = std::num::ParseIntError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split("|").collect::<Vec<&str>>();
        Ok(Self { member: parts[0].parse()?,
                  gid: parts[1].parse()?, })
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PublicKey {
    pub id: u64,
    pub key: String,
}

#[derive(Debug)]
pub enum CliError {
    Serde(serde_json::Error),
    Io(std::io::Error),
    Toml(toml::de::Error),
    Hyper(hyper::Error),
}

impl From<serde_json::Error> for CliError {
    fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }
}
impl From<std::io::Error> for CliError {
    fn from(err: std::io::Error) -> CliError { CliError::Io(err) }
}
impl From<toml::de::Error> for CliError {
    fn from(err: toml::de::Error) -> CliError { CliError::Toml(err) }
}
impl From<hyper::Error> for CliError {
    fn from(err: hyper::Error) -> CliError { CliError::Hyper(err) }
}
<commit_msg>Add RateLimit struct<commit_after>use hyper;
use serde_json;
use std;
use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
use toml;

#[derive(Deserialize, Debug, Clone)]
pub struct Config {
    pub token: String,
    pub org: String,
    #[serde(default = "default_team")]
    pub team: Vec<TeamConfig>,
    #[serde(default = "default_repo")]
    pub repo: Vec<RepoConfig>,
    #[serde(default = "default_endpoint")]
    pub endpoint: String,
    #[serde(default = "default_home")]
    pub home: String,
    #[serde(default = "default_sh")]
    pub sh: String,
    #[serde(default = "default_cache_duration")]
    pub cache_duration: u64,
    #[serde(default = "default_cert_path")]
    pub cert_path: String,
    #[serde(default = "default_user_conf_path")]
    pub user_conf_path: String,
    pub proxy_url: Option<String>,
}

fn default_team() -> Vec<TeamConfig> { Vec::new() }
fn default_repo() -> Vec<RepoConfig> { Vec::new() }
fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }
fn default_user_conf_path() -> String { String::from(".config/sectora.toml") }

impl Config {
    pub fn new(configpath: &std::path::Path) -> Result<Self, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(toml::from_str::<Config>(&contents)?)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserConfig {
    pub sh: Option<String>,
    pub pass: Option<String>,
}

impl UserConfig {
    #[allow(dead_code)]
    pub fn new(configpath: &std::path::Path) -> Result<Self, CliError> {
        let mut file = File::open(configpath)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(toml::from_str::<UserConfig>(&contents)?)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Team {
    pub id: u64,
    pub name: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TeamConfig {
    pub name: String,
    pub gid: Option<u64>,
    pub group: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Repo {
    pub id: u64,
    pub name: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RepoConfig {
    pub name: String,
    pub gid: Option<u64>,
    pub group: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SectorType {
    Team,
    Repo,
}

impl fmt::Display for SectorType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &SectorType::Team => write!(f, "T"),
            &SectorType::Repo => write!(f, "R"),
        }
    }
}

impl FromStr for SectorType {
    type Err = std::io::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "T" => Ok(SectorType::Team),
            "R" => Ok(SectorType::Repo),
            _ => Err(std::io::Error::new(std::io::ErrorKind::Other, "unknown sector type")),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Sector {
    pub id: u64,
    pub name: String,
    pub sector_type: SectorType,
}

impl From<Team> for Sector {
    fn from(team: Team) -> Self {
        Self { id: team.id,
               name: team.name,
               sector_type: SectorType::Team, }
    }
}

impl From<Repo> for Sector {
    fn from(repo: Repo) -> Self {
        Self { id: repo.id,
               name: repo.name,
               sector_type: SectorType::Repo, }
    }
}

impl fmt::Display for Sector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}:{}", self.id, self.name, self.sector_type) }
}

pub enum ParseSectorError {
    Id(std::num::ParseIntError),
    Type(std::io::Error),
}

impl FromStr for Sector {
    type Err = ParseSectorError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split(":").collect::<Vec<&str>>();
        Ok(Self { id: parts[0].parse().map_err(|e| ParseSectorError::Id(e))?,
                  name: String::from(parts[1]),
                  sector_type: parts[2].parse().map_err(|e| ParseSectorError::Type(e))?, })
    }
}

#[derive(Debug, Clone)]
pub struct SectorGroup {
    pub sector: Sector,
    pub gid: Option<u64>,
    pub group: Option<String>,
    pub members: HashMap<String, Member>,
}

impl SectorGroup {
    #[allow(dead_code)]
    pub fn get_gid(&self) -> u64 { self.gid.unwrap_or(self.sector.id) }
    #[allow(dead_code)]
    pub fn get_group(&self) -> String { self.group.clone().unwrap_or(self.sector.name.clone()) }
}

impl fmt::Display for SectorGroup {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let members_str = self.members.values()
                              .map(|v| v.to_string())
                              .collect::<Vec<_>>()
                              .join(" ");
        write!(f,
               "{}\t{}\t{}\t{}",
               self.sector,
               self.gid.and_then(|i| Some(i.to_string())).unwrap_or(String::new()),
               self.group.clone().unwrap_or(String::new()),
               members_str)
    }
}

pub enum ParseSectorGroupError {
    Sector(ParseSectorError),
    Gid(std::num::ParseIntError),
    Member(std::num::ParseIntError),
}

impl FromStr for SectorGroup {
    type Err = ParseSectorGroupError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split("\t").collect::<Vec<&str>>();
        let sector = parts[0].parse().map_err(|e| ParseSectorGroupError::Sector(e))?;
        let gid: Option<u64> = match parts[1] {
            "" => None,
            s => Some(s.parse::<u64>().map_err(|e| ParseSectorGroupError::Gid(e))?),
        };
        let group: Option<String> = match parts[2] {
            "" => None,
            s => Some(String::from(s)),
        };
        let members = parts[3].split(" ")
                              .map(|s| s.parse::<Member>().map_err(|e| ParseSectorGroupError::Member(e)))
                              .collect::<Result<Vec<Member>, _>>()?
                              .into_iter()
                              .map(|m| (m.login.clone(), m))
                              .collect::<HashMap<_, _>>();
        Ok(Self { sector,
                  gid,
                  group,
                  members, })
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Member {
    pub id: u64,
    pub login: String,
}

impl fmt::Display for Member {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}", self.id, self.login) }
}

impl FromStr for Member {
    type Err = std::num::ParseIntError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split(":").collect::<Vec<&str>>();
        Ok(Self { id: parts[0].parse()?,
                  login: String::from(parts[1]), })
    }
}

#[allow(dead_code)]
pub struct MemberGid {
    pub member: Member,
    pub gid: u64,
}

impl fmt::Display for MemberGid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}|{}", self.member, self.gid) }
}

impl FromStr for MemberGid {
    type Err = std::num::ParseIntError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split("|").collect::<Vec<&str>>();
        Ok(Self { member: parts[0].parse()?,
                  gid: parts[1].parse()?, })
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PublicKey {
    pub id: u64,
    pub key: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Rate {
    pub limit: usize,
    pub remaining: usize,
    pub reset: usize,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RateLimit {
    pub rate: Rate,
}

#[derive(Debug)]
pub enum CliError {
    Serde(serde_json::Error),
    Io(std::io::Error),
    Toml(toml::de::Error),
    Hyper(hyper::Error),
}

impl From<serde_json::Error> for CliError {
    fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }
}
impl From<std::io::Error> for CliError {
    fn from(err: std::io::Error) -> CliError { CliError::Io(err) }
}
impl From<toml::de::Error> for CliError {
    fn from(err: toml::de::Error) -> CliError { CliError::Toml(err) }
}
impl From<hyper::Error> for CliError {
    fn from(err: hyper::Error) -> CliError { CliError::Hyper(err) }
}
<|endoftext|>


<commit_before>use error::Error;

#[derive(Debug)]
pub struct Summarizer {
    data: Vec<f64>,
}

impl Summarizer {
    /// Construct a `Summarizer` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        if data.is_empty() {
            return Err(Error::EmptySample);
        }

        if data.iter().any(|x| !x.is_finite()) {
            return Err(Error::BadSample);
        }

        let mut data = Vec::from(data);

        // Won't panic: we have checked that each float is finite.
        data.sort_by(|a, b| a.partial_cmp(b).unwrap_or_else(|| unreachable!()));

        let s = Summarizer { data };

        Ok(s)
    }

    pub fn as_slice(&self) -> &[f64] {
        self.data.as_slice()
    }

    pub fn size(&self) -> f64 {
        self.data.len() as f64
    }

    pub fn min(&self) -> f64 {
        self.data[0]
    }

    pub fn max(&self) -> f64 {
        self.data[self.data.len() - 1]
    }

    pub fn mean(&self) -> f64 {
        let t: f64 = self.data.iter().sum();

        t / self.size()
    }

    pub fn median(&self) -> f64 {
        let d = &self.data;
        let n = d.len();

        if n % 2 == 0 {
            (d[(n / 2) - 1] + d[n / 2]) / 2.0
        } else {
            d[(n - 1) / 2]
        }
    }

    /// Closest-ranks percentile computed via linear interpolation.
    /// See: http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm
    ///
    /// According to NIST, there isn't a standard computational definition of percentile.
    /// We take a practical approach that aims to be both unsurprising and consistent with
    /// common statistics packages. In particular, our implementation guarantees that the
    /// boundary percentiles correspond to the sample min and max.
    pub fn percentile(&self, p: f64) -> Result<f64, Error> {
        if !p.is_finite() { return Err(Error::Undefined); }
        if p < 0.0 || 1.0 < p {
            return Err(Error::Undefined);
        }

        let rank = (self.size() - 1.0) * p;
        let frac = rank.fract();

        let i = rank.floor() as usize;
        let j = i + 1;

        if j == self.data.len() {
            // This implies that `i` indexes the largest data point in the sample.
            // Dereferencing at `j` would be an error, but `i` is exactly the max.
            return Ok(self.data[i]);
        }

        let xi = self.data[i];
        let xj = self.data[j];
        let x = xi + frac * (xj - xi);

        Ok(x)
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        let m = self.mean();
        let sum_sq_diff: f64 = self.data
            .iter()
            .map(|x| (x - m).powi(2))
            .sum();

        (1.0 / (self.size() - 1.0)) * sum_sq_diff
    }

    pub fn standard_deviation(&self) -> f64 {
        self.unbiased_variance().sqrt()
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_deviation() / self.size().sqrt()
    }
}

#[derive(Debug)]
pub struct Summary {
    iqr: f64,
    len: usize,
    lower_quartile: f64,
    min: f64,
    min_non_outlier: f64,
    max: f64,
    max_non_outlier: f64,
    mean: f64,
    median: f64,
    standard_deviation: f64,
    standard_error: f64,
    unbiased_variance: f64,
    upper_quartile: f64,
}

impl Summary {
    /// Construct a `Summary` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        let s = Summarizer::new(data)?;

        // The percentile arguments below are statically known to meet the
        // `percentile()` bounds, so we can always unwrap.
        let q1 = s.percentile(0.25).unwrap_or_else(|_| unreachable!());
        let q3 = s.percentile(0.75).unwrap_or_else(|_| unreachable!());
        let iqr = q3 - q1;

        let lower_outlier_bound = q1 - 1.5 * iqr;
        let min_non_outlier = s
            .as_slice()
            .iter()
            .cloned()
            .find(|&x| lower_outlier_bound <= x)
            .unwrap_or_else(|| unreachable!());  // By definition of quartile.

        let upper_outlier_bound = q3 + 1.5 * iqr;
        let max_non_outlier = s
            .as_slice()
            .iter()
            .cloned()
            .rev()
            .find(|&x| x <= upper_outlier_bound)
            .unwrap_or_else(|| unreachable!());  // By definition of quartile.

        Ok(Summary {
            iqr: iqr,
            len: s.data.len(),
            lower_quartile: q1,
            min: s.min(),
            min_non_outlier: min_non_outlier,
            max: s.max(),
            max_non_outlier: max_non_outlier,
            mean: s.mean(),
            median: s.median(),
            upper_quartile: q3,
            unbiased_variance: s.unbiased_variance(),
            standard_deviation: s.standard_deviation(),
            standard_error: s.standard_error(),
        })
    }

    pub fn size(&self) -> f64 {
        self.len as f64
    }

    pub fn range(&self) -> f64 {
        self.max - self.min
    }

    pub fn iqr(&self) -> f64 {
        self.iqr
    }

    pub fn lower_quartile(&self) -> f64 {
        self.lower_quartile
    }

    pub fn min(&self) -> f64 {
        self.min
    }

    pub fn min_non_outlier(&self) -> f64 {
        self.min_non_outlier
    }

    pub fn max(&self) -> f64 {
        self.max
    }

    pub fn max_non_outlier(&self) -> f64 {
        self.max_non_outlier
    }

    pub fn mean(&self) -> f64 {
        self.mean
    }

    pub fn median(&self) -> f64 {
        self.median
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        self.unbiased_variance
    }

    pub fn upper_quartile(&self) -> f64 {
        self.upper_quartile
    }

    pub fn standard_deviation(&self) -> f64 {
        self.standard_deviation
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_error
    }
}
<commit_msg>Move all `Summary` calculations into `Summarizer` methods<commit_after>use error::Error;

#[derive(Debug)]
pub struct Summarizer {
    data: Vec<f64>,
}

impl Summarizer {
    /// Construct a `Summarizer` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        if data.is_empty() {
            return Err(Error::EmptySample);
        }

        if data.iter().any(|x| !x.is_finite()) {
            return Err(Error::BadSample);
        }

        let mut data = Vec::from(data);

        // Won't panic: we have checked that each float is finite.
        data.sort_by(|a, b| a.partial_cmp(b).unwrap_or_else(|| unreachable!()));

        let s = Summarizer { data };

        Ok(s)
    }

    pub fn as_slice(&self) -> &[f64] {
        self.data.as_slice()
    }

    pub fn size(&self) -> f64 {
        self.data.len() as f64
    }

    pub fn iqr(&self) -> f64 {
        self.upper_quartile() - self.lower_quartile()
    }

    pub fn lower_quartile(&self) -> f64 {
        // Statically known to be defined.
        self.percentile(0.25).unwrap_or_else(|_| unreachable!())
    }

    pub fn min(&self) -> f64 {
        self.data[0]
    }

    pub fn min_non_outlier(&self) -> f64 {
        let lower_outlier_bound = self.lower_quartile() - 1.5 * self.iqr();

        self.data
            .iter()
            .cloned()
            .find(|&x| lower_outlier_bound <= x)
            .unwrap_or_else(|| unreachable!())  // By definition of quartile.
    }

    pub fn max(&self) -> f64 {
        self.data[self.data.len() - 1]
    }

    pub fn max_non_outlier(&self) -> f64 {
        let upper_outlier_bound = self.upper_quartile() + 1.5 * self.iqr();

        self.data
            .iter()
            .cloned()
            .rev()
            .find(|&x| x <= upper_outlier_bound)
            .unwrap_or_else(|| unreachable!())  // By definition of quartile.
    }

    pub fn mean(&self) -> f64 {
        let t: f64 = self.data.iter().sum();

        t / self.size()
    }

    pub fn median(&self) -> f64 {
        let d = &self.data;
        let n = d.len();

        if n % 2 == 0 {
            (d[(n / 2) - 1] + d[n / 2]) / 2.0
        } else {
            d[(n - 1) / 2]
        }
    }

    /// Closest-ranks percentile computed via linear interpolation.
    /// See: http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm
    ///
    /// According to NIST, there isn't a standard computational definition of percentile.
    /// We take a practical approach that aims to be both unsurprising and consistent with
    /// common statistics packages. In particular, our implementation guarantees that the
    /// boundary percentiles correspond to the sample min and max.
    pub fn percentile(&self, p: f64) -> Result<f64, Error> {
        if !p.is_finite() { return Err(Error::Undefined); }
        if p < 0.0 || 1.0 < p {
            return Err(Error::Undefined);
        }

        let rank = (self.size() - 1.0) * p;
        let frac = rank.fract();

        let i = rank.floor() as usize;
        let j = i + 1;

        if j == self.data.len() {
            // This implies that `i` indexes the largest data point in the sample.
            // Dereferencing at `j` would be an error, but `i` is exactly the max.
            return Ok(self.data[i]);
        }

        let xi = self.data[i];
        let xj = self.data[j];
        let x = xi + frac * (xj - xi);

        Ok(x)
    }

    pub fn range(&self) -> f64 {
        self.max() - self.min()
    }

    pub fn upper_quartile(&self) -> f64 {
        // Statically known to be defined.
        self.percentile(0.75).unwrap_or_else(|_| unreachable!())
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        let m = self.mean();
        let sum_sq_diff: f64 = self.data
            .iter()
            .map(|x| (x - m).powi(2))
            .sum();

        (1.0 / (self.size() - 1.0)) * sum_sq_diff
    }

    pub fn standard_deviation(&self) -> f64 {
        self.unbiased_variance().sqrt()
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_deviation() / self.size().sqrt()
    }
}

#[derive(Debug)]
pub struct Summary {
    iqr: f64,
    len: usize,
    lower_quartile: f64,
    min: f64,
    min_non_outlier: f64,
    max: f64,
    max_non_outlier: f64,
    mean: f64,
    median: f64,
    range: f64,
    standard_deviation: f64,
    standard_error: f64,
    unbiased_variance: f64,
    upper_quartile: f64,
}

impl Summary {
    /// Construct a `Summary` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        let s = Summarizer::new(data)?;

        Ok(Summary {
            iqr: s.iqr(),
            len: s.data.len(),
            lower_quartile: s.lower_quartile(),
            min: s.min(),
            min_non_outlier: s.min_non_outlier(),
            max: s.max(),
            max_non_outlier: s.max_non_outlier(),
            mean: s.mean(),
            median: s.median(),
            range: s.range(),
            upper_quartile: s.upper_quartile(),
            unbiased_variance: s.unbiased_variance(),
            standard_deviation: s.standard_deviation(),
            standard_error: s.standard_error(),
        })
    }

    pub fn size(&self) -> f64 {
        self.len as f64
    }

    pub fn range(&self) -> f64 {
        self.range
    }

    pub fn iqr(&self) -> f64 {
        self.iqr
    }

    pub fn lower_quartile(&self) -> f64 {
        self.lower_quartile
    }

    pub fn min(&self) -> f64 {
        self.min
    }

    pub fn min_non_outlier(&self) -> f64 {
        self.min_non_outlier
    }

    pub fn max(&self) -> f64 {
        self.max
    }

    pub fn max_non_outlier(&self) -> f64 {
        self.max_non_outlier
    }

    pub fn mean(&self) -> f64 {
        self.mean
    }

    pub fn median(&self) -> f64 {
        self.median
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        self.unbiased_variance
    }

    pub fn upper_quartile(&self) -> f64 {
        self.upper_quartile
    }

    pub fn standard_deviation(&self) -> f64 {
        self.standard_deviation
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_error
    }
}
<|endoftext|>


<commit_before>pub mod framed;
pub mod server;
pub mod proto;
pub mod client;
pub mod shortcut;

pub static STANDALONE_ADDRESS: &'static str = "STANDALONE";<commit_msg>default runtime string for standalone address<commit_after>pub mod framed;
pub mod server;
pub mod proto;
pub mod client;
pub mod shortcut;

pub static STANDALONE_ADDRESS: &'static str = "STANDALONE";

lazy_static! {
    pub static ref STANDALONE_ADDRESS_STRING: String = String::from(STANDALONE_ADDRESS);
}<|endoftext|>