<commit_before>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()
        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // self.parse_let()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // self.parse_var()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // self.parse_def()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::If).is_some() {
            // self.parse_if()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // self.parse_using()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::While).is_some() {
            // self.parse_while()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // self.parse_loop()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::For).is_some() {
            // self.parse_for()
            unimplemented!()
        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()
        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Ignore newlines within an expression
            self.parse_expression()

        } else if let Some(identifier) = self.accept(ScriptLexerToken::Identifier) {
            // Simple expression
            Ok(Expression::Identifier(identifier.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::Number) {
            // Simple expression
            Ok(Expression::Number(number.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::HexNumber) {
            // Hex numbers work like normal numbers
            Ok(Expression::Number(number.clone()))

        } else if let Some(string) = self.accept(ScriptLexerToken::String) {
            // Simple expression
            Ok(Expression::String(string.clone()))

        } else {
            // Syntax error
            Err(ParseError::new())

        }
    }

    /*
    pub fn parse_let<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_var<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_def<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_if<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_using<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_while<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_loop<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_for<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }
    */
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<commit_msg>Put the unimplemented parsing bits back in<commit_after>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()

        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // let identifier = expression
            self.parse_let()

        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // var identifier = expression
            self.parse_var()

        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // def fn args { statements }
            self.parse_def()

        } else if self.accept(ScriptLexerToken::If).is_some() {
            // if expression { statements }
            self.parse_if()

        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // using expression { statements }
            self.parse_using()

        } else if self.accept(ScriptLexerToken::While).is_some() {
            // while expression { statements }
            self.parse_while()

        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // loop { statements }
            self.parse_loop()

        } else if self.accept(ScriptLexerToken::For).is_some() {
            // for identifier in expression { statements }
            self.parse_for()

        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()

        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Ignore newlines within an expression
            self.parse_expression()

        } else if let Some(identifier) = self.accept(ScriptLexerToken::Identifier) {
            // Simple expression
            Ok(Expression::Identifier(identifier.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::Number) {
            // Simple expression
            Ok(Expression::Number(number.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::HexNumber) {
            // Hex numbers work like normal numbers
            Ok(Expression::Number(number.clone()))

        } else if let Some(string) = self.accept(ScriptLexerToken::String) {
            // Simple expression
            Ok(Expression::String(string.clone()))

        } else {
            // Syntax error
            Err(ParseError::new())

        }
    }

    pub fn parse_let(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_var(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_def(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_if(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_using(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_while(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_loop(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }

    pub fn parse_for(&mut self) -> Result<Script, ParseError> {
        unimplemented!()
    }
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<|endoftext|>


<commit_before>use fall_tree::{NodeType, FileStats};
use lex::Token;

use tree_builder::{Node, TokenSequence};

pub struct Parser<'r> {
    node_types: &'r [NodeType],
    rules: &'r [SynRule],
    layers: Vec<&'r Expr>,
}

#[derive(Serialize, Deserialize)]
pub struct SynRule {
    pub ty: Option<usize>,
    pub body: Expr,
}

#[derive(Serialize, Deserialize)]
pub enum Expr {
    Or(Vec<Expr>),
    And(Vec<Expr>, Option<usize>),
    Rule(usize),
    Token(usize),
    Rep(Box<Expr>),
    Opt(Box<Expr>),
    Not(Vec<usize>),
    NotAhead(Box<Expr>),
    Eof,
    Layer(Box<Expr>, Box<Expr>),
    SkipUntil(Vec<usize>),
}

struct Ctx {
    ticks: u64,
    predicate_mode: bool,
}

impl Ctx {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_layer(&mut self, layer: u32) -> Node {
        Node::layer(layer)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

fn find_layers<'r>(rules: &'r [SynRule]) -> Vec<&'r Expr> {
    let mut result = Vec::new();
    for r in rules {
        go(&r.body, &mut result);
    }
    return result;
    fn go<'r>(expr: &'r Expr, acc: &mut Vec<&'r Expr>) {
        match *expr {
            Expr::Rule(_) | Expr::Token(_) | Expr::Not(_) |
            Expr::NotAhead(_) | Expr::Eof | Expr::SkipUntil(_) => return,
            Expr::Or(ref exprs) | Expr::And(ref exprs, _) => {
                for e in exprs {
                    go(e, acc)
                }
            }
            Expr::Rep(ref e) | Expr::Opt(ref e) => go(e, acc),
            Expr::Layer(..) => acc.push(expr)
        }
    }
}

impl<'r> Parser<'r> {
    pub fn new(node_types: &'r [NodeType], rules: &'r [SynRule]) -> Parser<'r> {
        let layers = find_layers(rules);
        Parser { node_types, rules: rules, layers: layers }
    }

    pub fn parse(&self, tokens: TokenSequence, stats: &mut FileStats) -> Node {
        let mut ctx = Ctx { ticks: 0, predicate_mode: false };
        let (mut file_node, mut leftover) = self
            .parse_exp(&Expr::Rule(0), tokens, &mut ctx)
            .unwrap_or_else(|| {
                let ty = self.node_type(self.rules[0].ty
                    .expect("First rule must be public"));
                (ctx.create_composite_node(Some(ty)), tokens)
            });
        let mut error = ctx.create_error_node();
        let mut skipped = false;
        while leftover.current().is_some() {
            skipped = true;
            let p = ctx.create_leaf_node(leftover);
            leftover = p.1;
            ctx.push_child(&mut error, p.0)
        }
        if skipped {
            ctx.push_child(&mut file_node, error)
        }
        stats.parsing_ticks = ctx.ticks;
        file_node
    }

    pub fn reparse(&self, parser_id: u32, tokens: TokenSequence, stats: &mut FileStats) -> Option<Node> {
        let expr = self.layers[parser_id as usize];
        let mut ctx = Ctx { ticks: 0, predicate_mode: false };
        if let Some((node, rest)) = self.parse_exp(expr, tokens, &mut ctx) {
            if rest.current().is_some() {
                return None
            }
            stats.parsing_ticks = ctx.ticks;
            return Some(node)
        }
        None
    }

    fn parse_exp<'t>(&self, expr: &Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx)
                     -> Option<(Node, TokenSequence<'t>)> {
        ctx.ticks += 1;
        match *expr {
            Expr::Or(ref parts) => {
                for p in parts.iter() {
                    if let Some(result) = self.parse_exp(p, tokens, ctx) {
                        return Some(result)
                    }
                }
                None
            }

            Expr::And(ref parts, commit) => {
                let mut node = ctx.create_composite_node(None);
                let commit = commit.unwrap_or(parts.len());
                let mut tokens = tokens;
                for (i, p) in parts.iter().enumerate() {
                    if let Some((n, ts)) = self.parse_exp(p, tokens, ctx) {
                        tokens = ts;
                        ctx.push_child(&mut node, n);
                    } else {
                        if i < commit {
                            return None
                        }
                        let error_node = ctx.create_error_node();
                        ctx.push_child(&mut node, error_node);
                        break
                    }
                }
                Some((node, tokens))
            }

            Expr::Rule(id) => {
                let rule = &self.rules[id];
                let ty = rule.ty.map(|ty| self.node_type(ty));
                if let Some((node, ts)) = self.parse_exp(&rule.body, tokens, ctx) {
                    let mut result = ctx.create_composite_node(ty);
                    ctx.push_child(&mut result, node);
                    Some((result, ts))
                } else {
                    None
                }
            }

            Expr::Token(ty) => {
                if let Some(current) = tokens.current() {
                    if self.token_set_contains(&[ty], current) {
                        return Some(ctx.create_leaf_node(tokens))
                    }
                }
                None
            }

            Expr::Opt(ref body) => self.parse_exp(&*body, tokens, ctx).or_else(|| {
                Some(ctx.create_success_node(tokens))
            }),
            Expr::Not(ref ts) => {
                if let Some(current) = tokens.current() {
                    if !self.token_set_contains(ts, current) {
                        return Some(ctx.create_leaf_node(tokens))
                    }
                }
                None
            }

            Expr::NotAhead(ref e) => if self.parse_exp(e, tokens, ctx).is_some() {
                None
            } else {
                Some(ctx.create_success_node(tokens))
            },
            Expr::Eof => if tokens.current().is_none() {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },
            Expr::Layer(ref l, ref e) => {
                let layer = {
                    let old_mode = ctx.predicate_mode;
                    ctx.predicate_mode = true;
                    let layer = self.parse_exp(l, tokens, ctx);
                    ctx.predicate_mode = old_mode;
                    layer
                };

                if let Some((_, rest)) = layer {
                    let layer_id = self.layers.iter()
                        .position(|&l| l as *const Expr == expr as *const Expr)
                        .unwrap();

                    let mut result = ctx.create_layer(layer_id as u32);
                    let layer = tokens.prefix(rest);
                    if let Some((layer_contents, mut leftovers)) = self.parse_exp(e, layer, ctx) {
                        ctx.push_child(&mut result, layer_contents);
                        if leftovers.current().is_some() {
                            let mut error = ctx.create_error_node();
                            while leftovers.current().is_some() {
                                let p = ctx.create_leaf_node(leftovers);
                                ctx.push_child(&mut error, p.0);
                                leftovers = p.1;
                            }
                            ctx.push_child(&mut result, error)
                        }
                    };
                    return Some((result, rest));
                };
                None
            }

            Expr::Rep(ref body) => {
                let mut node = ctx.create_composite_node(None);
                let mut tokens = tokens;
                loop {
                    if let Some((n, t)) = self.parse_exp(body, tokens, ctx) {
                        ctx.push_child(&mut node, n);
                        tokens = t;
                    } else {
                        break;
                    }
                }
                Some((node, tokens))
            }

            Expr::SkipUntil(ref ts) => {
                let mut result = ctx.create_error_node();
                let mut skipped = false;
                let mut tokens = tokens;
                loop {
                    if let Some(t) = tokens.current() {
                        if self.token_set_contains(ts, t) {
                            break;
                        } else {
                            skipped = true;
                            let p = ctx.create_leaf_node(tokens);
                            ctx.push_child(&mut result, p.0);
                            tokens = p.1;
                        }
                    } else {
                        break
                    }
                }

                if !skipped {
                    return Some(ctx.create_success_node(tokens));
                }

                Some((result, tokens))
            }
        }
    }

    fn token_set_contains(&self, ts: &[usize], token: Token) -> bool {
        ts.iter().any(|&t| self.node_type(t) == token.ty)
    }

    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}
<commit_msg>Fix skip until, probably<commit_after>use fall_tree::{NodeType, FileStats};
use lex::Token;

use tree_builder::{Node, TokenSequence};

pub struct Parser<'r> {
    node_types: &'r [NodeType],
    rules: &'r [SynRule],
    layers: Vec<&'r Expr>,
}

#[derive(Serialize, Deserialize)]
pub struct SynRule {
    pub ty: Option<usize>,
    pub body: Expr,
}

#[derive(Serialize, Deserialize)]
pub enum Expr {
    Or(Vec<Expr>),
    And(Vec<Expr>, Option<usize>),
    Rule(usize),
    Token(usize),
    Rep(Box<Expr>),
    Opt(Box<Expr>),
    Not(Vec<usize>),
    NotAhead(Box<Expr>),
    Eof,
    Layer(Box<Expr>, Box<Expr>),
    SkipUntil(Vec<usize>),
}

struct Ctx {
    ticks: u64,
    predicate_mode: bool,
}

impl Ctx {
    fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::composite(ty)
    }

    fn create_layer(&mut self, layer: u32) -> Node {
        Node::layer(layer)
    }

    fn create_error_node(&mut self) -> Node {
        Node::error()
    }

    fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        tokens.bump()
    }

    fn create_success_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        Node::success(tokens)
    }

    fn push_child(&self, parent: &mut Node, child: Node) {
        if self.predicate_mode {
            return;
        }
        match child {
            // Microoptimization: don't store empty success nodes
            Node::Composite { ty: None, ref children, .. } if children.is_empty() => return,
            _ => {}
        }
        parent.push_child(child)
    }
}

fn find_layers<'r>(rules: &'r [SynRule]) -> Vec<&'r Expr> {
    let mut result = Vec::new();
    for r in rules {
        go(&r.body, &mut result);
    }
    return result;
    fn go<'r>(expr: &'r Expr, acc: &mut Vec<&'r Expr>) {
        match *expr {
            Expr::Rule(_) | Expr::Token(_) | Expr::Not(_) |
            Expr::NotAhead(_) | Expr::Eof | Expr::SkipUntil(_) => return,
            Expr::Or(ref exprs) | Expr::And(ref exprs, _) => {
                for e in exprs {
                    go(e, acc)
                }
            }
            Expr::Rep(ref e) | Expr::Opt(ref e) => go(e, acc),
            Expr::Layer(..) => acc.push(expr)
        }
    }
}

impl<'r> Parser<'r> {
    pub fn new(node_types: &'r [NodeType], rules: &'r [SynRule]) -> Parser<'r> {
        let layers = find_layers(rules);
        Parser { node_types, rules: rules, layers: layers }
    }

    pub fn parse(&self, tokens: TokenSequence, stats: &mut FileStats) -> Node {
        let mut ctx = Ctx { ticks: 0, predicate_mode: false };
        let (mut file_node, mut leftover) = self
            .parse_exp(&Expr::Rule(0), tokens, &mut ctx)
            .unwrap_or_else(|| {
                let ty = self.node_type(self.rules[0].ty
                    .expect("First rule must be public"));
                (ctx.create_composite_node(Some(ty)), tokens)
            });
        let mut error = ctx.create_error_node();
        let mut skipped = false;
        while leftover.current().is_some() {
            skipped = true;
            let p = ctx.create_leaf_node(leftover);
            leftover = p.1;
            ctx.push_child(&mut error, p.0)
        }
        if skipped {
            ctx.push_child(&mut file_node, error)
        }
        stats.parsing_ticks = ctx.ticks;
        file_node
    }

    pub fn reparse(&self, parser_id: u32, tokens: TokenSequence, stats: &mut FileStats) -> Option<Node> {
        let expr = self.layers[parser_id as usize];
        let mut ctx = Ctx { ticks: 0, predicate_mode: false };
        if let Some((node, rest)) = self.parse_exp(expr, tokens, &mut ctx) {
            if rest.current().is_some() {
                return None
            }
            stats.parsing_ticks = ctx.ticks;
            return Some(node)
        }
        None
    }

    fn parse_exp<'t>(&self, expr: &Expr, tokens: TokenSequence<'t>, ctx: &mut Ctx)
                     -> Option<(Node, TokenSequence<'t>)> {
        ctx.ticks += 1;
        match *expr {
            Expr::Or(ref parts) => {
                for p in parts.iter() {
                    if let Some(result) = self.parse_exp(p, tokens, ctx) {
                        return Some(result)
                    }
                }
                None
            }

            Expr::And(ref parts, commit) => {
                let mut node = ctx.create_composite_node(None);
                let commit = commit.unwrap_or(parts.len());
                let mut tokens = tokens;
                for (i, p) in parts.iter().enumerate() {
                    if let Some((n, ts)) = self.parse_exp(p, tokens, ctx) {
                        tokens = ts;
                        ctx.push_child(&mut node, n);
                    } else {
                        if i < commit {
                            return None
                        }
                        let error_node = ctx.create_error_node();
                        ctx.push_child(&mut node, error_node);
                        break
                    }
                }
                Some((node, tokens))
            }

            Expr::Rule(id) => {
                let rule = &self.rules[id];
                let ty = rule.ty.map(|ty| self.node_type(ty));
                if let Some((node, ts)) = self.parse_exp(&rule.body, tokens, ctx) {
                    let mut result = ctx.create_composite_node(ty);
                    ctx.push_child(&mut result, node);
                    Some((result, ts))
                } else {
                    None
                }
            }

            Expr::Token(ty) => {
                if let Some(current) = tokens.current() {
                    if self.token_set_contains(&[ty], current) {
                        return Some(ctx.create_leaf_node(tokens))
                    }
                }
                None
            }

            Expr::Opt(ref body) => self.parse_exp(&*body, tokens, ctx).or_else(|| {
                Some(ctx.create_success_node(tokens))
            }),
            Expr::Not(ref ts) => {
                if let Some(current) = tokens.current() {
                    if !self.token_set_contains(ts, current) {
                        return Some(ctx.create_leaf_node(tokens))
                    }
                }
                None
            }

            Expr::NotAhead(ref e) => if self.parse_exp(e, tokens, ctx).is_some() {
                None
            } else {
                Some(ctx.create_success_node(tokens))
            },
            Expr::Eof => if tokens.current().is_none() {
                Some(ctx.create_success_node(tokens))
            } else {
                None
            },
            Expr::Layer(ref l, ref e) => {
                let layer = {
                    let old_mode = ctx.predicate_mode;
                    ctx.predicate_mode = true;
                    let layer = self.parse_exp(l, tokens, ctx);
                    ctx.predicate_mode = old_mode;
                    layer
                };

                if let Some((_, rest)) = layer {
                    let layer_id = self.layers.iter()
                        .position(|&l| l as *const Expr == expr as *const Expr)
                        .unwrap();

                    let mut result = ctx.create_layer(layer_id as u32);
                    let layer = tokens.prefix(rest);
                    if let Some((layer_contents, mut leftovers)) = self.parse_exp(e, layer, ctx) {
                        ctx.push_child(&mut result, layer_contents);
                        if leftovers.current().is_some() {
                            let mut error = ctx.create_error_node();
                            while leftovers.current().is_some() {
                                let p = ctx.create_leaf_node(leftovers);
                                ctx.push_child(&mut error, p.0);
                                leftovers = p.1;
                            }
                            ctx.push_child(&mut result, error)
                        }
                    };
                    return Some((result, rest));
                };
                None
            }

            Expr::Rep(ref body) => {
                let mut node = ctx.create_composite_node(None);
                let mut tokens = tokens;
                loop {
                    if let Some((n, t)) = self.parse_exp(body, tokens, ctx) {
                        ctx.push_child(&mut node, n);
                        tokens = t;
                    } else {
                        break;
                    }
                }
                Some((node, tokens))
            }

            Expr::SkipUntil(ref ts) => {
                let mut result = ctx.create_error_node();
                let mut skipped = false;
                let mut tokens = tokens;
                loop {
                    if let Some(t) = tokens.current() {
                        if self.token_set_contains(ts, t) {
                            break;
                        } else {
                            skipped = true;
                            let p = ctx.create_leaf_node(tokens);
                            ctx.push_child(&mut result, p.0);
                            tokens = p.1;
                        }
                    } else {
                        return None
                    }
                }

                if !skipped {
                    return Some(ctx.create_success_node(tokens));
                }

                Some((result, tokens))
            }
        }
    }

    fn token_set_contains(&self, ts: &[usize], token: Token) -> bool {
        ts.iter().any(|&t| self.node_type(t) == token.ty)
    }

    fn node_type(&self, idx: usize) -> NodeType {
        self.node_types[idx]
    }
}
<|endoftext|>


<commit_before>
use std::ops::Fn;
use regex::{Captures, Regex};

/// A Parser is designed to take an input type and turn part of it into an
/// output type.  Probably in every real-life scenario, the input type is a
/// slice of some type.  Thus a parser returns an output type along with another
/// input type, which for slices would be the rest of the data.
pub trait Parser<'a, I, O> {

  fn parse(&self, data: I) -> ParseResult<'a, I, O>;

}

pub type ParseResult<'a, I:'a, O> = Result<(O, I), String>;

pub fn literal<'a, T:'a + Eq + Clone>(literal: T) -> LiteralParser<'a, T>{
  LiteralParser{literal: literal}
}

/// A parser that consumes one item in a slice and only returns ok if it equals
/// the given literal
pub struct LiteralParser<'a, T:'a + Eq + Clone> {
  pub literal: T,
}

impl<'a, T: 'a + Eq + Clone> Parser<'a,  &'a [T], T> for LiteralParser<'a, T> {
  fn parse(&self, data: &'a[T]) -> ParseResult<'a, &'a[T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), data.slice_from(1)))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

/// A string Parser that attempts to consume the given regex
pub struct RegexLiteralParser<'a> {
  pub regex: Regex,
}

impl<'a> Parser<'a, &'a str, ()> for RegexLiteralParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, ()> {
    self.regex.find(data).map(|(_, e)| ((), data.slice_from(e))).ok_or(format!("regex literal match fail"))
  }
}

pub struct RegexCapturesParser<'a> {
  pub regex: Regex,
}
impl<'a> Parser<'a, &'a str, Captures<'a>> for RegexCapturesParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, Captures<'a>> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok((caps, data.slice_from(e))),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

/// A slice Parser that matches against the first item in the slice
pub struct MatchParser<'a, I, O> {
  pub matcher: Box< Fn<(&'a I,), Result<O, String>> +'a>
}
impl<'a, I: Clone, O> Parser<'a, &'a [I], O> for MatchParser<'a, I, O> {
  fn parse(&self, data: &'a[I]) -> ParseResult<'a, &'a[I], O> {
    if data.len() < 1 {
      Err(format!("Unexpected End!"))
    } else {
      self.matcher.call((&data[0],)).map(|res| (res, data.slice_from(1)))
    }
  }
}

/// A Parser that will keep repeating the given parser until it returns an
/// error.  The accumulated results are returned.
pub struct RepParser<'a, I, O, P: Parser<'a, I, O>>{
  pub parser: P
}

impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Vec<O>> for RepParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

/// A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
/// returns an error.  The accumulated `rep` results are returned.  If `rep`
/// returns an error at any time, the error is escelated.
pub struct RepSepParser<'a, I, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> {
  pub rep: A,
  pub sep: B,
  pub min_reps: usize,
}
impl<'a, I: Clone, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> Parser<'a, I, Vec<O>> for RepSepParser<'a, I, O, U, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
  }
}

/// A Parser that will combine two parsers into a tuple of results.  If either
/// parser returns an error, the error is escelated (ie partial successes are
/// not returned)
pub struct DualParser<'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> {
  pub first: X,
  pub second: Y,
}

impl <'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> Parser<'a, I, (A,B)> for DualParser<'a, I, A, B, X, Y> {
  fn parse(&self, data: I) -> ParseResult<'a, I, (A, B)> {
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

//memoization coming sooooon
pub struct LazyParser<'a, I, O> {
  pub generator: Box<Fn() -> Box<Parser<'a, I, O> + 'a> + 'a>
}
impl<'a, I, O> Parser<'a, I, O> for LazyParser<'a, I, O> {
  fn parse(&self, input: I) -> ParseResult<'a, I, O> {
    self.generator.call(()).parse(input)
  }
}

/// A parser that will attempt to parse using parser `a`, and then `b` if
/// the first fails.  The contained parsers are lazy so that we can support recursive
/// grammars.
///
/// In general, the "greedier" parser should be `a`.
pub struct OrParser<'a, I, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> {
  pub a: A,
  pub b: B,
}

impl<'a, I: Clone, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> Parser<'a, I, O> for OrParser<'a, I, O, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    match self.a.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.b.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

/// A Parser that can map the successful result of a parser to another type
pub struct MapParser<'a, I, O, U, P: Parser<'a, I, O>> {
  pub parser: P,
  pub mapper: Box<Fn<(O,), U> + 'a>, //this has to be a &Fn and not a regular lambda since it must be immutable
}
impl<'a, I, O, U, P: Parser<'a, I, O>> Parser<'a, I, U> for MapParser<'a, I, O, U, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, U> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper.call((output,)), input)))
  }
}

/// A Parser that will attempt to use a parser, returning an option of the contained parser's result
pub struct OptionParser<'a, I, O, P: Parser<'a, I, O>> {
  pub parser: P
}
impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Option<O>> for OptionParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Option<O>> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

<commit_msg>fixing Fn syntax for latest rust nightly<commit_after>
use std::ops::Fn;
use regex::{Captures, Regex};

/// A Parser is designed to take an input type and turn part of it into an
/// output type.  Probably in every real-life scenario, the input type is a
/// slice of some type.  Thus a parser returns an output type along with another
/// input type, which for slices would be the rest of the data.
pub trait Parser<'a, I, O> {

  fn parse(&self, data: I) -> ParseResult<'a, I, O>;

}

pub type ParseResult<'a, I:'a, O> = Result<(O, I), String>;

pub fn literal<'a, T:'a + Eq + Clone>(literal: T) -> LiteralParser<'a, T>{
  LiteralParser{literal: literal}
}

/// A parser that consumes one item in a slice and only returns ok if it equals
/// the given literal
pub struct LiteralParser<'a, T:'a + Eq + Clone> {
  pub literal: T,
}

impl<'a, T: 'a + Eq + Clone> Parser<'a,  &'a [T], T> for LiteralParser<'a, T> {
  fn parse(&self, data: &'a[T]) -> ParseResult<'a, &'a[T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), data.slice_from(1)))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

/// A string Parser that attempts to consume the given regex
pub struct RegexLiteralParser<'a> {
  pub regex: Regex,
}

impl<'a> Parser<'a, &'a str, ()> for RegexLiteralParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, ()> {
    self.regex.find(data).map(|(_, e)| ((), data.slice_from(e))).ok_or(format!("regex literal match fail"))
  }
}

pub struct RegexCapturesParser<'a> {
  pub regex: Regex,
}
impl<'a> Parser<'a, &'a str, Captures<'a>> for RegexCapturesParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, Captures<'a>> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok((caps, data.slice_from(e))),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

/// A slice Parser that matches against the first item in the slice
pub struct MatchParser<'a, I, O> {
  pub matcher: Box< Fn(&'a I) -> Result<O, String> +'a>
}
impl<'a, I: Clone, O> Parser<'a, &'a [I], O> for MatchParser<'a, I, O> {
  fn parse(&self, data: &'a[I]) -> ParseResult<'a, &'a[I], O> {
    if data.len() < 1 {
      Err(format!("Unexpected End!"))
    } else {
      self.matcher.call((&data[0],)).map(|res| (res, data.slice_from(1)))
    }
  }
}

/// A Parser that will keep repeating the given parser until it returns an
/// error.  The accumulated results are returned.
pub struct RepParser<'a, I, O, P: Parser<'a, I, O>>{
  pub parser: P
}

impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Vec<O>> for RepParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

/// A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
/// returns an error.  The accumulated `rep` results are returned.  If `rep`
/// returns an error at any time, the error is escelated.
pub struct RepSepParser<'a, I, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> {
  pub rep: A,
  pub sep: B,
  pub min_reps: usize,
}
impl<'a, I: Clone, O, U, A: Parser<'a, I, O>, B: Parser<'a, I, U>> Parser<'a, I, Vec<O>> for RepSepParser<'a, I, O, U, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
  }
}

/// A Parser that will combine two parsers into a tuple of results.  If either
/// parser returns an error, the error is escelated (ie partial successes are
/// not returned)
pub struct DualParser<'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> {
  pub first: X,
  pub second: Y,
}

impl <'a, I, A, B, X: Parser<'a, I, A>, Y: Parser<'a, I, B>> Parser<'a, I, (A,B)> for DualParser<'a, I, A, B, X, Y> {
  fn parse(&self, data: I) -> ParseResult<'a, I, (A, B)> {
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

//memoization coming sooooon
pub struct LazyParser<'a, I, O> {
  pub generator: Box<Fn() -> Box<Parser<'a, I, O> + 'a> + 'a>
}
impl<'a, I, O> Parser<'a, I, O> for LazyParser<'a, I, O> {
  fn parse(&self, input: I) -> ParseResult<'a, I, O> {
    self.generator.call(()).parse(input)
  }
}

/// A parser that will attempt to parse using parser `a`, and then `b` if
/// the first fails.  The contained parsers are lazy so that we can support recursive
/// grammars.
///
/// In general, the "greedier" parser should be `a`.
pub struct OrParser<'a, I, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> {
  pub a: A,
  pub b: B,
}

impl<'a, I: Clone, O, A: Parser<'a, I, O>, B: Parser<'a, I, O>> Parser<'a, I, O> for OrParser<'a, I, O, A, B> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    match self.a.parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.b.parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

/// A Parser that can map the successful result of a parser to another type
pub struct MapParser<'a, I, O, U, P: Parser<'a, I, O>> {
  pub parser: P,
  pub mapper: Box<Fn(O) -> U + 'a>, //this has to be a &Fn and not a regular lambda since it must be immutable
}
impl<'a, I, O, U, P: Parser<'a, I, O>> Parser<'a, I, U> for MapParser<'a, I, O, U, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, U> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper.call((output,)), input)))
  }
}

/// A Parser that will attempt to use a parser, returning an option of the contained parser's result
pub struct OptionParser<'a, I, O, P: Parser<'a, I, O>> {
  pub parser: P
}
impl<'a, I: Clone, O, P: Parser<'a, I, O>> Parser<'a, I, Option<O>> for OptionParser<'a, I, O, P> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Option<O>> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

<|endoftext|>


<commit_before>// These methods are described in:
// http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use

use libc;
use super::Result;

/// Get the current RSS memory of this process in KB
#[cfg(target_os = "linux")]
pub fn current_rss() -> Result<u64> {
    os::current_rss()
}

/// Get the current RSS memory of a process with given pid in KB
#[cfg(target_os = "linux")]
pub fn current_rss_of(pid: libc::pid_t) -> Result<u64> {
    os::current_rss_of(pid)
}

/// Get the max RSS memory of this process in KB
#[cfg(target_os = "linux")]
pub fn max_rss() -> u64 {
    os::max_rss()
}

#[cfg(target_os = "linux")]
mod os {
    use std::mem;
    use libc;
    use std::path::Path;
    use super::super::Result;
    use super::super::ProbeError;
    use super::super::file_to_string;

    #[inline]
    pub fn current_rss() -> Result<u64> {
        read_and_get_current_rss(&Path::new("/proc/self/statm"))
    }

    #[inline]
    pub fn current_rss_of(pid: libc::pid_t) -> Result<u64> {
        read_and_get_current_rss(&Path::new(&format!("/proc/{}/statm", pid)))
    }

    #[inline]
    pub fn read_and_get_current_rss(path: &Path) -> Result<u64> {
        let raw_data = try!(file_to_string(path));
        let segments: Vec<&str> = raw_data.split_whitespace().collect();

        if segments.len() < 2 {
            return Err(ProbeError::UnexpectedContent("Incorrect number of segments".to_owned()))
        }

        let pages: u64 = try!(segments[1].parse().map_err(|_| {
            ProbeError::UnexpectedContent("Could not parse segment".to_owned())
        }));

        // Value is in pages, needs to be multiplied by the page size to get a value in KB. We ask the OS
        // for this information using sysconf.
        let pagesize = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as u64 / 1024;

        Ok(pages * pagesize)
    }

    #[inline]
    pub fn max_rss() -> u64 {
        let mut rusage: libc::rusage = unsafe { mem::uninitialized() };
        unsafe { libc::getrusage(libc::RUSAGE_SELF, &mut rusage) };
        rusage.ru_maxrss as u64
    }
}

#[cfg(test)]
mod tests {
    use libc;
    use std::path::Path;
    use super::super::ProbeError;

    #[test]
    fn test_current_rss() {
        assert!(super::current_rss().is_ok());
        // See if it's a sort of sane value, between 1 and 250 mb
        assert!(super::current_rss().unwrap() > 1_000);
        assert!(super::current_rss().unwrap() < 50_000);
    }

    #[test]
    fn test_read_and_get_current_rss() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm");
        let value = super::os::read_and_get_current_rss(&path).unwrap();
        assert_eq!(4552, value);
    }

    #[test]
    fn test_read_and_get_current_rss_wrong_path() {
        let path = Path::new("/nonsense");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::IO(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_incomplete() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_incomplete");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_garbage() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_garbage");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_current_rss_of() {
        let pid = unsafe { libc::getpid() };
        assert!(super::current_rss_of(pid).is_ok());
        // See if it's a sort of sane value, between 1 and 50 mb
        assert!(super::current_rss_of(pid).unwrap() > 1_000);
        assert!(super::current_rss_of(pid).unwrap() < 50_000);
    }

    #[test]
    fn test_current_rss_of_invalid_pid() {
        assert!(super::current_rss_of(0).is_err());
    }

    #[test]
    fn test_max_rss() {
        // See if it's a sort of sane value, between 1 and 50 mb
        assert!(super::max_rss() > 1_000);
        assert!(super::max_rss() < 50_000);
    }
}
<commit_msg>Fix process memory test again on Travis<commit_after>// These methods are described in:
// http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use

use libc;
use super::Result;

/// Get the current RSS memory of this process in KB
#[cfg(target_os = "linux")]
pub fn current_rss() -> Result<u64> {
    os::current_rss()
}

/// Get the current RSS memory of a process with given pid in KB
#[cfg(target_os = "linux")]
pub fn current_rss_of(pid: libc::pid_t) -> Result<u64> {
    os::current_rss_of(pid)
}

/// Get the max RSS memory of this process in KB
#[cfg(target_os = "linux")]
pub fn max_rss() -> u64 {
    os::max_rss()
}

#[cfg(target_os = "linux")]
mod os {
    use std::mem;
    use libc;
    use std::path::Path;
    use super::super::Result;
    use super::super::ProbeError;
    use super::super::file_to_string;

    #[inline]
    pub fn current_rss() -> Result<u64> {
        read_and_get_current_rss(&Path::new("/proc/self/statm"))
    }

    #[inline]
    pub fn current_rss_of(pid: libc::pid_t) -> Result<u64> {
        read_and_get_current_rss(&Path::new(&format!("/proc/{}/statm", pid)))
    }

    #[inline]
    pub fn read_and_get_current_rss(path: &Path) -> Result<u64> {
        let raw_data = try!(file_to_string(path));
        let segments: Vec<&str> = raw_data.split_whitespace().collect();

        if segments.len() < 2 {
            return Err(ProbeError::UnexpectedContent("Incorrect number of segments".to_owned()))
        }

        let pages: u64 = try!(segments[1].parse().map_err(|_| {
            ProbeError::UnexpectedContent("Could not parse segment".to_owned())
        }));

        // Value is in pages, needs to be multiplied by the page size to get a value in KB. We ask the OS
        // for this information using sysconf.
        let pagesize = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as u64 / 1024;

        Ok(pages * pagesize)
    }

    #[inline]
    pub fn max_rss() -> u64 {
        let mut rusage: libc::rusage = unsafe { mem::uninitialized() };
        unsafe { libc::getrusage(libc::RUSAGE_SELF, &mut rusage) };
        rusage.ru_maxrss as u64
    }
}

#[cfg(test)]
mod tests {
    use libc;
    use std::path::Path;
    use super::super::ProbeError;

    #[test]
    fn test_current_rss() {
        assert!(super::current_rss().is_ok());
        // See if it's a sort of sane value, between 1 and 250 mb
        assert!(super::current_rss().unwrap() > 1_000);
        assert!(super::current_rss().unwrap() < 250_000);
    }

    #[test]
    fn test_read_and_get_current_rss() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm");
        let value = super::os::read_and_get_current_rss(&path).unwrap();
        assert_eq!(4552, value);
    }

    #[test]
    fn test_read_and_get_current_rss_wrong_path() {
        let path = Path::new("/nonsense");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::IO(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_incomplete() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_incomplete");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_get_current_rss_garbage() {
        let path = Path::new("fixtures/linux/process_memory/proc_self_statm_garbage");
        match super::os::read_and_get_current_rss(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_current_rss_of() {
        let pid = unsafe { libc::getpid() };
        assert!(super::current_rss_of(pid).is_ok());
        // See if it's a sort of sane value, between 1 and 250 mb
        assert!(super::current_rss_of(pid).unwrap() > 1_000);
        assert!(super::current_rss_of(pid).unwrap() < 250_000);
    }

    #[test]
    fn test_current_rss_of_invalid_pid() {
        assert!(super::current_rss_of(0).is_err());
    }

    #[test]
    fn test_max_rss() {
        // See if it's a sort of sane value, between 1 and 250 mb
        assert!(super::max_rss() > 1_000);
        assert!(super::max_rss() < 250_000);
    }
}
<|endoftext|>


<commit_before>// Test case for issue #2843.
//
// xfail-test

proto! streamp (
    open:send<T: send> {
        data(T) -> open<T>
    }
)

fn rendezvous() {
    let (c, s) = streamp::init();
    let streams: ~[streamp::client::open<int>] = ~[c];

    error!("%?", streams[0]);
}

fn main(args: ~[str]) {
    //os::getenv("FOO");
    rendezvous();
}<commit_msg>Un-xfail test for #2834<commit_after>// Test case for issue #2843.
//

proto! streamp (
    open:send<T: send> {
        data(T) -> open<T>
    }
)

fn rendezvous() {
    let (c, s) = streamp::init();
    let streams: ~[streamp::client::open<int>] = ~[c];

    error!("%?", streams[0]);
}

fn main(args: ~[~str]) {
    //os::getenv("FOO");
    rendezvous();
}<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate winapi;
extern crate kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    original_cp: DWORD,
    input: Receiver<u16>,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
        win32!(SetConsoleOutputCP(self.original_cp));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        let cp: DWORD;
        unsafe {
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
            cp = GetConsoleOutputCP();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));
        win32!(SetConsoleOutputCP(437 as DWORD));

        let rx = Screen::spawn_input_thread(conin as usize);
        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            original_cp: cp,
            input: rx,
            conout: conout,
        }
    }

    // We have to take the conin handle as a usize instead of a *mut c_void in order to avoid a
    // lecture from the compiler about how the latter type cannot be safely sent between threads.
    // I'm not sure if a better solution exists at this time.
    fn spawn_input_thread(conin: usize) -> Receiver<u16> {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            loop {
                let conin = conin as *mut c_void;
                let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
                let mut chars_read: DWORD = 0;
                win32!(ReadFile(conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));
                for i in 0..chars_read as usize {
                    tx.send(buf[i]).unwrap();
                }
            }
        });

        rx
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in 0..self.height {
            self.write(&blank_line);
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteConsoleA(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const WHITE_ON_RED: WORD = BACKGROUND_RED as WORD;
        self.set_colors(WHITE_ON_RED);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_red(&mut self, s: &str) {
        let orig = self.original_colors;
        const RED_ON_BLACK: WORD = FOREGROUND_RED as WORD;
        self.set_colors(RED_ON_BLACK);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.input.try_recv() {
            ret.push(Screen::translate_byte(byte));
        }
        if ret.is_empty() {
            let byte = self.input.recv().unwrap();
            ret.push(Screen::translate_byte(byte));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 9 {
            Tab
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conout: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conout, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    // AppVeyor builds run without a console, making this test impossible.
    if option_env!("APPVEYOR").is_some() {
        // TODO: It should be made obvious from the output that this test was skipped
        return;
    }
    let conout = unsafe { kernel32::GetStdHandle(0xFFFFFFF5) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<commit_msg>Remove Windows CP management<commit_after>#![cfg(windows)]

extern crate winapi;
extern crate kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;

use std::thread;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    input: Receiver<u16>,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let rx = Screen::spawn_input_thread(conin as usize);
        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            input: rx,
            conout: conout,
        }
    }

    // We have to take the conin handle as a usize instead of a *mut c_void in order to avoid a
    // lecture from the compiler about how the latter type cannot be safely sent between threads.
    // I'm not sure if a better solution exists at this time.
    fn spawn_input_thread(conin: usize) -> Receiver<u16> {
        let (tx, rx) = mpsc::channel();

        thread::spawn(move || {
            loop {
                let conin = conin as *mut c_void;
                let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
                let mut chars_read: DWORD = 0;
                win32!(ReadFile(conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));
                for i in 0..chars_read as usize {
                    tx.send(buf[i]).unwrap();
                }
            }
        });

        rx
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in 0..self.height {
            self.write(&blank_line);
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteConsoleA(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_red_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const WHITE_ON_RED: WORD = BACKGROUND_RED as WORD;
        self.set_colors(WHITE_ON_RED);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_red(&mut self, s: &str) {
        let orig = self.original_colors;
        const RED_ON_BLACK: WORD = FOREGROUND_RED as WORD;
        self.set_colors(RED_ON_BLACK);
        self.write(s);
        self.set_colors(orig);
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(byte) = self.input.try_recv() {
            ret.push(Screen::translate_byte(byte));
        }
        if ret.is_empty() {
            let byte = self.input.recv().unwrap();
            ret.push(Screen::translate_byte(byte));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 9 {
            Tab
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conout: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conout, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    // AppVeyor builds run without a console, making this test impossible.
    if option_env!("APPVEYOR").is_some() {
        // TODO: It should be made obvious from the output that this test was skipped
        return;
    }
    let conout = unsafe { kernel32::GetStdHandle(0xFFFFFFF5) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate "sdl2-sys" as sys;

use libc::{c_int, c_char};
use self::sys::surface::SDL_Surface;
use self::sys::rwops::SDL_RWops;
use self::sys::render::SDL_Texture;
use self::sys::render::SDL_Renderer;
use self::sys::version::SDL_version;

pub type IMG_InitFlags = c_int;
pub const IMG_INIT_JPG: IMG_InitFlags = 0x00000001;
pub const IMG_INIT_PNG: IMG_InitFlags = 0x00000002;
pub const IMG_INIT_TIF: IMG_InitFlags = 0x00000004;
pub const IMG_INIT_WEBP: IMG_InitFlags = 0x00000008;

extern "C" {

// This function gets the version of the dynamically linked SDL_image library.
pub fn IMG_Linked_Version() -> *const SDL_version;

// Loads dynamic libraries and prepares them for use.  Flags should be
// one or more flags from IMG_InitFlags OR'd together.
// It returns the flags successfully initialized, or 0 on failure.
pub fn IMG_Init(flags: c_int) -> c_int;

// Unloads libraries loaded with IMG_Init
pub fn IMG_Quit();

// Load an image from an SDL data source.
// The 'type' may be one of: "BMP", "GIF", "PNG", etc.
// If the image format supports a transparent pixel, SDL will set the
// colorkey for the surface.  You can enable RLE acceleration on the
// surface afterwards by calling:
//  SDL_SetColorKey(image, SDL_RLEACCEL, image->format->colorkey);
pub fn IMG_LoadTyped_RW(src: *const SDL_RWops, freesrc: c_int,
                        fmt: *const c_char) -> *const SDL_Surface;

// Convenience functions
pub fn IMG_Load(file: *const c_char) -> *const SDL_Surface;
pub fn IMG_Load_RW(src: *const SDL_RWops, freesrc: c_int) -> *const SDL_Surface;

// Load an image directly into a render texture.
// Requires SDL2
pub fn IMG_LoadTexture(renderer: *const SDL_Renderer,
                       file: *const c_char) -> *const SDL_Texture;
pub fn IMG_LoadTexture_RW(renderer: *const SDL_Renderer, src: *const SDL_RWops,
                          freesrc: c_int) -> *const SDL_Texture;
pub fn IMG_LoadTextureTyped_RW(renderer: *const SDL_Renderer, src: *const SDL_RWops,
                               freesrc: c_int, fmt: *const c_char) -> *const SDL_Texture;

// Functions to detect a file type, given a seekable source
pub fn IMG_isICO(src: *const SDL_RWops) -> c_int;
pub fn IMG_isCUR(src: *const SDL_RWops) -> c_int;
pub fn IMG_isBMP(src: *const SDL_RWops) -> c_int;
pub fn IMG_isGIF(src: *const SDL_RWops) -> c_int;
pub fn IMG_isJPG(src: *const SDL_RWops) -> c_int;
pub fn IMG_isLBM(src: *const SDL_RWops) -> c_int;
pub fn IMG_isPCX(src: *const SDL_RWops) -> c_int;
pub fn IMG_isPNG(src: *const SDL_RWops) -> c_int;
pub fn IMG_isPNM(src: *const SDL_RWops) -> c_int;
pub fn IMG_isTIF(src: *const SDL_RWops) -> c_int;
pub fn IMG_isXCF(src: *const SDL_RWops) -> c_int;
pub fn IMG_isXPM(src: *const SDL_RWops) -> c_int;
pub fn IMG_isXV(src: *const SDL_RWops) -> c_int;
pub fn IMG_isWEBP(src: *const SDL_RWops) -> c_int;

// Individual loading functions
pub fn IMG_LoadICO_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadCUR_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadBMP_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadGIF_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadJPG_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadLBM_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadPCX_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadPNG_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadPNM_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadTGA_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadTIF_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadXCF_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadXPM_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadXV_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadWEBP_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_ReadXPMFromArray(xpm: *const *const c_char) -> *const SDL_Surface;

// Individual saving functions
pub fn IMG_SavePNG(surface: *const SDL_Surface, file: *const c_char) -> c_int;
pub fn IMG_SavePNG_RW(surface: *const SDL_Surface, dst: *const SDL_RWops,
                      freedst: c_int) -> c_int;

}   // extern "C"
<commit_msg>No need to preface sys with self::.<commit_after>extern crate sdl2;
extern crate "sdl2-sys" as sys;

use libc::{c_int, c_char};
use sys::surface::SDL_Surface;
use sys::rwops::SDL_RWops;
use sys::render::SDL_Texture;
use sys::render::SDL_Renderer;
use sys::version::SDL_version;

pub type IMG_InitFlags = c_int;
pub const IMG_INIT_JPG: IMG_InitFlags = 0x00000001;
pub const IMG_INIT_PNG: IMG_InitFlags = 0x00000002;
pub const IMG_INIT_TIF: IMG_InitFlags = 0x00000004;
pub const IMG_INIT_WEBP: IMG_InitFlags = 0x00000008;

extern "C" {

// This function gets the version of the dynamically linked SDL_image library.
pub fn IMG_Linked_Version() -> *const SDL_version;

// Loads dynamic libraries and prepares them for use.  Flags should be
// one or more flags from IMG_InitFlags OR'd together.
// It returns the flags successfully initialized, or 0 on failure.
pub fn IMG_Init(flags: c_int) -> c_int;

// Unloads libraries loaded with IMG_Init
pub fn IMG_Quit();

// Load an image from an SDL data source.
// The 'type' may be one of: "BMP", "GIF", "PNG", etc.
// If the image format supports a transparent pixel, SDL will set the
// colorkey for the surface.  You can enable RLE acceleration on the
// surface afterwards by calling:
//  SDL_SetColorKey(image, SDL_RLEACCEL, image->format->colorkey);
pub fn IMG_LoadTyped_RW(src: *const SDL_RWops, freesrc: c_int,
                        fmt: *const c_char) -> *const SDL_Surface;

// Convenience functions
pub fn IMG_Load(file: *const c_char) -> *const SDL_Surface;
pub fn IMG_Load_RW(src: *const SDL_RWops, freesrc: c_int) -> *const SDL_Surface;

// Load an image directly into a render texture.
// Requires SDL2
pub fn IMG_LoadTexture(renderer: *const SDL_Renderer,
                       file: *const c_char) -> *const SDL_Texture;
pub fn IMG_LoadTexture_RW(renderer: *const SDL_Renderer, src: *const SDL_RWops,
                          freesrc: c_int) -> *const SDL_Texture;
pub fn IMG_LoadTextureTyped_RW(renderer: *const SDL_Renderer, src: *const SDL_RWops,
                               freesrc: c_int, fmt: *const c_char) -> *const SDL_Texture;

// Functions to detect a file type, given a seekable source
pub fn IMG_isICO(src: *const SDL_RWops) -> c_int;
pub fn IMG_isCUR(src: *const SDL_RWops) -> c_int;
pub fn IMG_isBMP(src: *const SDL_RWops) -> c_int;
pub fn IMG_isGIF(src: *const SDL_RWops) -> c_int;
pub fn IMG_isJPG(src: *const SDL_RWops) -> c_int;
pub fn IMG_isLBM(src: *const SDL_RWops) -> c_int;
pub fn IMG_isPCX(src: *const SDL_RWops) -> c_int;
pub fn IMG_isPNG(src: *const SDL_RWops) -> c_int;
pub fn IMG_isPNM(src: *const SDL_RWops) -> c_int;
pub fn IMG_isTIF(src: *const SDL_RWops) -> c_int;
pub fn IMG_isXCF(src: *const SDL_RWops) -> c_int;
pub fn IMG_isXPM(src: *const SDL_RWops) -> c_int;
pub fn IMG_isXV(src: *const SDL_RWops) -> c_int;
pub fn IMG_isWEBP(src: *const SDL_RWops) -> c_int;

// Individual loading functions
pub fn IMG_LoadICO_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadCUR_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadBMP_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadGIF_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadJPG_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadLBM_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadPCX_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadPNG_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadPNM_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadTGA_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadTIF_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadXCF_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadXPM_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadXV_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_LoadWEBP_RW(src: *const SDL_RWops) -> *const SDL_Surface;
pub fn IMG_ReadXPMFromArray(xpm: *const *const c_char) -> *const SDL_Surface;

// Individual saving functions
pub fn IMG_SavePNG(surface: *const SDL_Surface, file: *const c_char) -> c_int;
pub fn IMG_SavePNG_RW(surface: *const SDL_Surface, dst: *const SDL_RWops,
                      freedst: c_int) -> c_int;

}   // extern "C"
<|endoftext|>


<commit_before>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Use https://github.com/nox/serde_urlencoded
// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Move all enums here (ListingOrderBy, ListingSort, etc.)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.
// FIXME: Write nicer wrappers, getting rid of Listing.

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingSort {
    #[serde(rename = "asc")]
    Asc,
    #[serde(rename = "desc")]
    Desc,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingVisibility {
    #[serde(rename = "public")]
    Public,
    #[serde(rename = "internal")]
    Internal,
    #[serde(rename = "private")]
    Private,
}

#[derive(Debug, Serialize, Deserialize)]
enum IssueState {
    #[serde(rename = "opened")]
    Opened,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectOwner {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: String,
    pub avatar_url: String,
    pub web_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespaceAvatar {
    url: Option<String>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
struct ProjectNamespace {
    id: i64,
    name: String,
    path: String,
    owner_id: Option<i64>,  // FIXME: Why would a project not have this?
    created_at: String,  // FIXME: Date instead?
    updated_at: String,  // FIXME: Date instead?
    description: String,
    avatar: Option<ProjectNamespaceAvatar>,
    membership_lock: Option<bool>,
    share_with_group_lock: bool,
    visibility_level: i64,
    request_access_enabled: bool,
    ldap_sync_status: Option<String>,
    ldap_sync_error: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_successful_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_sync_at: Option<String>,  // FIXME: Is String the proper type?
    deleted_at: Option<String>,  // FIXME: Is String the proper type?
    lfs_enabled: Option<String>,  // FIXME: Is String the proper type?
    repository_size_limit: Option<String>  // FIXME: Is String the proper type?
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectForkedFrom {
    id: i64,
    http_url_to_repo: String,
    web_url: String,
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectAccess {
    access_level: i64,
    notification_level: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectPermissions {
    project_access: Option<ProjectAccess>,
    group_access: Option<ProjectAccess>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectSharedWithGroup {
    group_id: i64,
    group_name: String,
    group_access_level: i64,
}

// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct Project {
    id: i64,
    description: String,
    default_branch: Option<String>,
    tag_list: Vec<String>,
    public: bool,
    archived: bool,
    visibility_level: i64,
    ssh_url_to_repo: String,
    http_url_to_repo: String,
    web_url: String,
    // owner: Option<ProjectOwner>,  // FIXME: Why would a project not have an owner?
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
    container_registry_enabled: Option<bool>,
    issues_enabled: bool,
    merge_requests_enabled: bool,
    wiki_enabled: bool,
    builds_enabled: bool,
    snippets_enabled: bool,
    created_at: String,  // FIXME: Date instead?
    last_activity_at: String,  // FIXME: Date instead?
    shared_runners_enabled: bool,
    lfs_enabled: bool,
    creator_id: i64,
    namespace: ProjectNamespace,
    forked_from_project: Option<ProjectForkedFrom>,
    avatar_url: Option<String>,
    star_count: i64,
    forks_count: i64,
    open_issues_count: i64,
    runners_token: Option<String>,
    public_builds: bool,
    shared_with_groups: Vec<ProjectSharedWithGroup>,
    only_allow_merge_if_build_succeeds: bool,
    request_access_enabled: bool,
    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,  // FIXME: Is bool the proper type?
    approvals_before_merge: Option<i64>,
    permissions: Option<ProjectPermissions>,
}

pub type Projects = Vec<Project>;

#[derive(Debug, Serialize, Deserialize)]
struct Milestone {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MilestoneState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    username: String,
    id: i64,
    state: UserState,
    avatar_url: Option<String>,
    web_url: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Issue {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: IssueState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    labels: Vec<String>,
    milestone: Option<Milestone>,
    assignee: Option<User>,
    author: User,
    subscribed: bool,
    user_notes_count: i64,
    upvotes: i64,
    downvotes: i64,
    due_date: Option<String>,  // FIXME: Use date type?
    confidential: bool,
    web_url: Option<String>
}

pub type Issues = Vec<Issue>;
<commit_msg>Fix deserialization problem: `caused by: missing field "open_issues_count" at line 1 column 1463`<commit_after>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Use https://github.com/nox/serde_urlencoded
// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Move all enums here (ListingOrderBy, ListingSort, etc.)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.
// FIXME: Write nicer wrappers, getting rid of Listing.

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingSort {
    #[serde(rename = "asc")]
    Asc,
    #[serde(rename = "desc")]
    Desc,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingVisibility {
    #[serde(rename = "public")]
    Public,
    #[serde(rename = "internal")]
    Internal,
    #[serde(rename = "private")]
    Private,
}

#[derive(Debug, Serialize, Deserialize)]
enum IssueState {
    #[serde(rename = "opened")]
    Opened,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectOwner {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: String,
    pub avatar_url: String,
    pub web_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespaceAvatar {
    url: Option<String>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
struct ProjectNamespace {
    id: i64,
    name: String,
    path: String,
    owner_id: Option<i64>,  // FIXME: Why would a project not have this?
    created_at: String,  // FIXME: Date instead?
    updated_at: String,  // FIXME: Date instead?
    description: String,
    avatar: Option<ProjectNamespaceAvatar>,
    membership_lock: Option<bool>,
    share_with_group_lock: bool,
    visibility_level: i64,
    request_access_enabled: bool,
    ldap_sync_status: Option<String>,
    ldap_sync_error: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_successful_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_sync_at: Option<String>,  // FIXME: Is String the proper type?
    deleted_at: Option<String>,  // FIXME: Is String the proper type?
    lfs_enabled: Option<String>,  // FIXME: Is String the proper type?
    repository_size_limit: Option<String>  // FIXME: Is String the proper type?
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectForkedFrom {
    id: i64,
    http_url_to_repo: String,
    web_url: String,
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectAccess {
    access_level: i64,
    notification_level: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectPermissions {
    project_access: Option<ProjectAccess>,
    group_access: Option<ProjectAccess>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectSharedWithGroup {
    group_id: i64,
    group_name: String,
    group_access_level: i64,
}

// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
#[derive(Default, Debug, Serialize, Deserialize)]
pub struct Project {
    id: i64,
    description: String,
    default_branch: Option<String>,
    tag_list: Vec<String>,
    public: bool,
    archived: bool,
    visibility_level: i64,
    ssh_url_to_repo: String,
    http_url_to_repo: String,
    web_url: String,
    // owner: Option<ProjectOwner>,  // FIXME: Why would a project not have an owner?
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
    container_registry_enabled: Option<bool>,
    issues_enabled: bool,
    merge_requests_enabled: bool,
    wiki_enabled: bool,
    builds_enabled: bool,
    snippets_enabled: bool,
    created_at: String,  // FIXME: Date instead?
    last_activity_at: String,  // FIXME: Date instead?
    shared_runners_enabled: bool,
    lfs_enabled: bool,
    creator_id: i64,
    namespace: ProjectNamespace,
    forked_from_project: Option<ProjectForkedFrom>,
    avatar_url: Option<String>,
    star_count: i64,
    forks_count: i64,
    open_issues_count: Option<i64>,
    runners_token: Option<String>,
    public_builds: bool,
    shared_with_groups: Vec<ProjectSharedWithGroup>,
    only_allow_merge_if_build_succeeds: bool,
    request_access_enabled: bool,
    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,  // FIXME: Is bool the proper type?
    approvals_before_merge: Option<i64>,
    permissions: Option<ProjectPermissions>,
}

pub type Projects = Vec<Project>;

#[derive(Debug, Serialize, Deserialize)]
struct Milestone {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MilestoneState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    username: String,
    id: i64,
    state: UserState,
    avatar_url: Option<String>,
    web_url: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Issue {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: IssueState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    labels: Vec<String>,
    milestone: Option<Milestone>,
    assignee: Option<User>,
    author: User,
    subscribed: bool,
    user_notes_count: i64,
    upvotes: i64,
    downvotes: i64,
    due_date: Option<String>,  // FIXME: Use date type?
    confidential: bool,
    web_url: Option<String>
}

pub type Issues = Vec<Issue>;
<|endoftext|>