<commit_before>use codemap::Spanned;
use lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;
use self::ParseErrorKind::*;

type ParseIter<'a> = Peekable<Iter<'a, Spanned<Token>>>;
type Parse = Result<Node, ParseErrorKind>;

#[derive(Debug, Clone, PartialEq)]
pub enum Node {
  Block(Vec<Node>),
  If{cond: Box<Node>},
  Stmt(Box<Node>),
  Break,
  Continue,
  Expr,
  Pass,

  BinExpr {
    lhs: Box<Node>,
    op: Token,
    rhs: Box<Node>,
  },

  UnExpr {
    val: Box<Node>,
    op: Token,
  },

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),
  Table,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Op {
  Right(u32),
  Left(u32),
  None,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ParseErrorKind {
  UnexpectedToken(Token),
  UnexpectedEOF,
  UnknownBinaryOperator,
  UnknownUnaryOperator,
}

// Return true if the next token in `it` is `kind`
fn peek_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    c.node == kind
  }
  else {
    false
  }
}

// Return true if the next token in `it` is `kind` *and* consume the token
fn use_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    if c.node == kind {
      it.next();
    }
    c.node == kind
  }
  else {
    false
  }
}

// Panic if the next token in `it` is *not* `kind`
fn require_token(it: &mut ParseIter, kind: Token) -> Result<(), ParseErrorKind> {
  if let Some(&c) = it.peek() {
    it.next();

    if c.node == kind {
      return Ok(());
    }

    return Err(UnexpectedToken(c.node.clone()));
  }

  return Err(UnexpectedEOF);
}

fn op_precedence(op: &Token) -> Op {
  match *op {
    Token::Add | Token::Sub => Op::Left(10),
    Token::Div | Token::Mul => Op::Left(20),
    Token::Car => Op::Right(30),
    _ => Op::None,
  }
}

fn parse_binexpr(it: &mut ParseIter) -> Parse {
  let mut expr = parse_unexpr(it)?;

  while let Some(&c) = it.peek() {
    let prec = op_precedence(&c.node);

    if let Op::None = prec {
      break;
    }

    it.next();

    let rhs = parse_unexpr(it)?;

    if let Node::BinExpr{lhs: cur_lhs, op: cur_op, rhs: cur_rhs} = expr.clone() {
      let cur_prec = op_precedence(&cur_op);
      match (cur_prec, prec) {
        // these should never happen
        (_, Op::None) => {break}
        (Op::None, _) => {break}

        (Op::Left(n), Op::Left(m)) => {
          // left-to-right if n >= m
          if n >= m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n < m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }

        (Op::Right(n), Op::Right(m)) => {
          // left-to-right if n > m
          if n > m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n <= m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }

        (Op::Right(n), Op::Left(m)) => {
          // left-to-right if n >= m
          if n >= m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n < m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }

        (Op::Left(n), Op::Right(m)) => {
          // left-to-right if n >= m
          if n >= m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n < m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }
      };
    }
    else {
      expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
    }
  };

  Ok(expr)
}

fn parse_unexpr(it: &mut ParseIter) -> Parse {
  parse_simple(it)
}

fn parse_simple(it: &mut ParseIter) -> Parse {
  parse_prefix(it)
}

fn parse_prefix(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Null => {it.next(); Ok(Node::Null)},
      Token::Bool(x) => {it.next(); Ok(Node::Bool(x))},
      Token::Float(x) => {it.next(); Ok(Node::Float(x))},
      Token::Int(x) => {it.next(); Ok(Node::Int(x))},
      Token::Str(ref x) => {it.next(); Ok(Node::Str(x.clone()))},
      Token::Name(ref x) => {it.next(); Ok(Node::Name(x.clone()))},
      Token::Table => {it.next(); Ok(Node::Table)},
      Token::Pal => {
        it.next();
        let out = parse_binexpr(it)?;
        require_token(it, Token::Par)?;
        Ok(out)
      }
      _ => Err(UnexpectedToken(c.node.clone())),
    }
  }

  Err(UnexpectedEOF)
}

fn parse_stmt(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Break => {
        it.next();
        Ok(Node::Break)
      }

      Token::Continue => {
        it.next();
        Ok(Node::Continue)
      }

      Token::Pass => {
        it.next();
        Ok(Node::Pass)
      }

      _ => {
        parse_binexpr(it).map(|expr| Node::Stmt(Box::new(expr)))
      }
    }
  }

  Err(UnexpectedEOF)
}

pub fn parse(tokens: Vec<Spanned<Token>>) -> Parse {
  let mut it: ParseIter = tokens.iter().peekable();
  let mut nodes: Vec<Node> = vec![];

  while !peek_token(&mut it, Token::EOF) {
    nodes.push(parse_stmt(&mut it)?);
    require_token(&mut it, Token::End)?;
  }

  Ok(Node::Block(nodes))
}
<commit_msg>parser: Clean up binary expression parsing<commit_after>use codemap::Spanned;
use lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;
use self::ParseErrorKind::*;

type ParseIter<'a> = Peekable<Iter<'a, Spanned<Token>>>;
type Parse = Result<Node, ParseErrorKind>;

#[derive(Debug, Clone, PartialEq)]
pub enum Node {
  Block(Vec<Node>),
  If{cond: Box<Node>},
  Stmt(Box<Node>),
  Break,
  Continue,
  Expr,
  Pass,

  BinExpr {
    lhs: Box<Node>,
    op: Token,
    rhs: Box<Node>,
  },

  UnExpr {
    val: Box<Node>,
    op: Token,
  },

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),
  Table,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Op {
  Right(u32),
  Left(u32),
  None,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ParseErrorKind {
  UnexpectedToken(Token),
  UnexpectedEOF,
  UnknownBinaryOperator,
  UnknownUnaryOperator,
}

// Return true if the next token in `it` is `kind`
fn peek_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    c.node == kind
  }
  else {
    false
  }
}

// Return true if the next token in `it` is `kind` *and* consume the token
fn use_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    if c.node == kind {
      it.next();
    }
    c.node == kind
  }
  else {
    false
  }
}

// Panic if the next token in `it` is *not* `kind`
fn require_token(it: &mut ParseIter, kind: Token) -> Result<(), ParseErrorKind> {
  if let Some(&c) = it.peek() {
    it.next();

    if c.node == kind {
      return Ok(());
    }

    return Err(UnexpectedToken(c.node.clone()));
  }

  return Err(UnexpectedEOF);
}

fn op_precedence(op: &Token) -> Op {
  match *op {
    Token::Add | Token::Sub => Op::Left(10),
    Token::Div | Token::Mul => Op::Left(20),
    Token::Car => Op::Right(30),
    _ => Op::None,
  }
}

fn parse_binexpr(it: &mut ParseIter) -> Parse {
  let mut expr = parse_unexpr(it)?;

  while let Some(&c) = it.peek() {
    let prec = op_precedence(&c.node);

    if let Op::None = prec {
      break;
    }

    it.next();

    let rhs = parse_unexpr(it)?;

    expr = if let Node::BinExpr{lhs: cur_lhs, op: cur_op, rhs: cur_rhs} = expr.clone() {
      let cur_prec = op_precedence(&cur_op);
      match (cur_prec, prec) {
        // these should never happen
        (_, Op::None) => {break}
        (Op::None, _) => {break}

        // left-to-right
        // there has to be a better way to handle this, no?
        (Op::Left(n), Op::Left(m)) if n >= m => {
          Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)}
        }
        (Op::Right(n), Op::Right(m)) if n > m => {
          Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)}
        }
        (Op::Right(n), Op::Left(m)) if n >= m => {
          Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)}
        }
        (Op::Left(n), Op::Right(m)) if n >= m => {
          Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)}
        }

        // right-to-left
        _ => {
          Node::BinExpr {
            lhs: cur_lhs,
            op: cur_op,
            rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
          }
        }
      }
    }
    else {
      Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)}
    };
  };

  Ok(expr)
}

fn parse_unexpr(it: &mut ParseIter) -> Parse {
  parse_simple(it)
}

fn parse_simple(it: &mut ParseIter) -> Parse {
  parse_prefix(it)
}

fn parse_prefix(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Null => {it.next(); Ok(Node::Null)},
      Token::Bool(x) => {it.next(); Ok(Node::Bool(x))},
      Token::Float(x) => {it.next(); Ok(Node::Float(x))},
      Token::Int(x) => {it.next(); Ok(Node::Int(x))},
      Token::Str(ref x) => {it.next(); Ok(Node::Str(x.clone()))},
      Token::Name(ref x) => {it.next(); Ok(Node::Name(x.clone()))},
      Token::Table => {it.next(); Ok(Node::Table)},
      Token::Pal => {
        it.next();
        let out = parse_binexpr(it)?;
        require_token(it, Token::Par)?;
        Ok(out)
      }
      _ => Err(UnexpectedToken(c.node.clone())),
    }
  }

  Err(UnexpectedEOF)
}

fn parse_stmt(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Break => {
        it.next();
        Ok(Node::Break)
      }

      Token::Continue => {
        it.next();
        Ok(Node::Continue)
      }

      Token::Pass => {
        it.next();
        Ok(Node::Pass)
      }

      _ => {
        parse_binexpr(it).map(|expr| Node::Stmt(Box::new(expr)))
      }
    }
  }

  Err(UnexpectedEOF)
}

pub fn parse(tokens: Vec<Spanned<Token>>) -> Parse {
  let mut it: ParseIter = tokens.iter().peekable();
  let mut nodes: Vec<Node> = vec![];

  while !peek_token(&mut it, Token::EOF) {
    nodes.push(parse_stmt(&mut it)?);
    require_token(&mut it, Token::End)?;
  }

  Ok(Node::Block(nodes))
}
<|endoftext|>


<commit_before>use ast::*;
use scanner::{Lexeme, Position, Token, TokenWithContext};
use std::iter::Peekable;

/// This behave exactly as try! but wraps the returned result in a Some.
/// It's useful to remove some boilerplate in the code introduced by
/// the use of Option<Result<T, E>>
macro_rules! try_wrap_err {
    ($e:expr) => (match $e {Ok(e) => e, Err(e) => return Some(Err(e))})
}

#[derive(Debug)]
pub enum ParseError {
    UnconsumedTokens,
    UnexpectedEndOfFile,
    UnexpectedToken(Lexeme, Position),
    MissingSubexpression(Lexeme, Position),
    MissingClosingParen(Lexeme, Position),
}

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Expr, Vec<ParseError>> {
    let mut iter = tokens.iter().peekable();
    if let Some(result) = parse_expression(&mut iter) {
        match result {
            Ok(expr) => {
                if let None = iter.next() {
                    Ok(expr)
                } else {
                    Err(vec![ParseError::UnconsumedTokens])
                }
            }
            Err(error) => {
                {
                    synchronise(&mut iter);
                }
                Err(vec![error])
            }
        }

    } else {
        Err(vec![ParseError::UnexpectedEndOfFile])
    }
}

fn synchronise<'a, I>(tokens: &mut Peekable<I>)
    where I: Iterator<Item = &'a TokenWithContext>
{
    enum TokenKind {
        StartOfConstruct,
        BodyOfConstruct,
        EndOfConstruct,
    };
    fn classify(token: &Token) -> TokenKind {
        match token {
            &Token::Semicolon => TokenKind::EndOfConstruct,
            &Token::Class => TokenKind::StartOfConstruct,
            &Token::Fun => TokenKind::StartOfConstruct,
            &Token::Var => TokenKind::StartOfConstruct,
            &Token::For => TokenKind::StartOfConstruct,
            &Token::If => TokenKind::StartOfConstruct,
            &Token::While => TokenKind::StartOfConstruct,
            &Token::Print => TokenKind::StartOfConstruct,
            &Token::Return => TokenKind::StartOfConstruct,
            _ => TokenKind::BodyOfConstruct,
        }
    }
    while let Some(token_kind) = tokens.peek().map(|t| classify(&t.token)) {
        match token_kind {
            TokenKind::StartOfConstruct => {
                break;
            }
            TokenKind::BodyOfConstruct => {
                let _ = tokens.next();
            }
            TokenKind::EndOfConstruct => {
                let _ = tokens.next();
                break;
            }
        }
    }
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<BinaryOperator>,
                       parse_subexpression: &Fn(&mut Peekable<I>)
                                                -> Option<Result<Expr, ParseError>>)
                       -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        let result = parse_subexpression(tokens);
        if let Some(Ok(subexpression)) = result {
            expr = subexpression;
        } else {
            return result;
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // We know it's right, we read it just for error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right = if let Some(result) = parse_subexpression(tokens) {
            try_wrap_err!(result)
        } else {
            return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                             operator.position)));
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Some(Ok(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::BangEqual => Some(BinaryOperator::NotEqual),
            Token::EqualEqual => Some(BinaryOperator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Greater => Some(BinaryOperator::Greater),
            Token::GreaterEqual => Some(BinaryOperator::GreaterEqual),
            Token::Less => Some(BinaryOperator::Less),
            Token::LessEqual => Some(BinaryOperator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Minus => Some(BinaryOperator::Minus),
            Token::Plus => Some(BinaryOperator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Slash => Some(BinaryOperator::Slash),
            Token::Star => Some(BinaryOperator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<UnaryOperator> {
        match *token {
            Token::Minus => Some(UnaryOperator::Minus),
            Token::Bang => Some(UnaryOperator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // For error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right = if let Some(result) = parse_unary(tokens) {
            try_wrap_err!(result)
        } else {
            return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                             operator.position)));
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Some(Ok(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr = if let Some(result) = parse_expression(tokens) {
                    try_wrap_err!(result)
                } else {
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::RightParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Some(Ok(Expr::Grouping(Box::new(grouping_expression))));
                        } else {
                            return Some(Err(ParseError::MissingClosingParen(token.lexeme.clone(),
                                                                            token.position)));
                        }

                    }
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                }
            }
            _ => {
                return Some(Err(ParseError::UnexpectedToken(primary_token.lexeme.clone(),
                                                            primary_token.position)));
            }
        };
        Some(Ok(parsed_expression))
    } else {
        None
    }
}

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

    #[test]
    fn literal() {
        let string = String::from("123");
        let (tokens, _) = scan(&string);
        let expr = parse(tokens).unwrap();
        assert_eq!(&string, &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let (tokens, _) = scan(&"123+456");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let (tokens, _) = scan(&"123+456*789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let (tokens, _) = scan(&"123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let (tokens, _) = scan(&"-123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn unclosed_group() {
        let (tokens, _) = scan(&"(2");
        assert!(parse(tokens).is_err());
    }

    #[test]
    fn unopened_group() {
        let (tokens, _) = scan(&"2)");
        assert!(parse(tokens).is_err());
    }
}
<commit_msg>[clippy] unified expression in pattern matching<commit_after>use ast::*;
use scanner::{Lexeme, Position, Token, TokenWithContext};
use std::iter::Peekable;

/// This behave exactly as try! but wraps the returned result in a Some.
/// It's useful to remove some boilerplate in the code introduced by
/// the use of Option<Result<T, E>>
macro_rules! try_wrap_err {
    ($e:expr) => (match $e {Ok(e) => e, Err(e) => return Some(Err(e))})
}

#[derive(Debug)]
pub enum ParseError {
    UnconsumedTokens,
    UnexpectedEndOfFile,
    UnexpectedToken(Lexeme, Position),
    MissingSubexpression(Lexeme, Position),
    MissingClosingParen(Lexeme, Position),
}

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Expr, Vec<ParseError>> {
    let mut iter = tokens.iter().peekable();
    if let Some(result) = parse_expression(&mut iter) {
        match result {
            Ok(expr) => {
                if let None = iter.next() {
                    Ok(expr)
                } else {
                    Err(vec![ParseError::UnconsumedTokens])
                }
            }
            Err(error) => {
                {
                    synchronise(&mut iter);
                }
                Err(vec![error])
            }
        }

    } else {
        Err(vec![ParseError::UnexpectedEndOfFile])
    }
}

fn synchronise<'a, I>(tokens: &mut Peekable<I>)
    where I: Iterator<Item = &'a TokenWithContext>
{
    enum TokenKind {
        StartOfConstruct,
        BodyOfConstruct,
        EndOfConstruct,
    };
    fn classify(token: &Token) -> TokenKind {
        match *token {
            Token::Semicolon => TokenKind::EndOfConstruct,
            Token::Class | Token::Fun | Token::Var | Token::For | Token::If | Token::While |
            Token::Print | Token::Return => TokenKind::StartOfConstruct,
            _ => TokenKind::BodyOfConstruct,
        }
    }
    while let Some(token_kind) = tokens.peek().map(|t| classify(&t.token)) {
        match token_kind {
            TokenKind::StartOfConstruct => {
                break;
            }
            TokenKind::BodyOfConstruct => {
                let _ = tokens.next();
            }
            TokenKind::EndOfConstruct => {
                let _ = tokens.next();
                break;
            }
        }
    }
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<BinaryOperator>,
                       parse_subexpression: &Fn(&mut Peekable<I>)
                                                -> Option<Result<Expr, ParseError>>)
                       -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        let result = parse_subexpression(tokens);
        if let Some(Ok(subexpression)) = result {
            expr = subexpression;
        } else {
            return result;
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // We know it's right, we read it just for error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right = if let Some(result) = parse_subexpression(tokens) {
            try_wrap_err!(result)
        } else {
            return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                             operator.position)));
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Some(Ok(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::BangEqual => Some(BinaryOperator::NotEqual),
            Token::EqualEqual => Some(BinaryOperator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Greater => Some(BinaryOperator::Greater),
            Token::GreaterEqual => Some(BinaryOperator::GreaterEqual),
            Token::Less => Some(BinaryOperator::Less),
            Token::LessEqual => Some(BinaryOperator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Minus => Some(BinaryOperator::Minus),
            Token::Plus => Some(BinaryOperator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<BinaryOperator> {
        match *token {
            Token::Slash => Some(BinaryOperator::Slash),
            Token::Star => Some(BinaryOperator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<UnaryOperator> {
        match *token {
            Token::Minus => Some(UnaryOperator::Minus),
            Token::Bang => Some(UnaryOperator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // For error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right = if let Some(result) = parse_unary(tokens) {
            try_wrap_err!(result)
        } else {
            return Some(Err(ParseError::MissingSubexpression(operator.lexeme.clone(),
                                                             operator.position)));
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Some(Ok(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr = if let Some(result) = parse_expression(tokens) {
                    try_wrap_err!(result)
                } else {
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::RightParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Some(Ok(Expr::Grouping(Box::new(grouping_expression))));
                        } else {
                            return Some(Err(ParseError::MissingClosingParen(token.lexeme.clone(),
                                                                            token.position)));
                        }

                    }
                    return Some(Err(ParseError::UnexpectedEndOfFile));
                }
            }
            _ => {
                return Some(Err(ParseError::UnexpectedToken(primary_token.lexeme.clone(),
                                                            primary_token.position)));
            }
        };
        Some(Ok(parsed_expression))
    } else {
        None
    }
}

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

    #[test]
    fn literal() {
        let string = String::from("123");
        let (tokens, _) = scan(&string);
        let expr = parse(tokens).unwrap();
        assert_eq!(&string, &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let (tokens, _) = scan(&"123+456");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let (tokens, _) = scan(&"123+456*789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let (tokens, _) = scan(&"123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let (tokens, _) = scan(&"-123*456+789");
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn unclosed_group() {
        let (tokens, _) = scan(&"(2");
        assert!(parse(tokens).is_err());
    }

    #[test]
    fn unopened_group() {
        let (tokens, _) = scan(&"2)");
        assert!(parse(tokens).is_err());
    }
}
<|endoftext|>


<commit_before>use std::env;
use ansi_term::Colour::{Cyan, Blue, Red, Green, Purple};
use ansi_term::{ANSIStrings, ANSIGenericString};
use git2::{self, Repository, StatusOptions};
use regex::Regex;
use clap::{ArgMatches, App, SubCommand};
use tico::tico;

fn shorten_path(cwd: &str) -> String {
  let friendly_path = match env::home_dir() {
    Some(path) => Regex::new(path.to_str().unwrap()).unwrap().replace(cwd, "~"),
    _ => return String::from("")
  };

  tico(&friendly_path)
}

fn repo_status(r: &Repository) -> Option<String> {
  let mut out = vec![];

  if let Some(name) = get_head_shortname(r) {
    out.push(Cyan.paint(name));
  }

  if let Some((ahead, behind)) = get_ahead_behind(r) {
    if ahead > 0 {
      out.push(Cyan.paint(format!("↑{}", ahead)));
    }
    if behind > 0 {
      out.push(Cyan.paint(format!("↓{}", behind)));
    }
  }

  if let Some((index_change, wt_change, conflicted, untracked)) = count_files_statuses(r) {
    if index_change == 0 && wt_change == 0 && conflicted == 0 && untracked == 0 {
      out.push(Green.paint("✔"));
    } else {
      if index_change > 0 {
        out.push(Green.paint(format!("♦{}", index_change)));
      }
      if conflicted > 0 {
        out.push(Red.paint(format!("✖{}", conflicted)));
      }
      if wt_change > 0 {
        out.push(ANSIGenericString::from(format!("✚{}", wt_change)));
      }
      if untracked > 0 {
        out.push(ANSIGenericString::from("…"));
      }
    }
  }

  if let Some(action) = get_action(r) {
    out.push(Purple.paint(format!(" {}", action)));
  }

  Some(ANSIStrings(&out).to_string())
}

fn get_ahead_behind(r: &Repository) -> Option<(usize, usize)> {
  let head = try_opt!(r.head().ok());
  if !head.is_branch() {
    return None
  }

  let head_name = try_opt!(head.shorthand());
  let head_branch = try_opt!(r.find_branch(head_name, git2::BranchType::Local).ok());
  let upstream = try_opt!(head_branch.upstream().ok());
  let head_oid = try_opt!(head.target());
  let upstream_oid = try_opt!(upstream.get().target());

  r.graph_ahead_behind(head_oid, upstream_oid).ok()
}

fn get_head_shortname(r: &Repository) -> Option<String> {
  let head = try_opt!(r.head().ok());
  if let Some(shorthand) = head.shorthand() {
    if shorthand != "HEAD" {
      return Some(shorthand.to_string())
    }
  }

  let object = try_opt!(head.peel(git2::ObjectType::Commit).ok());
  let short_id = try_opt!(object.short_id().ok());

  Some(format!(":{}", short_id.iter().map(|ch| *ch as char).collect::<String>()))
}

fn count_files_statuses(r: &Repository) -> Option<(usize, usize, usize, usize)> {
  let mut opts = StatusOptions::new();
  opts.include_untracked(true);

  fn count_files(statuses: &git2::Statuses, status: git2::Status) -> usize {
    statuses.iter().filter(|entry| entry.status().intersects(status)).count()
  }

  let statuses = try_opt!(r.statuses(Some(&mut opts)).ok());

  Some((
    count_files(
      &statuses,
      git2::STATUS_INDEX_NEW |
      git2::STATUS_INDEX_MODIFIED |
      git2::STATUS_INDEX_DELETED |
      git2::STATUS_INDEX_RENAMED |
      git2::STATUS_INDEX_TYPECHANGE
    ),
    count_files(
      &statuses,
      git2::STATUS_WT_MODIFIED |
      git2::STATUS_WT_DELETED |
      git2::STATUS_WT_TYPECHANGE |
      git2::STATUS_WT_RENAMED
    ),
    count_files(&statuses, git2::STATUS_CONFLICTED),
    count_files(&statuses, git2::STATUS_WT_NEW),
  ))
}

// Based on https://github.com/zsh-users/zsh/blob/ed4e37e45c2f5761981cdc6027a5d6abc753176a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git#L11
fn get_action(r: &Repository) -> Option<String> {
  let gitdir = r.path();

  for tmp in &[
    gitdir.join("rebase-apply"),
    gitdir.join("rebase"),
    gitdir.join("..").join(".dotest"),
  ] {
    if tmp.join("rebasing").exists() {
      return Some("rebase".to_string());
    }
    if tmp.join("applying").exists() {
      return Some("am".to_string());
    }
    if tmp.exists() {
      return Some("am/rebase".to_string());
    }
  }

  for tmp in &[
    gitdir.join("rebase-merge").join("interactive"),
    gitdir.join(".dotest-merge").join("interactive"),
  ] {
    if tmp.exists() {
      return Some("rebase-i".to_string());
    }
  }

  for tmp in &[
    gitdir.join("rebase-merge"),
    gitdir.join(".dotest-merge"),
  ] {
    if tmp.exists() {
      return Some("rebase-m".to_string());
    }
  }

  if gitdir.join("MERGE_HEAD").exists() {
    return Some("merge".to_string());
  }

  if gitdir.join("BISECT_LOG").exists() {
    return Some("bisect".to_string());
  }

  if gitdir.join("CHERRY_PICK_HEAD").exists() {
    if gitdir.join("sequencer").exists() {
      return Some("cherry-seq".to_string());
    } else {
      return Some("cherry".to_string());
    }
  }

  if gitdir.join("sequencer").exists() {
    return Some("cherry-or-revert".to_string());
  }

  None
}

pub fn display(_sub: &ArgMatches) {
  let my_path = env::current_dir().unwrap();
  let display_path = Blue.paint(shorten_path(my_path.to_str().unwrap()));

  let branch = match Repository::discover(my_path) {
    Ok(repo) => repo_status(&repo),
    Err(_e) => None,
  };
  let display_branch = Cyan.paint(branch.unwrap_or_default());

  println!("");
  println!("{} {}", display_path, display_branch);
}

pub fn cli_arguments<'a>() -> App<'a, 'a> {
  SubCommand::with_name("precmd")
}
<commit_msg>add the flag --git-detailed to display the detailed git status<commit_after>use std::env;
use ansi_term::Colour::{Cyan, Blue, Red, Green, Purple};
use ansi_term::{ANSIStrings, ANSIGenericString};
use git2::{self, Repository, StatusOptions};
use regex::Regex;
use clap::{ArgMatches, App, SubCommand, Arg};
use tico::tico;

fn shorten_path(cwd: &str) -> String {
  let friendly_path = match env::home_dir() {
    Some(path) => Regex::new(path.to_str().unwrap()).unwrap().replace(cwd, "~"),
    _ => return String::from("")
  };

  tico(&friendly_path)
}

fn repo_status(r: &Repository, detailed: bool) -> Option<String> {
  let mut out = vec![];

  if let Some(name) = get_head_shortname(r) {
    out.push(Cyan.paint(name));
  }

  if !detailed {
    if let Some((index_change, wt_change, conflicted, untracked)) = count_files_statuses(r) {
      if index_change != 0 || wt_change != 0 || conflicted != 0 || untracked != 0 {
        out.push(Red.bold().paint("*"));
      }
    }
  } else {
    if let Some((ahead, behind)) = get_ahead_behind(r) {
      if ahead > 0 {
        out.push(Cyan.paint(format!("↑{}", ahead)));
      }
      if behind > 0 {
        out.push(Cyan.paint(format!("↓{}", behind)));
      }
    }

    if let Some((index_change, wt_change, conflicted, untracked)) = count_files_statuses(r) {
      if index_change == 0 && wt_change == 0 && conflicted == 0 && untracked == 0 {
        out.push(Green.paint("✔"));
      } else {
        if index_change > 0 {
          out.push(Green.paint(format!("♦{}", index_change)));
        }
        if conflicted > 0 {
          out.push(Red.paint(format!("✖{}", conflicted)));
        }
        if wt_change > 0 {
          out.push(ANSIGenericString::from(format!("✚{}", wt_change)));
        }
        if untracked > 0 {
          out.push(ANSIGenericString::from("…"));
        }
      }
    }

    if let Some(action) = get_action(r) {
      out.push(Purple.paint(format!(" {}", action)));
    }
  }

  Some(ANSIStrings(&out).to_string())
}

fn get_ahead_behind(r: &Repository) -> Option<(usize, usize)> {
  let head = try_opt!(r.head().ok());
  if !head.is_branch() {
    return None
  }

  let head_name = try_opt!(head.shorthand());
  let head_branch = try_opt!(r.find_branch(head_name, git2::BranchType::Local).ok());
  let upstream = try_opt!(head_branch.upstream().ok());
  let head_oid = try_opt!(head.target());
  let upstream_oid = try_opt!(upstream.get().target());

  r.graph_ahead_behind(head_oid, upstream_oid).ok()
}

fn get_head_shortname(r: &Repository) -> Option<String> {
  let head = try_opt!(r.head().ok());
  if let Some(shorthand) = head.shorthand() {
    if shorthand != "HEAD" {
      return Some(shorthand.to_string())
    }
  }

  let object = try_opt!(head.peel(git2::ObjectType::Commit).ok());
  let short_id = try_opt!(object.short_id().ok());

  Some(format!(":{}", short_id.iter().map(|ch| *ch as char).collect::<String>()))
}

fn count_files_statuses(r: &Repository) -> Option<(usize, usize, usize, usize)> {
  let mut opts = StatusOptions::new();
  opts.include_untracked(true);

  fn count_files(statuses: &git2::Statuses, status: git2::Status) -> usize {
    statuses.iter().filter(|entry| entry.status().intersects(status)).count()
  }

  let statuses = try_opt!(r.statuses(Some(&mut opts)).ok());

  Some((
    count_files(
      &statuses,
      git2::STATUS_INDEX_NEW |
      git2::STATUS_INDEX_MODIFIED |
      git2::STATUS_INDEX_DELETED |
      git2::STATUS_INDEX_RENAMED |
      git2::STATUS_INDEX_TYPECHANGE
    ),
    count_files(
      &statuses,
      git2::STATUS_WT_MODIFIED |
      git2::STATUS_WT_DELETED |
      git2::STATUS_WT_TYPECHANGE |
      git2::STATUS_WT_RENAMED
    ),
    count_files(&statuses, git2::STATUS_CONFLICTED),
    count_files(&statuses, git2::STATUS_WT_NEW),
  ))
}

// Based on https://github.com/zsh-users/zsh/blob/ed4e37e45c2f5761981cdc6027a5d6abc753176a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git#L11
fn get_action(r: &Repository) -> Option<String> {
  let gitdir = r.path();

  for tmp in &[
    gitdir.join("rebase-apply"),
    gitdir.join("rebase"),
    gitdir.join("..").join(".dotest"),
  ] {
    if tmp.join("rebasing").exists() {
      return Some("rebase".to_string());
    }
    if tmp.join("applying").exists() {
      return Some("am".to_string());
    }
    if tmp.exists() {
      return Some("am/rebase".to_string());
    }
  }

  for tmp in &[
    gitdir.join("rebase-merge").join("interactive"),
    gitdir.join(".dotest-merge").join("interactive"),
  ] {
    if tmp.exists() {
      return Some("rebase-i".to_string());
    }
  }

  for tmp in &[
    gitdir.join("rebase-merge"),
    gitdir.join(".dotest-merge"),
  ] {
    if tmp.exists() {
      return Some("rebase-m".to_string());
    }
  }

  if gitdir.join("MERGE_HEAD").exists() {
    return Some("merge".to_string());
  }

  if gitdir.join("BISECT_LOG").exists() {
    return Some("bisect".to_string());
  }

  if gitdir.join("CHERRY_PICK_HEAD").exists() {
    if gitdir.join("sequencer").exists() {
      return Some("cherry-seq".to_string());
    } else {
      return Some("cherry".to_string());
    }
  }

  if gitdir.join("sequencer").exists() {
    return Some("cherry-or-revert".to_string());
  }

  None
}

pub fn display(sub_matches: &ArgMatches) {
  let my_path = env::current_dir().unwrap();
  let display_path = Blue.paint(shorten_path(my_path.to_str().unwrap()));

  let branch = match Repository::discover(my_path) {
    Ok(repo) => repo_status(&repo, sub_matches.is_present("git-detailed")),
    Err(_e) => None,
  };
  let display_branch = Cyan.paint(branch.unwrap_or_default());

  println!("");
  println!("{} {}", display_path, display_branch);
}

pub fn cli_arguments<'a>() -> App<'a, 'a> {
  SubCommand::with_name("precmd")
    .arg(
      Arg::with_name("git-detailed")
        .long("git-detailed")
        .help("Prints detailed git status")
    )
}
<|endoftext|>


<commit_before>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        {
            let container = try!(self.lookup_mut(id));
            if !container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");

            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // There can be multiple directions we are moving in, e.g up and left.
        let parent_id = try!(self.parent_of(id)).get_id();
        let dirs_moving_in = Direction::from_edge(edge);
        let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| self.sibling_in_dir(id, *dir))
            // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

        // Because we can't have multiple mutable references active in the tree at once,
        // first we modify the one the user is resizing and then adjust the siblings.
        {
            let container = try!(self.lookup_mut(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);
        }
        //....update parent?
        {
            let container = try!(self.lookup_mut(parent_id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                          vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);

        }
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                         vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(reversed_edge, new_geo);
        }
        /*let node_ix = self.tree.lookup_id(id)
            .expect("Could not find node index for an id");
        let workspace_ix = try!(self.tree.ancestor_of_type(node_ix,
                                                           ContainerType::Workspace)
                                .map_err(|err| TreeError::PetGraph(err)));
        self.layout(workspace_ix);*/
        action.grab = pointer;
        self.update_pointer_pos(id, edge)
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        }
    }

    if new_geo.size.w < MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = geo.size.w;
    }

    if new_geo.size.h < MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = geo.size.h;
    }
    new_geo
}

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w != MIN_SIZE.w && geo.size.h != MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<commit_msg>All resize operations are deferred / are atomic<commit_after>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        {
            let container = try!(self.lookup_mut(id));
            if !container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");

            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // This is the vector of operations we will perform, we do all geometry sets atomically.
        let mut resizing_ops: Vec<(Uuid, (ResizeEdge, Geometry))> = Vec::with_capacity(4);
        {
            let container = try!(self.lookup_mut(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            resizing_ops.push((id, (edge, new_geo)));
        }
        let dirs_moving_in = Direction::from_edge(edge);
        let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| self.sibling_in_dir(id, *dir))
        // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

        //....update parent?
        /*{
            let container = try!(self.lookup_mut(parent_id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                          vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);

        }*/
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                         vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            action.grab = pointer;
            resizing_ops.push((sibling, (reversed_edge, new_geo)));
            container.set_geometry(reversed_edge, new_geo);
        }
        for (id, (edge, geo)) in resizing_ops {
            let container = self.lookup_mut(id)
                .expect("Id no longer points to node!");
            container.set_geometry(edge, geo);
        }
        /*let node_ix = self.tree.lookup_id(id)
            .expect("Could not find node index for an id");
        let workspace_ix = try!(self.tree.ancestor_of_type(node_ix,
                                                           ContainerType::Workspace)
                                .map_err(|err| TreeError::PetGraph(err)));
        self.layout(workspace_ix);*/
        action.grab = pointer;
        self.update_pointer_pos(id, edge)
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        }
    }

    if new_geo.size.w < MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = geo.size.w;
    }

    if new_geo.size.h < MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = geo.size.h;
    }
    new_geo
}

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w != MIN_SIZE.w && geo.size.h != MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;

use crate::authentication::Credentials;
use crate::spotify_id::FileId;
use crate::volume::Volume;

#[derive(Clone)]
pub struct Cache {
    root: PathBuf,
    use_audio_cache: bool,
}

fn mkdir_existing(path: &Path) -> io::Result<()> {
    fs::create_dir(path).or_else(|err| {
        if err.kind() == io::ErrorKind::AlreadyExists {
            Ok(())
        } else {
            Err(err)
        }
    })
}

impl Cache {
    pub fn new(location: PathBuf, use_audio_cache: bool) -> Cache {
        mkdir_existing(&location).unwrap();
        mkdir_existing(&location.join("files")).unwrap();

        Cache {
            root: location,
            use_audio_cache: use_audio_cache,
        }
    }
}

impl Cache {
    fn credentials_path(&self) -> PathBuf {
        self.root.join("credentials.json")
    }

    pub fn credentials(&self) -> Option<Credentials> {
        let path = self.credentials_path();
        Credentials::from_file(path)
    }

    pub fn save_credentials(&self, cred: &Credentials) {
        let path = self.credentials_path();
        cred.save_to_file(&path);
    }
}

// cache volume to root/volume
impl Cache {
    fn volume_path(&self) -> PathBuf {
        self.root.join("volume")
    }

    pub fn volume(&self) -> Option<u16> {
        let path = self.volume_path();
        Volume::from_file(path)
    }

    pub fn save_volume(&self, volume: Volume) {
        let path = self.volume_path();
        volume.save_to_file(&path);
    }
}

impl Cache {
    fn file_path(&self, file: FileId) -> PathBuf {
        let name = file.to_base16();
        self.root.join("files").join(&name[0..2]).join(&name[2..])
    }

    pub fn file(&self, file: FileId) -> Option<File> {
        File::open(self.file_path(file)).ok()
    }

    pub fn save_file(&self, file: FileId, contents: &mut dyn Read) {
        if self.use_audio_cache {
            let path = self.file_path(file);

            mkdir_existing(path.parent().unwrap()).unwrap();

            let mut cache_file = File::create(path)
            match cache_file {
                Ok(file) => ::std::io::copy(contents, &mut file).unwrap(),
                Err(error) => {
                    self.use_audio_cache = false
                },
            };
        }
    }
}
<commit_msg>Instead of disabling audio cache, just clean the audio cache and start caching again from the current file<commit_after>use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;

use crate::authentication::Credentials;
use crate::spotify_id::FileId;
use crate::volume::Volume;

#[derive(Clone)]
pub struct Cache {
    root: PathBuf,
    use_audio_cache: bool,
}

fn mkdir_existing(path: &Path) -> io::Result<()> {
    fs::create_dir(path).or_else(|err| {
        if err.kind() == io::ErrorKind::AlreadyExists {
            Ok(())
        } else {
            Err(err)
        }
    })
}

impl Cache {
    pub fn new(location: PathBuf, use_audio_cache: bool) -> Cache {
        mkdir_existing(&location).unwrap();
        mkdir_existing(&location.join("files")).unwrap();

        Cache {
            root: location,
            use_audio_cache: use_audio_cache,
        }
    }
}

impl Cache {
    fn credentials_path(&self) -> PathBuf {
        self.root.join("credentials.json")
    }

    pub fn credentials(&self) -> Option<Credentials> {
        let path = self.credentials_path();
        Credentials::from_file(path)
    }

    pub fn save_credentials(&self, cred: &Credentials) {
        let path = self.credentials_path();
        cred.save_to_file(&path);
    }
}

// cache volume to root/volume
impl Cache {
    fn volume_path(&self) -> PathBuf {
        self.root.join("volume")
    }

    pub fn volume(&self) -> Option<u16> {
        let path = self.volume_path();
        Volume::from_file(path)
    }

    pub fn save_volume(&self, volume: Volume) {
        let path = self.volume_path();
        volume.save_to_file(&path);
    }
}

impl Cache {
    fn file_path(&self, file: FileId) -> PathBuf {
        let name = file.to_base16();
        self.root.join("files").join(&name[0..2]).join(&name[2..])
    }

    pub fn file(&self, file: FileId) -> Option<File> {
        File::open(self.file_path(file)).ok()
    }

    pub fn save_file(&self, file: FileId, contents: &mut dyn Read) {
        if self.use_audio_cache {
            let path = self.file_path(file);
            mkdir_existing(path.parent().unwrap()).unwrap();

            let file_create = File::create(path);
            match file_create {
                Ok(mut cache_file) => {
                    ::std::io::copy(contents, &mut cache_file).unwrap();
                }
                Err(_error) => {
                    ::std::fs::remove_dir_all(&self.root.join("files")).unwrap();
                    mkdir_existing(&self.root.join("files")).unwrap();

                    let path = self.file_path(file);
                    mkdir_existing(path.parent().unwrap()).unwrap();
                    let mut cache_file = File::create(path).unwrap();
                    ::std::io::copy(contents, &mut cache_file).unwrap();
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>//! Magnetic moment (base unit ampere square meter A · m²).

quantity! {
    /// Magnetic moment (base unit ampere square meter A · m²).
    quantity: MagneticMoment; "magnetic moment";
    /// Dimension of magnetic moment, IL² (base unit ampere square meter A · m²).
    dimension: ISQ<
        P2,     // length
        Z0,     // mass
        Z0,     // time
        P1,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @ampere_square_meter: prefix!(none); "A · m²", "ampere square meter",
            "ampere square meters";
        @joule_per_tesla: prefix!(none); "J/T", "joule per tesla", "joules per tesla";
        @newton_meter_per_tesla: prefix!(none); "N · m/T", "newton meter per tesla",
            "newton meters per tesla";
        @ampere_square_centimeter: prefix!(none) * prefix!(centi) * prefix!(centi); "A · cm²",
            "ampere square centimeter", "ampere square centimeters";

        @statampere_square_centimeter: 3.335_641_E-10 * prefix!(centi) * prefix!(centi);
            "statA · cm²", "statampere square centimeter", "statampere square centimeters";
        @erg_per_gauss:  1.0_E-7 / 1.0_E-4; "erg/G", "erg per gauss", "ergs per gauss";

        @bohr_magneton: 9.274_010_0783_E-24; "µBohr",
            "Bohr magneton", "Bohr magnetons";
        @nuclear_magneton: 5.050_783_7461_E-27; "μNuclear",
            "nuclear magneton", "nuclear magnetons";
    }
}

#[cfg(test)]
mod test {
    storage_types! {
        use crate::num::One;
        use crate::si::magnetic_moment as mm;
        use crate::si::electric_current as ec;
        use crate::si::quantities::*;
        use crate::si::energy as e;
        use crate::si::magnetic_flux_density as mfd;
        use crate::si::area as area;
        use crate::tests::Test;

        #[test]
        fn check_dimension() {
            let _: MagneticMoment<V> = ElectricCurrent::new::<ec::ampere>(V::one())
                * Area::new::<area::square_meter>(V::one());
        }

        #[test]
        fn check_units() {
            test::<ec::ampere, area::square_meter, mm::ampere_square_meter>();
            test::<ec::ampere, area::square_meter, mm::joule_per_tesla>();
            test::<ec::ampere, area::square_meter, mm::newton_meter_per_tesla>();
            test::<ec::ampere, area::square_centimeter, mm::ampere_square_centimeter>();
            test::<ec::statampere, area::square_centimeter, mm::statampere_square_centimeter>();

            fn test<EC: ec::Conversion<V>, A: area::Conversion<V>, MM: mm::Conversion<V>>() {
                Test::assert_approx_eq(&MagneticMoment::new::<MM>(V::one()),
                    &(ElectricCurrent::new::<EC>(V::one())
                        * Area::new::<A>(V::one())));
            }
        }

        #[test]
        fn check_units_energy_per_field() {
            test::<e::joule, mfd::tesla, mm::ampere_square_meter>();
            test::<e::joule, mfd::tesla, mm::joule_per_tesla>();
            test::<e::joule, mfd::tesla, mm::newton_meter_per_tesla>();
            test::<e::erg, mfd::gauss, mm::erg_per_gauss>();

            fn test<E: e::Conversion<V>, MFD: mfd::Conversion<V>, MM: mm::Conversion<V>>() {
                Test::assert_approx_eq(&MagneticMoment::new::<MM>(V::one()),
                    &(Energy::new::<E>(V::one())
                        / MagneticFluxDensity::new::<MFD>(V::one())));
            }
        }
    }
}
<commit_msg>Add elementary particle magnetic moment units from CODATA.<commit_after>//! Magnetic moment (base unit ampere square meter A · m²).

quantity! {
    /// Magnetic moment (base unit ampere square meter A · m²).
    quantity: MagneticMoment; "magnetic moment";
    /// Dimension of magnetic moment, IL² (base unit ampere square meter A · m²).
    dimension: ISQ<
        P2,     // length
        Z0,     // mass
        Z0,     // time
        P1,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @ampere_square_meter: prefix!(none); "A · m²", "ampere square meter",
            "ampere square meters";
        @joule_per_tesla: prefix!(none); "J/T", "joule per tesla", "joules per tesla";
        @newton_meter_per_tesla: prefix!(none); "N · m/T", "newton meter per tesla",
            "newton meters per tesla";
        @ampere_square_centimeter: prefix!(none) * prefix!(centi) * prefix!(centi); "A · cm²",
            "ampere square centimeter", "ampere square centimeters";

        @statampere_square_centimeter: 3.335_641_E-10 * prefix!(centi) * prefix!(centi);
            "statA · cm²", "statampere square centimeter", "statampere square centimeters";
        @erg_per_gauss:  1.0_E-7 / 1.0_E-4; "erg/G", "erg per gauss", "ergs per gauss";

        @bohr_magneton: 9.274_010_0783_E-24; "µ(Bohr)", "Bohr magneton", "Bohr magnetons";
        @nuclear_magneton: 5.050_783_7461_E-27; "μ(Nuclear)", "nuclear magneton",
            "nuclear magnetons";
        @atomic_unit_of_magnetic_dipole_moment: 1.854_802_015_66_E-23; "ħ · e/mₑ",
            "atomic unit of magnetic dipole moment", " atomic units of magnetic dipole moment";
        @deuteron_magnetic_moment: 4.330_735_094_E-27; "μ(deuteron)", "deuteron magnetic moment",
            "deuteron magnetic moments";
        @electron_magnetic_moment: -9.284_764_704_3_E-24; "μₑ", "electron magnetic moment",
            "electron magnetic moments";
        @helion_magnetic_moment: -1.074_617_532_E-26; "μ(helion)", "helion magnetic moment",
            "helion magnetic moments";
        @muon_magnetic_moment: -4.490_448_30_E-26; "μ(muon)", "muon magnetic moment",
            "muon magnetic moments";
        @neutron_magnetic_moment: -9.662_365_1_E-27; "μ(neutron)", "neutron magnetic moment",
            "neutron magnetic moments";
        @proton_magnetic_moment: 1.410_606_797_36_E-26; "μ(proton)", "proton magnetic moment",
            "proton magnetic moments";
        @shielded_helion_magnetic_moment: -1.074_553_090_E-26; "μ’(helion)",
            "shielded helion magnetic moment", "shielded helion magnetic moments";
        @shielded_proton_magnetic_moment: 1.410_570_560_E-26; "μ’(proton)",
            "shielded proton magnetic moment", "shielded proton magnetic moments";
        @triton_magnetic_moment: 1.504_609_520_2_E-26; "μ(triton)", "triton magnetic moment",
            "triton magnetic moments";
    }
}

#[cfg(test)]
mod test {
    storage_types! {
        use crate::num::One;
        use crate::si::magnetic_moment as mm;
        use crate::si::electric_current as ec;
        use crate::si::quantities::*;
        use crate::si::energy as e;
        use crate::si::magnetic_flux_density as mfd;
        use crate::si::area as area;
        use crate::tests::Test;

        #[test]
        fn check_dimension() {
            let _: MagneticMoment<V> = ElectricCurrent::new::<ec::ampere>(V::one())
                * Area::new::<area::square_meter>(V::one());
        }

        #[test]
        fn check_units() {
            test::<ec::ampere, area::square_meter, mm::ampere_square_meter>();
            test::<ec::ampere, area::square_meter, mm::joule_per_tesla>();
            test::<ec::ampere, area::square_meter, mm::newton_meter_per_tesla>();
            test::<ec::ampere, area::square_centimeter, mm::ampere_square_centimeter>();
            test::<ec::statampere, area::square_centimeter, mm::statampere_square_centimeter>();

            fn test<EC: ec::Conversion<V>, A: area::Conversion<V>, MM: mm::Conversion<V>>() {
                Test::assert_approx_eq(&MagneticMoment::new::<MM>(V::one()),
                    &(ElectricCurrent::new::<EC>(V::one())
                        * Area::new::<A>(V::one())));
            }
        }

        #[test]
        fn check_units_energy_per_field() {
            test::<e::joule, mfd::tesla, mm::ampere_square_meter>();
            test::<e::joule, mfd::tesla, mm::joule_per_tesla>();
            test::<e::joule, mfd::tesla, mm::newton_meter_per_tesla>();
            test::<e::erg, mfd::gauss, mm::erg_per_gauss>();

            fn test<E: e::Conversion<V>, MFD: mfd::Conversion<V>, MM: mm::Conversion<V>>() {
                Test::assert_approx_eq(&MagneticMoment::new::<MM>(V::one()),
                    &(Energy::new::<E>(V::one())
                        / MagneticFluxDensity::new::<MFD>(V::one())));
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::common::util::*;
use regex::Regex;
use std::os::unix::process::ExitStatusExt;
use std::process::{Child, Command};

// A child process the tests will try to kill.
struct Target {
    child: Child,
    killed: bool,
}

impl Target {
    // Creates a target that will naturally die after some time if not killed
    // fast enough.
    // This timeout avoids hanging failing tests.
    fn new() -> Target {
        Target {
            child: Command::new("sleep")
                .arg("30")
                .spawn()
                .expect("cannot spawn target"),
            killed: false,
        }
    }

    // Waits for the target to complete and returns the signal it received if any.
    fn wait_for_signal(&mut self) -> Option<i32> {
        let sig = self.child.wait().expect("cannot wait on target").signal();
        self.killed = true;
        sig
    }

    fn pid(&self) -> u32 {
        self.child.id()
    }
}

impl Drop for Target {
    // Terminates this target to avoid littering test boxes with zombi processes
    // when a test fails after creating a target but before killing it.
    fn drop(&mut self) {
        if !self.killed {
            self.child.kill().expect("cannot kill target");
        }
    }
}

#[test]
fn test_kill_list_all_signals() {
    // Check for a few signals.  Do not try to be comprehensive.
    new_ucmd!()
        .arg("-l")
        .succeeds()
        .stdout_contains("KILL")
        .stdout_contains("TERM")
        .stdout_contains("HUP");
}

#[test]
fn test_kill_list_final_new_line() {
    new_ucmd!()
        .arg("-l")
        .succeeds()
        .stdout_matches(&Regex::new("\\n$").unwrap());
}

#[test]
fn test_kill_list_all_signals_as_table() {
    // Check for a few signals.  Do not try to be comprehensive.
    new_ucmd!()
        .arg("-t")
        .succeeds()
        .stdout_contains("KILL")
        .stdout_contains("TERM")
        .stdout_contains("HUP");
}

#[test]
fn test_kill_list_one_signal_from_name() {
    // Use SIGKILL because it is 9 on all unixes.
    new_ucmd!()
        .arg("-l")
        .arg("KILL")
        .succeeds()
        .stdout_matches(&Regex::new("\\b9\\b").unwrap());
}

#[test]
fn test_kill_set_bad_signal_name() {
    // spell-checker:disable-line
    new_ucmd!()
        .arg("-s")
        .arg("IAMNOTASIGNAL") // spell-checker:disable-line
        .fails()
        .stderr_contains("unknown signal");
}

#[test]
fn test_kill_with_default_signal() {
    let mut target = Target::new();
    new_ucmd!().arg(format!("{}", target.pid())).succeeds();
    assert_eq!(target.wait_for_signal(), Some(libc::SIGTERM));
}

#[test]
fn test_kill_with_signal_number_old_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-9")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(9));
}

#[test]
fn test_kill_with_signal_number_new_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-s")
        .arg("9")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(9));
}

#[test]
fn test_kill_with_signal_name_new_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-s")
        .arg("KILL")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
}
<commit_msg>fix kill list final new line test<commit_after>use crate::common::util::*;
use regex::Regex;
use std::os::unix::process::ExitStatusExt;
use std::process::{Child, Command};

// A child process the tests will try to kill.
struct Target {
    child: Child,
    killed: bool,
}

impl Target {
    // Creates a target that will naturally die after some time if not killed
    // fast enough.
    // This timeout avoids hanging failing tests.
    fn new() -> Target {
        Target {
            child: Command::new("sleep")
                .arg("30")
                .spawn()
                .expect("cannot spawn target"),
            killed: false,
        }
    }

    // Waits for the target to complete and returns the signal it received if any.
    fn wait_for_signal(&mut self) -> Option<i32> {
        let sig = self.child.wait().expect("cannot wait on target").signal();
        self.killed = true;
        sig
    }

    fn pid(&self) -> u32 {
        self.child.id()
    }
}

impl Drop for Target {
    // Terminates this target to avoid littering test boxes with zombi processes
    // when a test fails after creating a target but before killing it.
    fn drop(&mut self) {
        if !self.killed {
            self.child.kill().expect("cannot kill target");
        }
    }
}

#[test]
fn test_kill_list_all_signals() {
    // Check for a few signals.  Do not try to be comprehensive.
    new_ucmd!()
        .arg("-l")
        .succeeds()
        .stdout_contains("KILL")
        .stdout_contains("TERM")
        .stdout_contains("HUP");
}

#[test]
fn test_kill_list_final_new_line() {
    new_ucmd!()
        .arg("-l")
        .succeeds()
        .stdout_matches(&Regex::new("[\\n\\r]$").unwrap());
}

#[test]
fn test_kill_list_all_signals_as_table() {
    // Check for a few signals.  Do not try to be comprehensive.
    new_ucmd!()
        .arg("-t")
        .succeeds()
        .stdout_contains("KILL")
        .stdout_contains("TERM")
        .stdout_contains("HUP");
}

#[test]
fn test_kill_list_one_signal_from_name() {
    // Use SIGKILL because it is 9 on all unixes.
    new_ucmd!()
        .arg("-l")
        .arg("KILL")
        .succeeds()
        .stdout_matches(&Regex::new("\\b9\\b").unwrap());
}

#[test]
fn test_kill_set_bad_signal_name() {
    // spell-checker:disable-line
    new_ucmd!()
        .arg("-s")
        .arg("IAMNOTASIGNAL") // spell-checker:disable-line
        .fails()
        .stderr_contains("unknown signal");
}

#[test]
fn test_kill_with_default_signal() {
    let mut target = Target::new();
    new_ucmd!().arg(format!("{}", target.pid())).succeeds();
    assert_eq!(target.wait_for_signal(), Some(libc::SIGTERM));
}

#[test]
fn test_kill_with_signal_number_old_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-9")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(9));
}

#[test]
fn test_kill_with_signal_number_new_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-s")
        .arg("9")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(9));
}

#[test]
fn test_kill_with_signal_name_new_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-s")
        .arg("KILL")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
}
<|endoftext|>


<commit_before>use std::process;
use std::process::Command;

fn main() {
    #[cfg(target_os = "macos")]
    fn inner() -> &'static str {
        "open"
    }
    #[cfg(target_os = "windows")]
    fn inner() -> &'static str {
        "start"
    }
    #[cfg(target_os = "linux")]
    fn inner() -> &'static str {
        "xdg-open"
    }
    #[cfg(target_os = "unix")]
    fn inner() -> &'static str {
        "xdg-open"
    }

    let command = inner();
    let arg = "http://groonga.org/docs/";
    let err = match Command::new(command)
        .args(&[arg])
        // .stdout(Stdio::inherit())
        // .stderr(Stdio::inherit())
        .spawn() {
        Ok(_) => return (),
        Err(e) => e,
    };
    println!("Failed to execute docopen subcommand. reason: {:?}", err);
    process::exit(1);

}
<commit_msg>grnenv-docopen: Suppress stdio outputs<commit_after>use std::process;
use std::process::{Command, Stdio};

fn main() {
    #[cfg(target_os = "macos")]
    fn inner() -> &'static str {
        "open"
    }
    #[cfg(target_os = "windows")]
    fn inner() -> &'static str {
        "start"
    }
    #[cfg(target_os = "linux")]
    fn inner() -> &'static str {
        "xdg-open"
    }
    #[cfg(target_os = "unix")]
    fn inner() -> &'static str {
        "xdg-open"
    }

    let command = inner();
    let arg = "http://groonga.org/docs/";
    let err = match Command::new(command)
        .args(&[arg])
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn() {
        Ok(_) => return (),
        Err(e) => e,
    };
    println!("Failed to execute docopen subcommand. reason: {:?}", err);
    process::exit(1);

}
<|endoftext|>