<commit_before>//! Various extension methods to ast Expr Nodes, which are hard to code-generate.

use crate::{
    ast::{self, child_opt, children, AstChildren, AstNode},
    SmolStr,
    SyntaxKind::*,
    SyntaxToken, T,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ElseBranch {
    Block(ast::Block),
    IfExpr(ast::IfExpr),
}

impl ast::IfExpr {
    pub fn then_branch(&self) -> Option<ast::Block> {
        self.blocks().nth(0)
    }
    pub fn else_branch(&self) -> Option<ElseBranch> {
        let res = match self.blocks().nth(1) {
            Some(block) => ElseBranch::Block(block),
            None => {
                let elif: ast::IfExpr = child_opt(self)?;
                ElseBranch::IfExpr(elif)
            }
        };
        Some(res)
    }

    fn blocks(&self) -> AstChildren<ast::Block> {
        children(self)
    }
}

impl ast::RefExpr {
    pub fn is_mut(&self) -> bool {
        self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PrefixOp {
    /// The `*` operator for dereferencing
    Deref,
    /// The `!` operator for logical inversion
    Not,
    /// The `-` operator for negation
    Neg,
}

impl ast::PrefixExpr {
    pub fn op_kind(&self) -> Option<PrefixOp> {
        match self.op_token()?.kind() {
            T![*] => Some(PrefixOp::Deref),
            T![!] => Some(PrefixOp::Not),
            T![-] => Some(PrefixOp::Neg),
            _ => None,
        }
    }

    pub fn op_token(&self) -> Option<SyntaxToken> {
        self.syntax().first_child_or_token()?.into_token()
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum BinOp {
    /// The `||` operator for boolean OR
    BooleanOr,
    /// The `&&` operator for boolean AND
    BooleanAnd,
    /// The `==` operator for equality testing
    EqualityTest,
    /// The `!=` operator for equality testing
    NegatedEqualityTest,
    /// The `<=` operator for lesser-equal testing
    LesserEqualTest,
    /// The `>=` operator for greater-equal testing
    GreaterEqualTest,
    /// The `<` operator for comparison
    LesserTest,
    /// The `>` operator for comparison
    GreaterTest,
    /// The `+` operator for addition
    Addition,
    /// The `*` operator for multiplication
    Multiplication,
    /// The `-` operator for subtraction
    Subtraction,
    /// The `/` operator for division
    Division,
    /// The `%` operator for remainder after division
    Remainder,
    /// The `<<` operator for left shift
    LeftShift,
    /// The `>>` operator for right shift
    RightShift,
    /// The `^` operator for bitwise XOR
    BitwiseXor,
    /// The `|` operator for bitwise OR
    BitwiseOr,
    /// The `&` operator for bitwise AND
    BitwiseAnd,
    /// The `..` operator for right-open ranges
    RangeRightOpen,
    /// The `..=` operator for right-closed ranges
    RangeRightClosed,
    /// The `=` operator for assignment
    Assignment,
    /// The `+=` operator for assignment after addition
    AddAssign,
    /// The `/=` operator for assignment after division
    DivAssign,
    /// The `*=` operator for assignment after multiplication
    MulAssign,
    /// The `%=` operator for assignment after remainders
    RemAssign,
    /// The `>>=` operator for assignment after shifting right
    ShrAssign,
    /// The `<<=` operator for assignment after shifting left
    ShlAssign,
    /// The `-=` operator for assignment after subtraction
    SubAssign,
    /// The `|=` operator for assignment after bitwise OR
    BitOrAssign,
    /// The `&=` operator for assignment after bitwise AND
    BitAndAssign,
    /// The `^=` operator for assignment after bitwise XOR
    BitXorAssign,
}

impl ast::BinExpr {
    fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
        self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| match c
            .kind()
        {
            T![||] => Some((c, BinOp::BooleanOr)),
            T![&&] => Some((c, BinOp::BooleanAnd)),
            T![==] => Some((c, BinOp::EqualityTest)),
            T![!=] => Some((c, BinOp::NegatedEqualityTest)),
            T![<=] => Some((c, BinOp::LesserEqualTest)),
            T![>=] => Some((c, BinOp::GreaterEqualTest)),
            T![<] => Some((c, BinOp::LesserTest)),
            T![>] => Some((c, BinOp::GreaterTest)),
            T![+] => Some((c, BinOp::Addition)),
            T![*] => Some((c, BinOp::Multiplication)),
            T![-] => Some((c, BinOp::Subtraction)),
            T![/] => Some((c, BinOp::Division)),
            T![%] => Some((c, BinOp::Remainder)),
            T![<<] => Some((c, BinOp::LeftShift)),
            T![>>] => Some((c, BinOp::RightShift)),
            T![^] => Some((c, BinOp::BitwiseXor)),
            T![|] => Some((c, BinOp::BitwiseOr)),
            T![&] => Some((c, BinOp::BitwiseAnd)),
            T![..] => Some((c, BinOp::RangeRightOpen)),
            T![..=] => Some((c, BinOp::RangeRightClosed)),
            T![=] => Some((c, BinOp::Assignment)),
            T![+=] => Some((c, BinOp::AddAssign)),
            T![/=] => Some((c, BinOp::DivAssign)),
            T![*=] => Some((c, BinOp::MulAssign)),
            T![%=] => Some((c, BinOp::RemAssign)),
            T![>>=] => Some((c, BinOp::ShrAssign)),
            T![<<=] => Some((c, BinOp::ShlAssign)),
            T![-=] => Some((c, BinOp::SubAssign)),
            T![|=] => Some((c, BinOp::BitOrAssign)),
            T![&=] => Some((c, BinOp::BitAndAssign)),
            T![^=] => Some((c, BinOp::BitXorAssign)),
            _ => None,
        })
    }

    pub fn op_kind(&self) -> Option<BinOp> {
        self.op_details().map(|t| t.1)
    }

    pub fn op_token(&self) -> Option<SyntaxToken> {
        self.op_details().map(|t| t.0)
    }

    pub fn lhs(&self) -> Option<ast::Expr> {
        children(self).nth(0)
    }

    pub fn rhs(&self) -> Option<ast::Expr> {
        children(self).nth(1)
    }

    pub fn sub_exprs(&self) -> (Option<ast::Expr>, Option<ast::Expr>) {
        let mut children = children(self);
        let first = children.next();
        let second = children.next();
        (first, second)
    }
}

pub enum ArrayExprKind {
    Repeat { initializer: Option<ast::Expr>, repeat: Option<ast::Expr> },
    ElementList(AstChildren<ast::Expr>),
}

impl ast::ArrayExpr {
    pub fn kind(&self) -> ArrayExprKind {
        if self.is_repeat() {
            ArrayExprKind::Repeat {
                initializer: children(self).nth(0),
                repeat: children(self).nth(1),
            }
        } else {
            ArrayExprKind::ElementList(children(self))
        }
    }

    fn is_repeat(&self) -> bool {
        self.syntax().children_with_tokens().any(|it| it.kind() == T![;])
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum LiteralKind {
    String,
    ByteString,
    Char,
    Byte,
    IntNumber { suffix: Option<SmolStr> },
    FloatNumber { suffix: Option<SmolStr> },
    Bool,
}

impl ast::Literal {
    pub fn token(&self) -> SyntaxToken {
        self.syntax()
            .children_with_tokens()
            .find(|e| e.kind() != ATTR && !e.kind().is_trivia())
            .and_then(|e| e.into_token())
            .unwrap()
    }

    pub fn kind(&self) -> LiteralKind {
        match self.token().kind() {
            INT_NUMBER => {
                let int_suffix_list = [
                    "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
                    "u16", "u8",
                ];

                // The lexer treats e.g. `1f64` as an integer literal. See
                // https://github.com/rust-analyzer/rust-analyzer/issues/1592
                // and the comments on the linked PR.
                let float_suffix_list = [
                    "f32", "f64"
                ];

                let text = self.token().text().to_string();

                let float_suffix = float_suffix_list
                    .iter()
                    .find(|&s| text.ends_with(s))
                    .map(|&suf| SmolStr::new(suf));

                if float_suffix.is_some() {
                    LiteralKind::FloatNumber { suffix: float_suffix }
                } else {
                    let suffix = int_suffix_list
                        .iter()
                        .find(|&s| text.ends_with(s))
                        .map(|&suf| SmolStr::new(suf));
                    LiteralKind::IntNumber { suffix }
                }
            }
            FLOAT_NUMBER => {
                let allowed_suffix_list = ["f64", "f32"];
                let text = self.token().text().to_string();
                let suffix = allowed_suffix_list
                    .iter()
                    .find(|&s| text.ends_with(s))
                    .map(|&suf| SmolStr::new(suf));
                LiteralKind::FloatNumber { suffix }
            }
            STRING | RAW_STRING => LiteralKind::String,
            T![true] | T![false] => LiteralKind::Bool,
            BYTE_STRING | RAW_BYTE_STRING => LiteralKind::ByteString,
            CHAR => LiteralKind::Char,
            BYTE => LiteralKind::Byte,
            _ => unreachable!(),
        }
    }
}

#[test]
fn test_literal_with_attr() {
    let parse = ast::SourceFile::parse(r#"const _: &str = { #[attr] "Hello" };"#);
    let lit = parse.tree().syntax().descendants().find_map(ast::Literal::cast).unwrap();
    assert_eq!(lit.token().text(), r#""Hello""#);
}

impl ast::NamedField {
    pub fn parent_struct_lit(&self) -> ast::StructLit {
        self.syntax().ancestors().find_map(ast::StructLit::cast).unwrap()
    }
}
<commit_msg>cargo format<commit_after>//! Various extension methods to ast Expr Nodes, which are hard to code-generate.

use crate::{
    ast::{self, child_opt, children, AstChildren, AstNode},
    SmolStr,
    SyntaxKind::*,
    SyntaxToken, T,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ElseBranch {
    Block(ast::Block),
    IfExpr(ast::IfExpr),
}

impl ast::IfExpr {
    pub fn then_branch(&self) -> Option<ast::Block> {
        self.blocks().nth(0)
    }
    pub fn else_branch(&self) -> Option<ElseBranch> {
        let res = match self.blocks().nth(1) {
            Some(block) => ElseBranch::Block(block),
            None => {
                let elif: ast::IfExpr = child_opt(self)?;
                ElseBranch::IfExpr(elif)
            }
        };
        Some(res)
    }

    fn blocks(&self) -> AstChildren<ast::Block> {
        children(self)
    }
}

impl ast::RefExpr {
    pub fn is_mut(&self) -> bool {
        self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PrefixOp {
    /// The `*` operator for dereferencing
    Deref,
    /// The `!` operator for logical inversion
    Not,
    /// The `-` operator for negation
    Neg,
}

impl ast::PrefixExpr {
    pub fn op_kind(&self) -> Option<PrefixOp> {
        match self.op_token()?.kind() {
            T![*] => Some(PrefixOp::Deref),
            T![!] => Some(PrefixOp::Not),
            T![-] => Some(PrefixOp::Neg),
            _ => None,
        }
    }

    pub fn op_token(&self) -> Option<SyntaxToken> {
        self.syntax().first_child_or_token()?.into_token()
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum BinOp {
    /// The `||` operator for boolean OR
    BooleanOr,
    /// The `&&` operator for boolean AND
    BooleanAnd,
    /// The `==` operator for equality testing
    EqualityTest,
    /// The `!=` operator for equality testing
    NegatedEqualityTest,
    /// The `<=` operator for lesser-equal testing
    LesserEqualTest,
    /// The `>=` operator for greater-equal testing
    GreaterEqualTest,
    /// The `<` operator for comparison
    LesserTest,
    /// The `>` operator for comparison
    GreaterTest,
    /// The `+` operator for addition
    Addition,
    /// The `*` operator for multiplication
    Multiplication,
    /// The `-` operator for subtraction
    Subtraction,
    /// The `/` operator for division
    Division,
    /// The `%` operator for remainder after division
    Remainder,
    /// The `<<` operator for left shift
    LeftShift,
    /// The `>>` operator for right shift
    RightShift,
    /// The `^` operator for bitwise XOR
    BitwiseXor,
    /// The `|` operator for bitwise OR
    BitwiseOr,
    /// The `&` operator for bitwise AND
    BitwiseAnd,
    /// The `..` operator for right-open ranges
    RangeRightOpen,
    /// The `..=` operator for right-closed ranges
    RangeRightClosed,
    /// The `=` operator for assignment
    Assignment,
    /// The `+=` operator for assignment after addition
    AddAssign,
    /// The `/=` operator for assignment after division
    DivAssign,
    /// The `*=` operator for assignment after multiplication
    MulAssign,
    /// The `%=` operator for assignment after remainders
    RemAssign,
    /// The `>>=` operator for assignment after shifting right
    ShrAssign,
    /// The `<<=` operator for assignment after shifting left
    ShlAssign,
    /// The `-=` operator for assignment after subtraction
    SubAssign,
    /// The `|=` operator for assignment after bitwise OR
    BitOrAssign,
    /// The `&=` operator for assignment after bitwise AND
    BitAndAssign,
    /// The `^=` operator for assignment after bitwise XOR
    BitXorAssign,
}

impl ast::BinExpr {
    fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
        self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| match c
            .kind()
        {
            T![||] => Some((c, BinOp::BooleanOr)),
            T![&&] => Some((c, BinOp::BooleanAnd)),
            T![==] => Some((c, BinOp::EqualityTest)),
            T![!=] => Some((c, BinOp::NegatedEqualityTest)),
            T![<=] => Some((c, BinOp::LesserEqualTest)),
            T![>=] => Some((c, BinOp::GreaterEqualTest)),
            T![<] => Some((c, BinOp::LesserTest)),
            T![>] => Some((c, BinOp::GreaterTest)),
            T![+] => Some((c, BinOp::Addition)),
            T![*] => Some((c, BinOp::Multiplication)),
            T![-] => Some((c, BinOp::Subtraction)),
            T![/] => Some((c, BinOp::Division)),
            T![%] => Some((c, BinOp::Remainder)),
            T![<<] => Some((c, BinOp::LeftShift)),
            T![>>] => Some((c, BinOp::RightShift)),
            T![^] => Some((c, BinOp::BitwiseXor)),
            T![|] => Some((c, BinOp::BitwiseOr)),
            T![&] => Some((c, BinOp::BitwiseAnd)),
            T![..] => Some((c, BinOp::RangeRightOpen)),
            T![..=] => Some((c, BinOp::RangeRightClosed)),
            T![=] => Some((c, BinOp::Assignment)),
            T![+=] => Some((c, BinOp::AddAssign)),
            T![/=] => Some((c, BinOp::DivAssign)),
            T![*=] => Some((c, BinOp::MulAssign)),
            T![%=] => Some((c, BinOp::RemAssign)),
            T![>>=] => Some((c, BinOp::ShrAssign)),
            T![<<=] => Some((c, BinOp::ShlAssign)),
            T![-=] => Some((c, BinOp::SubAssign)),
            T![|=] => Some((c, BinOp::BitOrAssign)),
            T![&=] => Some((c, BinOp::BitAndAssign)),
            T![^=] => Some((c, BinOp::BitXorAssign)),
            _ => None,
        })
    }

    pub fn op_kind(&self) -> Option<BinOp> {
        self.op_details().map(|t| t.1)
    }

    pub fn op_token(&self) -> Option<SyntaxToken> {
        self.op_details().map(|t| t.0)
    }

    pub fn lhs(&self) -> Option<ast::Expr> {
        children(self).nth(0)
    }

    pub fn rhs(&self) -> Option<ast::Expr> {
        children(self).nth(1)
    }

    pub fn sub_exprs(&self) -> (Option<ast::Expr>, Option<ast::Expr>) {
        let mut children = children(self);
        let first = children.next();
        let second = children.next();
        (first, second)
    }
}

pub enum ArrayExprKind {
    Repeat { initializer: Option<ast::Expr>, repeat: Option<ast::Expr> },
    ElementList(AstChildren<ast::Expr>),
}

impl ast::ArrayExpr {
    pub fn kind(&self) -> ArrayExprKind {
        if self.is_repeat() {
            ArrayExprKind::Repeat {
                initializer: children(self).nth(0),
                repeat: children(self).nth(1),
            }
        } else {
            ArrayExprKind::ElementList(children(self))
        }
    }

    fn is_repeat(&self) -> bool {
        self.syntax().children_with_tokens().any(|it| it.kind() == T![;])
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum LiteralKind {
    String,
    ByteString,
    Char,
    Byte,
    IntNumber { suffix: Option<SmolStr> },
    FloatNumber { suffix: Option<SmolStr> },
    Bool,
}

impl ast::Literal {
    pub fn token(&self) -> SyntaxToken {
        self.syntax()
            .children_with_tokens()
            .find(|e| e.kind() != ATTR && !e.kind().is_trivia())
            .and_then(|e| e.into_token())
            .unwrap()
    }

    pub fn kind(&self) -> LiteralKind {
        match self.token().kind() {
            INT_NUMBER => {
                let int_suffix_list = [
                    "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
                    "u16", "u8",
                ];

                // The lexer treats e.g. `1f64` as an integer literal. See
                // https://github.com/rust-analyzer/rust-analyzer/issues/1592
                // and the comments on the linked PR.
                let float_suffix_list = ["f32", "f64"];

                let text = self.token().text().to_string();

                let float_suffix = float_suffix_list
                    .iter()
                    .find(|&s| text.ends_with(s))
                    .map(|&suf| SmolStr::new(suf));

                if float_suffix.is_some() {
                    LiteralKind::FloatNumber { suffix: float_suffix }
                } else {
                    let suffix = int_suffix_list
                        .iter()
                        .find(|&s| text.ends_with(s))
                        .map(|&suf| SmolStr::new(suf));
                    LiteralKind::IntNumber { suffix }
                }
            }
            FLOAT_NUMBER => {
                let allowed_suffix_list = ["f64", "f32"];
                let text = self.token().text().to_string();
                let suffix = allowed_suffix_list
                    .iter()
                    .find(|&s| text.ends_with(s))
                    .map(|&suf| SmolStr::new(suf));
                LiteralKind::FloatNumber { suffix }
            }
            STRING | RAW_STRING => LiteralKind::String,
            T![true] | T![false] => LiteralKind::Bool,
            BYTE_STRING | RAW_BYTE_STRING => LiteralKind::ByteString,
            CHAR => LiteralKind::Char,
            BYTE => LiteralKind::Byte,
            _ => unreachable!(),
        }
    }
}

#[test]
fn test_literal_with_attr() {
    let parse = ast::SourceFile::parse(r#"const _: &str = { #[attr] "Hello" };"#);
    let lit = parse.tree().syntax().descendants().find_map(ast::Literal::cast).unwrap();
    assert_eq!(lit.token().text(), r#""Hello""#);
}

impl ast::NamedField {
    pub fn parent_struct_lit(&self) -> ast::StructLit {
        self.syntax().ancestors().find_map(ast::StructLit::cast).unwrap()
    }
}
<|endoftext|>


<commit_before>use super::*;

pub(super) fn opt_type_param_list(p: &mut Parser) {
    if !p.at(L_ANGLE) {
        return;
    }
    type_param_list(p);
}

fn type_param_list(p: &mut Parser) {
    assert!(p.at(L_ANGLE));
    let m = p.start();
    p.bump();

    while !p.at(EOF) && !p.at(R_ANGLE) {
        match p.current() {
            LIFETIME => lifetime_param(p),
            IDENT => type_param(p),
            _ => p.err_and_bump("expected type parameter"),
        }
        if !p.at(R_ANGLE) && !p.expect(COMMA) {
            break;
        }
    }
    p.expect(R_ANGLE);
    m.complete(p, TYPE_PARAM_LIST);
}

fn lifetime_param(p: &mut Parser) {
    assert!(p.at(LIFETIME));
    let m = p.start();
    p.bump();
    if p.at(COLON) {
        lifetime_bounds(p);
    }
    m.complete(p, LIFETIME_PARAM);
}

fn type_param(p: &mut Parser) {
    assert!(p.at(IDENT));
    let m = p.start();
    name(p);
    if p.at(COLON) {
        bounds(p);
    }
    // test type_param_default
    // struct S<T = i32>;
    if p.at(EQ) {
        p.bump();
        types::type_(p)
    }
    m.complete(p, TYPE_PARAM);
}

// test type_param_bounds
// struct S<T: 'a + ?Sized + (Copy)>;
pub(super) fn bounds(p: &mut Parser) {
    assert!(p.at(COLON));
    p.bump();
    bounds_without_colon(p);
}

fn lifetime_bounds(p: &mut Parser) {
    assert!(p.at(COLON));
    p.bump();
    while p.at(LIFETIME) {
        p.bump();
        if !p.eat(PLUS) {
            break;
        }
    }
}

pub(super) fn bounds_without_colon(p: &mut Parser) {
    loop {
        let has_paren = p.eat(L_PAREN);
        p.eat(QUESTION);
        match p.current() {
            LIFETIME => p.bump(),
            FOR_KW => types::for_type(p),
            _ if paths::is_path_start(p) => types::path_type(p),
            _ => break,
        }
        if has_paren {
            p.expect(R_PAREN);
        }
        if !p.eat(PLUS) {
            break;
        }
    }
}

// test where_clause
// fn foo()
// where
//    'a: 'b + 'c,
//    T: Clone + Copy + 'static,
//    Iterator::Item: 'a,
//    <T as Iterator>::Item: 'a
// {}
pub(super) fn opt_where_clause(p: &mut Parser) {
    if !p.at(WHERE_KW) {
        return;
    }
    let m = p.start();
    p.bump();

    if is_where_clause_end(p) {
        // Empty where clause
    } else {
        loop {
            where_predicate(p);

            let comma = p.eat(COMMA);

            if is_where_clause_end(p) {
                break;
            }

            if !comma {
                p.error("expected comma")
            }
        }
    }

    m.complete(p, WHERE_CLAUSE);
}

fn is_where_clause_end(p: &mut Parser) -> bool {
    p.current() == L_CURLY || p.current() == SEMI || p.current() == EQ
}

fn where_predicate(p: &mut Parser) {
    let m = p.start();
    match p.current() {
        LIFETIME => {
            p.bump();
            if p.at(COLON) {
                lifetime_bounds(p);
            } else {
                p.error("expected colon");
            }
        }
        IMPL_KW => {
            p.error("expected lifetime or type");
            return;
        }
        _ => {
            types::type_(p);

            if p.at(COLON) {
                bounds(p);
            } else {
                p.error("expected colon");
            }
        }
    }
    m.complete(p, WHERE_PRED);
}
<commit_msg>Don't leave a marker hanging without completing it.<commit_after>use super::*;

pub(super) fn opt_type_param_list(p: &mut Parser) {
    if !p.at(L_ANGLE) {
        return;
    }
    type_param_list(p);
}

fn type_param_list(p: &mut Parser) {
    assert!(p.at(L_ANGLE));
    let m = p.start();
    p.bump();

    while !p.at(EOF) && !p.at(R_ANGLE) {
        match p.current() {
            LIFETIME => lifetime_param(p),
            IDENT => type_param(p),
            _ => p.err_and_bump("expected type parameter"),
        }
        if !p.at(R_ANGLE) && !p.expect(COMMA) {
            break;
        }
    }
    p.expect(R_ANGLE);
    m.complete(p, TYPE_PARAM_LIST);
}

fn lifetime_param(p: &mut Parser) {
    assert!(p.at(LIFETIME));
    let m = p.start();
    p.bump();
    if p.at(COLON) {
        lifetime_bounds(p);
    }
    m.complete(p, LIFETIME_PARAM);
}

fn type_param(p: &mut Parser) {
    assert!(p.at(IDENT));
    let m = p.start();
    name(p);
    if p.at(COLON) {
        bounds(p);
    }
    // test type_param_default
    // struct S<T = i32>;
    if p.at(EQ) {
        p.bump();
        types::type_(p)
    }
    m.complete(p, TYPE_PARAM);
}

// test type_param_bounds
// struct S<T: 'a + ?Sized + (Copy)>;
pub(super) fn bounds(p: &mut Parser) {
    assert!(p.at(COLON));
    p.bump();
    bounds_without_colon(p);
}

fn lifetime_bounds(p: &mut Parser) {
    assert!(p.at(COLON));
    p.bump();
    while p.at(LIFETIME) {
        p.bump();
        if !p.eat(PLUS) {
            break;
        }
    }
}

pub(super) fn bounds_without_colon(p: &mut Parser) {
    loop {
        let has_paren = p.eat(L_PAREN);
        p.eat(QUESTION);
        match p.current() {
            LIFETIME => p.bump(),
            FOR_KW => types::for_type(p),
            _ if paths::is_path_start(p) => types::path_type(p),
            _ => break,
        }
        if has_paren {
            p.expect(R_PAREN);
        }
        if !p.eat(PLUS) {
            break;
        }
    }
}

// test where_clause
// fn foo()
// where
//    'a: 'b + 'c,
//    T: Clone + Copy + 'static,
//    Iterator::Item: 'a,
//    <T as Iterator>::Item: 'a
// {}
pub(super) fn opt_where_clause(p: &mut Parser) {
    if !p.at(WHERE_KW) {
        return;
    }
    let m = p.start();
    p.bump();

    if is_where_clause_end(p) {
        // Empty where clause
    } else {
        loop {
            where_predicate(p);

            let comma = p.eat(COMMA);

            if is_where_clause_end(p) {
                break;
            }

            if !comma {
                p.error("expected comma");
            }
        }
    }

    m.complete(p, WHERE_CLAUSE);
}

fn is_where_clause_end(p: &mut Parser) -> bool {
    p.current() == L_CURLY || p.current() == SEMI || p.current() == EQ
}

fn where_predicate(p: &mut Parser) {
    let m = p.start();
    match p.current() {
        LIFETIME => {
            p.bump();
            if p.at(COLON) {
                lifetime_bounds(p);
            } else {
                p.error("expected colon");
            }
        }
        IMPL_KW => {
            p.error("expected lifetime or type");
        }
        _ => {
            types::type_(p);

            if p.at(COLON) {
                bounds(p);
            } else {
                p.error("expected colon");
            }
        }
    }
    m.complete(p, WHERE_PRED);
}
<|endoftext|>


<commit_before>// Rubrail Example
//
// Demonstrates using Rubrail to layout and interact with a persistent Touchbar
// on Macbooks that support it.
//
// Usage notes:
//
// To access the touchbar, Rubrail *must* execute inside an OS X app bundle.
// Since Cargo doesn't do that itself, this example uses the Trampoline feature
// of the fruitbasket crate to relaunch itself in an app bundle.
//
// Simply run:
//
// $ cargo test && cargo run --example example
//
//
extern crate rubrail;
extern crate fruitbasket;

use rubrail::Touchbar;
use rubrail::TTouchbar;
use rubrail::TScrubberData;
use rubrail::ItemId;
use rubrail::SwipeState;

#[macro_use]
extern crate log;

use std::rc::Rc;
use std::cell::RefCell;

struct TouchbarHandler {
    devices: RefCell<Vec<String>>,
}
impl TScrubberData for TouchbarHandler {
    fn count(&self, _item: ItemId) -> u32 {
        self.devices.borrow().len() as u32
    }
    fn text(&self, _item: ItemId, idx: u32) -> String {
        self.devices.borrow()[idx as usize].to_string()
    }
    fn width(&self, _item: ItemId, idx: u32) -> u32 {
        // 10px per character + some padding seems to work nicely for the default
        // font.  no idea what it's like on other machines.  does the touchbar
        // font change? ¯\_(ツ)_/¯
        let len = self.devices.borrow()[idx as usize].len() as u32;
        let width = len * 8 + 20;
        width
    }
    fn touch(&self, _item: ItemId, idx: u32) {
        info!("scrub touch: {}", idx);
    }
}

fn populate(bar_rc: Rc<RefCell<Touchbar>>, count: u32) {
    // Get touchbar from the refcell.  It's wrapped in a cell so
    // it can be passed around in the button callbacks.
    let mut tb = (bar_rc).borrow_mut();

    // Create the lowest level "root" touchbar
    let mut barid = tb.create_bar();

    // Create a quit button for root bar
    let quit_id = tb.create_button(None, Some("Quit"), Box::new(move |_| {rubrail::app::quit()}));

    // Create an action button for the root bar.  When clicked, it will
    // close the bar and re-create itself.
    let bar_copy = bar_rc.clone();
    let text = format!("button{}", count);
    let button1_id = tb.create_button(None, Some(&text), Box::new(move |_| {
        populate(bar_copy.clone(), count+1)
    }));

    // Create a text label for the root bar
    let label1_id = tb.create_label("This is a label");
    tb.update_label(&label1_id, "This is a label\nWith two rows");
    tb.update_label_width(&label1_id, 100);

    // Support double-clicking the label with one finger
    tb.add_item_tap_gesture(&label1_id, 2, 1, Box::new(move |_item| {
        info!("Label double-clicked!");
    }));

    // Add a swipe gesture to the label that changes the text color to
    // increasingly green as you swipe right, or increasingly red as you swipe
    // left, and resets to white when released.
    tb.add_item_swipe_gesture(&label1_id, Box::new(move |item,state,translation| {
        let color: f64 = match translation.abs().trunc() as u32 {
            t if t < 10 => 1.0,
            t if t > 100 => 0.0,
            _ => (45. / translation.abs()),
        };
        let rgba = match state {
            SwipeState::Ended => (1.0, 1.0, 1.0, 1.0),
            _ => {
                match translation.is_sign_positive() {
                    true => (color, 1.0, color, 1.0),
                    false => (1.0, color, color, 1.0),
                }
            }
        };
        unsafe { rubrail::util::set_text_color(item, rgba.0, rgba.1, rgba.2, rgba.3); }
    }));

    // Create a data backend for scrolling text "scrubbers"
    let scrubber = Rc::new(TouchbarHandler {
        devices: RefCell::new(vec![
            "one".to_string(), "two".to_string(),
            "a little bit longer one".to_string(),
            "three".to_string(),
            "this one is really quite a bit longer than the others".to_string()]),
    });

    // Create a scrubber for the root bar
    let scrubber1_id = tb.create_text_scrubber(scrubber.clone());
    tb.select_scrubber_item(&scrubber1_id, 1);

    // Create a 'popbar', a second level deep bar
    let mut popbar1_id = tb.create_bar();
    let popbutton1_id = tb.create_popover_item(None, Some("Popbar1"), &popbar1_id);

    // Create another scrubber with the same data, for the popbar.
    // Note that the data and callbacks are shared, but this is a different
    // instance and can store a different active selection.
    let scrubber2_id = tb.create_text_scrubber(scrubber.clone());
    tb.select_scrubber_item(&scrubber2_id, 3);

    // Create a slider for the popbar.
    let slider1_id = tb.create_slider(0.0, 50.0, Some("Slide"), true,
                                      Box::new(move |_s,v| {info!("Slid to: {}", v);}));
    tb.update_slider(&slider1_id, 15.0);

    // Create a another popbar.  This will make a 2-level deep UI.
    let mut popbar2_id = tb.create_bar();
    let popbutton2_id = tb.create_popover_item(None, Some("Popbar2"), &popbar2_id);

    // Create buttons to display on the popbars
    let popbar_button_id = tb.create_button(None, Some("1 level deep"), Box::new(move |_| {}));
    let deep_button_id = tb.create_button(None, Some("2 levels deep"), Box::new(move |_| {}));

    // Layout the deepest (2-level) popbar
    tb.add_items_to_bar(&mut popbar2_id, vec![deep_button_id]);

    // Layout the middle (1-level) popbar
    tb.add_items_to_bar(&mut popbar1_id, vec![popbar_button_id, popbutton2_id, slider1_id, scrubber2_id]);

    // Layout the root bar
    tb.add_items_to_bar(&mut barid, vec![quit_id, button1_id, popbutton1_id, label1_id, scrubber1_id]);

    // Register the root bar and display it.
    tb.set_bar_as_root(barid);
}

fn main() {
    // Write log to home directory
    fruitbasket::create_logger(".rubrail.log", fruitbasket::LogDir::Home, 5, 2).unwrap();

    // Initialize OS X application.
    let icon = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("examples").join("icon.png");
    let mut nsapp = fruitbasket::Trampoline::new(
        "rubrail_example", "rubrail_example", "com.trevorbentley.rubrail_example")
        .icon("icon.png")
        .version(env!("CARGO_PKG_VERSION"))
        .plist_key("LSBackgroundOnly", "1")
        .resource(icon.to_str().unwrap())
        .build(fruitbasket::InstallDir::Custom("target/".to_string())).unwrap();
    nsapp.set_activation_policy(fruitbasket::ActivationPolicy::Prohibited);

    // Initialize the touchbar
    let bar_rc = Rc::new(RefCell::new(Touchbar::alloc("bar")));

    // Populate the touchbar with UI elements
    populate(bar_rc.clone(), 1);

    // Enter OS X application loop.
    nsapp.run(fruitbasket::RunPeriod::Forever);
}
<commit_msg>Use fruitbasket stopper correctly in example<commit_after>// Rubrail Example
//
// Demonstrates using Rubrail to layout and interact with a persistent Touchbar
// on Macbooks that support it.
//
// Usage notes:
//
// To access the touchbar, Rubrail *must* execute inside an OS X app bundle.
// Since Cargo doesn't do that itself, this example uses the Trampoline feature
// of the fruitbasket crate to relaunch itself in an app bundle.
//
// Simply run:
//
// $ cargo test && cargo run --example example
//
//
extern crate rubrail;
extern crate fruitbasket;

use rubrail::Touchbar;
use rubrail::TTouchbar;
use rubrail::TScrubberData;
use rubrail::ItemId;
use rubrail::SwipeState;

#[macro_use]
extern crate log;

use std::rc::Rc;
use std::cell::RefCell;

struct TouchbarHandler {
    devices: RefCell<Vec<String>>,
}
impl TScrubberData for TouchbarHandler {
    fn count(&self, _item: ItemId) -> u32 {
        self.devices.borrow().len() as u32
    }
    fn text(&self, _item: ItemId, idx: u32) -> String {
        self.devices.borrow()[idx as usize].to_string()
    }
    fn width(&self, _item: ItemId, idx: u32) -> u32 {
        // 10px per character + some padding seems to work nicely for the default
        // font.  no idea what it's like on other machines.  does the touchbar
        // font change? ¯\_(ツ)_/¯
        let len = self.devices.borrow()[idx as usize].len() as u32;
        let width = len * 8 + 20;
        width
    }
    fn touch(&self, _item: ItemId, idx: u32) {
        info!("scrub touch: {}", idx);
    }
}

fn populate(bar_rc: Rc<RefCell<Touchbar>>, count: u32, stopper: fruitbasket::FruitStopper) {
    // Get touchbar from the refcell.  It's wrapped in a cell so
    // it can be passed around in the button callbacks.
    let mut tb = (bar_rc).borrow_mut();

    // Create the lowest level "root" touchbar
    let mut barid = tb.create_bar();

    // Create a quit button for root bar
    let quit_stopper = stopper.clone();
    let quit_id = tb.create_button(None, Some("Quit"), Box::new(move |_| {quit_stopper.stop();}));

    // Create an action button for the root bar.  When clicked, it will
    // close the bar and re-create itself.
    let bar_copy = bar_rc.clone();
    let text = format!("button{}", count);
    let button1_id = tb.create_button(None, Some(&text), Box::new(move |_| {
        populate(bar_copy.clone(), count+1, stopper.clone())
    }));

    // Create a text label for the root bar
    let label1_id = tb.create_label("This is a label");
    tb.update_label(&label1_id, "This is a label\nWith two rows");
    tb.update_label_width(&label1_id, 100);

    // Support double-clicking the label with one finger
    tb.add_item_tap_gesture(&label1_id, 2, 1, Box::new(move |_item| {
        info!("Label double-clicked!");
    }));

    // Add a swipe gesture to the label that changes the text color to
    // increasingly green as you swipe right, or increasingly red as you swipe
    // left, and resets to white when released.
    tb.add_item_swipe_gesture(&label1_id, Box::new(move |item,state,translation| {
        let color: f64 = match translation.abs().trunc() as u32 {
            t if t < 10 => 1.0,
            t if t > 100 => 0.0,
            _ => (45. / translation.abs()),
        };
        let rgba = match state {
            SwipeState::Ended => (1.0, 1.0, 1.0, 1.0),
            _ => {
                match translation.is_sign_positive() {
                    true => (color, 1.0, color, 1.0),
                    false => (1.0, color, color, 1.0),
                }
            }
        };
        unsafe { rubrail::util::set_text_color(item, rgba.0, rgba.1, rgba.2, rgba.3); }
    }));

    // Create a data backend for scrolling text "scrubbers"
    let scrubber = Rc::new(TouchbarHandler {
        devices: RefCell::new(vec![
            "one".to_string(), "two".to_string(),
            "a little bit longer one".to_string(),
            "three".to_string(),
            "this one is really quite a bit longer than the others".to_string()]),
    });

    // Create a scrubber for the root bar
    let scrubber1_id = tb.create_text_scrubber(scrubber.clone());
    tb.select_scrubber_item(&scrubber1_id, 1);

    // Create a 'popbar', a second level deep bar
    let mut popbar1_id = tb.create_bar();
    let popbutton1_id = tb.create_popover_item(None, Some("Popbar1"), &popbar1_id);

    // Create another scrubber with the same data, for the popbar.
    // Note that the data and callbacks are shared, but this is a different
    // instance and can store a different active selection.
    let scrubber2_id = tb.create_text_scrubber(scrubber.clone());
    tb.select_scrubber_item(&scrubber2_id, 3);

    // Create a slider for the popbar.
    let slider1_id = tb.create_slider(0.0, 50.0, Some("Slide"), true,
                                      Box::new(move |_s,v| {info!("Slid to: {}", v);}));
    tb.update_slider(&slider1_id, 15.0);

    // Create a another popbar.  This will make a 2-level deep UI.
    let mut popbar2_id = tb.create_bar();
    let popbutton2_id = tb.create_popover_item(None, Some("Popbar2"), &popbar2_id);

    // Create buttons to display on the popbars
    let popbar_button_id = tb.create_button(None, Some("1 level deep"), Box::new(move |_| {}));
    let deep_button_id = tb.create_button(None, Some("2 levels deep"), Box::new(move |_| {}));

    // Layout the deepest (2-level) popbar
    tb.add_items_to_bar(&mut popbar2_id, vec![deep_button_id]);

    // Layout the middle (1-level) popbar
    tb.add_items_to_bar(&mut popbar1_id, vec![popbar_button_id, popbutton2_id, slider1_id, scrubber2_id]);

    // Layout the root bar
    tb.add_items_to_bar(&mut barid, vec![quit_id, button1_id, popbutton1_id, label1_id, scrubber1_id]);

    // Register the root bar and display it.
    tb.set_bar_as_root(barid);
}

fn main() {
    // Write log to home directory
    fruitbasket::create_logger(".rubrail.log", fruitbasket::LogDir::Home, 5, 2).unwrap();

    // Initialize OS X application.
    let icon = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("examples").join("icon.png");
    let mut nsapp = fruitbasket::Trampoline::new(
        "rubrail_example", "rubrail_example", "com.trevorbentley.rubrail_example")
        .icon("icon.png")
        .version(env!("CARGO_PKG_VERSION"))
        .plist_key("LSBackgroundOnly", "1")
        .resource(icon.to_str().unwrap())
        .build(fruitbasket::InstallDir::Custom("target/".to_string())).unwrap();
    nsapp.set_activation_policy(fruitbasket::ActivationPolicy::Prohibited);

    // Initialize the touchbar
    let bar_rc = Rc::new(RefCell::new(Touchbar::alloc("bar")));

    let stopper = nsapp.stopper();
    // Populate the touchbar with UI elements
    populate(bar_rc.clone(), 1, stopper);

    // Enter OS X application loop.
    nsapp.run(fruitbasket::RunPeriod::Forever);
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use decoders::cfa::*;
use std::f32::NAN;
use std::cmp;

#[derive(Debug, Clone)]
pub struct DngDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> DngDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> DngDecoder<'a> {
    DngDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for DngDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let ifds = self.tiff.find_ifds_with_tag(Tag::Compression).into_iter().filter(|ifd| {
      let compression = (**ifd).find_entry(Tag::Compression).unwrap().get_u32(0);
      let subsampled = match (**ifd).find_entry(Tag::NewSubFileType) {
        Some(e) => e.get_u32(0) & 1 != 0,
        None => false,
      };
      !subsampled && (compression == 7 || compression == 1 || compression == 0x884c)
    }).collect::<Vec<&TiffIFD>>();
    let raw = ifds[0];
    let width = fetch_tag!(raw, Tag::ImageWidth).get_usize(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_usize(0);

    let image = match fetch_tag!(raw, Tag::Compression).get_u32(0) {
      1 => try!(self.decode_uncompressed(raw, width, height)),
      7 => try!(self.decode_compressed(raw, width, height)),
      c => return Err(format!("Don't know how to read DNGs with compression {}", c).to_string()),
    };

    let (make, model, clean_make, clean_model) = {
      match self.rawloader.check_supported(&self.tiff) {
        Ok(cam) => {
          (cam.make.clone(), cam.model.clone(),
           cam.clean_make.clone(),cam.clean_model.clone())
        },
        Err(_) => {
          let make = fetch_tag!(self.tiff, Tag::Make).get_str();
          let model = fetch_tag!(self.tiff, Tag::Model).get_str();
          (make.to_string(), model.to_string(), make.to_string(), model.to_string())
        },
      }
    };

    Ok(Image {
      make: make,
      model: model,
      clean_make: clean_make,
      clean_model: clean_model,
      width: width,
      height: height,
      wb_coeffs: try!(self.get_wb()),
      data: image.into_boxed_slice(),
      blacklevels: try!(self.get_blacklevels(raw)),
      whitelevels: try!(self.get_whitelevels(raw)),
      xyz_to_cam: try!(self.get_color_matrix()),
      cfa: try!(self.get_cfa(raw)),
      crops: try!(self.get_crops(raw, width, height)),
    })
  }
}

impl<'a> DngDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  fn get_blacklevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    if let Some(levels) = raw.find_entry(Tag::BlackLevels) {
      if levels.count() < 4 {
        let black = levels.get_u32(0) as u16;
        Ok([black, black, black, black])
      } else {
        Ok([levels.get_u32(0) as u16,levels.get_u32(1) as u16,
            levels.get_u32(2) as u16,levels.get_u32(3) as u16])
      }
    } else {
      Ok([0,0,0,0])
    }
  }

  fn get_whitelevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    let level = fetch_tag!(raw, Tag::WhiteLevel).get_u32(0) as u16;
    Ok([level,level,level,level])
  }

  fn get_cfa(&self, raw: &TiffIFD) -> Result<CFA,String> {
    let pattern = fetch_tag!(raw, Tag::CFAPattern);
    Ok(CFA::new_from_tag(pattern))
  }

  fn get_crops(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<[usize;4],String> {
    if let Some(crops) = raw.find_entry(Tag::ActiveArea) {
      Ok([crops.get_usize(0), width - crops.get_usize(3),
          height - crops.get_usize(2), crops.get_usize(1)])
    } else {
      // Ignore missing crops, at least some pentax DNGs don't have it
      Ok([0,0,0,0])
    }
  }

  fn get_color_matrix(&self) -> Result<[[f32;3];4],String> {
    let mut matrix: [[f32;3];4] = [[0.0;3];4];
    let cmatrix = {
      if let Some(c) = self.tiff.find_entry(Tag::ColorMatrix2) {
        c
      } else {
        fetch_tag!(self.tiff, Tag::ColorMatrix1)
      }
    };
    if cmatrix.count() > 12 {
      Err(format!("color matrix supposedly has {} components",cmatrix.count()).to_string())
    } else {
      for i in 0..cmatrix.count() {
        matrix[i/3][i%3] = cmatrix.get_f32(i);
      }
      Ok(matrix)
    }
  }

  pub fn decode_uncompressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_usize(0);
    let src = &self.buffer[offset..];

    match fetch_tag!(raw, Tag::BitsPerSample).get_u32(0) {
      16  => Ok(decode_16le(src, width, height)),
      12  => Ok(decode_12be(src, width, height)),
      10  => Ok(decode_10le(src, width, height)),
      8   => {
        // It's 8 bit so there will be linearization involved surely!
        let linearization = fetch_tag!(self.tiff, Tag::Linearization);
        let curve = {
          let mut points = vec![0 as u16; 256];
          for i in 0..256 {
            points[i] = linearization.get_u32(i) as u16;
          }
          LookupTable::new(&points)
        };
        Ok(decode_8bit_wtable(src, &curve, width, height))
      },
      bps => Err(format!("DNG: Don't know about {} bps images", bps).to_string()),
    }
  }

  pub fn decode_compressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    if let Some(offsets) = raw.find_entry(Tag::StripOffsets) { // We're in a normal offset situation
      if offsets.count() != 1 {
        return Err("DNG: files with more than one slice not supported yet".to_string())
      }
      let offset = offsets.get_usize(0);
      let src = &self.buffer[offset..];
      let mut out = vec![0 as u16; width*height];
      let decompressor = try!(LjpegDecompressor::new(src, true));
      try!(decompressor.decode(&mut out, 0, width, width, height));
      Ok(out)
    } else if let Some(offsets) = raw.find_entry(Tag::TileOffsets) {
      // They've gone with tiling
      let twidth = fetch_tag!(raw, Tag::TileWidth).get_usize(0);
      let tlength = fetch_tag!(raw, Tag::TileLength).get_usize(0);
      let coltiles = (width-1)/twidth + 1;
      let rowtiles = (height-1)/tlength + 1;
      if coltiles*rowtiles != offsets.count() {
        return Err(format!("DNG: trying to decode {} tiles from {} offsets",
                           coltiles*rowtiles, offsets.count()).to_string())
      }

      Ok(decode_threaded_multiline(width, height, tlength, &(|strip: &mut [u16], row| {
        let row = row / tlength;
        for col in 0..coltiles {
          let offset = offsets.get_usize(row*coltiles+col);
          let src = &self.buffer[offset..];
          // We don't use bigtable here as the tiles are two small to amortize the setup cost
          let decompressor = LjpegDecompressor::new(src, true).unwrap();
          let bwidth = cmp::min(width, (col+1)*twidth) - col*twidth;
          let blength = cmp::min(height, (row+1)*tlength) - row*tlength;
          decompressor.decode(strip, col*twidth, width, bwidth, blength).unwrap();
        }
      })))
    } else {
      Err("DNG: didn't find tiles or strips".to_string())
    }
  }
}
<commit_msg>DNG: fix fetching of blacklevels when rational<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use decoders::cfa::*;
use std::f32::NAN;
use std::cmp;

#[derive(Debug, Clone)]
pub struct DngDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> DngDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> DngDecoder<'a> {
    DngDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for DngDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let ifds = self.tiff.find_ifds_with_tag(Tag::Compression).into_iter().filter(|ifd| {
      let compression = (**ifd).find_entry(Tag::Compression).unwrap().get_u32(0);
      let subsampled = match (**ifd).find_entry(Tag::NewSubFileType) {
        Some(e) => e.get_u32(0) & 1 != 0,
        None => false,
      };
      !subsampled && (compression == 7 || compression == 1 || compression == 0x884c)
    }).collect::<Vec<&TiffIFD>>();
    let raw = ifds[0];
    let width = fetch_tag!(raw, Tag::ImageWidth).get_usize(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_usize(0);

    let image = match fetch_tag!(raw, Tag::Compression).get_u32(0) {
      1 => try!(self.decode_uncompressed(raw, width, height)),
      7 => try!(self.decode_compressed(raw, width, height)),
      c => return Err(format!("Don't know how to read DNGs with compression {}", c).to_string()),
    };

    let (make, model, clean_make, clean_model) = {
      match self.rawloader.check_supported(&self.tiff) {
        Ok(cam) => {
          (cam.make.clone(), cam.model.clone(),
           cam.clean_make.clone(),cam.clean_model.clone())
        },
        Err(_) => {
          let make = fetch_tag!(self.tiff, Tag::Make).get_str();
          let model = fetch_tag!(self.tiff, Tag::Model).get_str();
          (make.to_string(), model.to_string(), make.to_string(), model.to_string())
        },
      }
    };

    Ok(Image {
      make: make,
      model: model,
      clean_make: clean_make,
      clean_model: clean_model,
      width: width,
      height: height,
      wb_coeffs: try!(self.get_wb()),
      data: image.into_boxed_slice(),
      blacklevels: try!(self.get_blacklevels(raw)),
      whitelevels: try!(self.get_whitelevels(raw)),
      xyz_to_cam: try!(self.get_color_matrix()),
      cfa: try!(self.get_cfa(raw)),
      crops: try!(self.get_crops(raw, width, height)),
    })
  }
}

impl<'a> DngDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  fn get_blacklevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    if let Some(levels) = raw.find_entry(Tag::BlackLevels) {
      if levels.count() < 4 {
        let black = levels.get_f32(0) as u16;
        Ok([black, black, black, black])
      } else {
        Ok([levels.get_f32(0) as u16,levels.get_f32(1) as u16,
            levels.get_f32(2) as u16,levels.get_f32(3) as u16])
      }
    } else {
      Ok([0,0,0,0])
    }
  }

  fn get_whitelevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    let level = fetch_tag!(raw, Tag::WhiteLevel).get_u32(0) as u16;
    Ok([level,level,level,level])
  }

  fn get_cfa(&self, raw: &TiffIFD) -> Result<CFA,String> {
    let pattern = fetch_tag!(raw, Tag::CFAPattern);
    Ok(CFA::new_from_tag(pattern))
  }

  fn get_crops(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<[usize;4],String> {
    if let Some(crops) = raw.find_entry(Tag::ActiveArea) {
      Ok([crops.get_usize(0), width - crops.get_usize(3),
          height - crops.get_usize(2), crops.get_usize(1)])
    } else {
      // Ignore missing crops, at least some pentax DNGs don't have it
      Ok([0,0,0,0])
    }
  }

  fn get_color_matrix(&self) -> Result<[[f32;3];4],String> {
    let mut matrix: [[f32;3];4] = [[0.0;3];4];
    let cmatrix = {
      if let Some(c) = self.tiff.find_entry(Tag::ColorMatrix2) {
        c
      } else {
        fetch_tag!(self.tiff, Tag::ColorMatrix1)
      }
    };
    if cmatrix.count() > 12 {
      Err(format!("color matrix supposedly has {} components",cmatrix.count()).to_string())
    } else {
      for i in 0..cmatrix.count() {
        matrix[i/3][i%3] = cmatrix.get_f32(i);
      }
      Ok(matrix)
    }
  }

  pub fn decode_uncompressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_usize(0);
    let src = &self.buffer[offset..];

    match fetch_tag!(raw, Tag::BitsPerSample).get_u32(0) {
      16  => Ok(decode_16le(src, width, height)),
      12  => Ok(decode_12be(src, width, height)),
      10  => Ok(decode_10le(src, width, height)),
      8   => {
        // It's 8 bit so there will be linearization involved surely!
        let linearization = fetch_tag!(self.tiff, Tag::Linearization);
        let curve = {
          let mut points = vec![0 as u16; 256];
          for i in 0..256 {
            points[i] = linearization.get_u32(i) as u16;
          }
          LookupTable::new(&points)
        };
        Ok(decode_8bit_wtable(src, &curve, width, height))
      },
      bps => Err(format!("DNG: Don't know about {} bps images", bps).to_string()),
    }
  }

  pub fn decode_compressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    if let Some(offsets) = raw.find_entry(Tag::StripOffsets) { // We're in a normal offset situation
      if offsets.count() != 1 {
        return Err("DNG: files with more than one slice not supported yet".to_string())
      }
      let offset = offsets.get_usize(0);
      let src = &self.buffer[offset..];
      let mut out = vec![0 as u16; width*height];
      let decompressor = try!(LjpegDecompressor::new(src, true));
      try!(decompressor.decode(&mut out, 0, width, width, height));
      Ok(out)
    } else if let Some(offsets) = raw.find_entry(Tag::TileOffsets) {
      // They've gone with tiling
      let twidth = fetch_tag!(raw, Tag::TileWidth).get_usize(0);
      let tlength = fetch_tag!(raw, Tag::TileLength).get_usize(0);
      let coltiles = (width-1)/twidth + 1;
      let rowtiles = (height-1)/tlength + 1;
      if coltiles*rowtiles != offsets.count() {
        return Err(format!("DNG: trying to decode {} tiles from {} offsets",
                           coltiles*rowtiles, offsets.count()).to_string())
      }

      Ok(decode_threaded_multiline(width, height, tlength, &(|strip: &mut [u16], row| {
        let row = row / tlength;
        for col in 0..coltiles {
          let offset = offsets.get_usize(row*coltiles+col);
          let src = &self.buffer[offset..];
          // We don't use bigtable here as the tiles are two small to amortize the setup cost
          let decompressor = LjpegDecompressor::new(src, true).unwrap();
          let bwidth = cmp::min(width, (col+1)*twidth) - col*twidth;
          let blength = cmp::min(height, (row+1)*tlength) - row*tlength;
          decompressor.decode(strip, col*twidth, width, bwidth, blength).unwrap();
        }
      })))
    } else {
      Err("DNG: didn't find tiles or strips".to_string())
    }
  }
}
<|endoftext|>


<commit_before>extern crate autograd as ag;
extern crate ndarray;

type Tensor = ag::Tensor<f32>;

struct LSTM {
    vector_dim: usize,
    hs: Vec<Tensor>,
    cells: Vec<Tensor>,
    wx: Tensor,
    wh: Tensor,
    b: Tensor,
}

impl LSTM {
    fn new(vector_dim: usize) -> LSTM {
        LSTM {
            vector_dim,
            hs: vec![],
            cells: vec![],
            wx: ag::variable(ag::ndarray_ext::random_normal(
                &[vector_dim, 4 * vector_dim],
                0.,
                0.01,
            )),
            wh: ag::variable(ag::ndarray_ext::random_normal(
                &[vector_dim, 4 * vector_dim],
                0.,
                0.01,
            )),
            b: ag::variable(ag::ndarray_ext::zeros(&[1, 4 * vector_dim])),
        }
    }

    /// Applies standard LSTM unit without peephole to `x`.
    /// `x` must be a tensor with shape `(batch_size, embedding_dim)`
    ///
    /// # Returns
    /// Output tensor of this unit with shape `(batch_size, state_size)`.
    fn step(&mut self, x: &Tensor) -> &Tensor {
        let (cell, h) = {
            let ref last_output = self.hs.pop().unwrap_or_else(|| ag::zeros(&x.shape()));
            let ref last_cell = self.cells.pop().unwrap_or_else(|| ag::zeros(&x.shape()));

            let ref xh = ag::matmul(x, &self.wx) + ag::matmul(last_output, &self.wh) + &self.b;

            let size = self.vector_dim as isize;
            let ref i = ag::slice(xh, &[0, 0 * size], &[-1, 1 * size]);
            let ref f = ag::slice(xh, &[0, 1 * size], &[-1, 2 * size]);
            let ref c = ag::slice(xh, &[0, 2 * size], &[-1, 3 * size]);
            let ref o = ag::slice(xh, &[0, 3 * size], &[-1, 4 * size]);

            let cell = ag::sigmoid(f) * last_cell + ag::sigmoid(i) * ag::tanh(c);
            let h = ag::sigmoid(o) * ag::tanh(&cell);
            (cell, h)
        };
        self.cells.push(cell);
        self.hs.push(h);
        self.hs.last().as_ref().unwrap()
    }
}

// TODO: Use real-world data
// TODO: Write in define-by-run style
pub fn main() {
    let vec_dim = 4;
    let max_sent = 2;
    let vocab_size = 5;

    let ref sentences = ag::placeholder(&[-1, max_sent]);
    let ref mut rnn = LSTM::new(vec_dim);

    let lookup_table = &ag::variable(ag::ndarray_ext::random_normal(
        &[vocab_size, vec_dim],
        0.,
        0.01,
    ));
    let w_pred = &ag::variable(ag::ndarray_ext::random_uniform(
        &[vec_dim, vocab_size],
        0.,
        0.01,
    ));

    // Compute cross entropy losses for each LSTM step
    let losses: Vec<Tensor> = (0..max_sent)
        .map(|i| {
            let cur_id = ag::slice(sentences, &[0, i], &[-1, i + 1]);
            let next_id = ag::slice(sentences, &[0, i + 1], &[-1, i + 2]);
            let x = ag::gather(lookup_table, &cur_id, 0);
            let h = rnn.step(&x);
            let prediction = ag::matmul(h, w_pred);
            ag::sparse_softmax_cross_entropy(prediction, next_id)
        })
        .collect();

    // Aggregate losses of generated words
    let ref loss = ag::add_n(losses.iter().map(|a| a).collect::<Vec<_>>().as_slice());

    // Compute gradients
    let vars = &[&rnn.wh, &rnn.wx, &rnn.b, lookup_table, w_pred];
    let grads = ag::grad(&[loss], vars);

    // test with toy data
    ag::test_helper::check_theoretical_grads(
        loss,
        &grads,
        vars,
        &[ag::Feed(
            sentences,
            ndarray::arr2(&[[2., 3., 1.], [3., 0., 1.]])
                .into_dyn()
                .view(),
        )],
        1e-3,
        1e-3,
    );
}
<commit_msg>Fix lstm example<commit_after>extern crate autograd as ag;
extern crate ndarray;

type Tensor = ag::Tensor<f32>;

struct LSTM {
    vector_dim: usize,
    hs: Vec<Tensor>,
    cells: Vec<Tensor>,
    wx: Tensor,
    wh: Tensor,
    b: Tensor,
}

impl LSTM {
    fn new(vector_dim: usize) -> LSTM {
        LSTM {
            vector_dim,
            hs: vec![],
            cells: vec![],
            wx: ag::variable(ag::ndarray_ext::random_normal(
                &[vector_dim, 4 * vector_dim],
                0.,
                0.01,
            )),
            wh: ag::variable(ag::ndarray_ext::random_normal(
                &[vector_dim, 4 * vector_dim],
                0.,
                0.01,
            )),
            b: ag::variable(ag::ndarray_ext::zeros(&[1, 4 * vector_dim])),
        }
    }

    /// Applies standard LSTM unit without peephole to `x`.
    /// `x` must be a tensor with shape `(batch_size, embedding_dim)`
    ///
    /// # Returns
    /// Output tensor of this unit with shape `(batch_size, state_size)`.
    fn step(&mut self, x: &Tensor) -> &Tensor {
        let (cell, h) = {
            let ref last_output = self.hs.pop().unwrap_or_else(|| ag::zeros(&x.shape()));
            let ref last_cell = self.cells.pop().unwrap_or_else(|| ag::zeros(&x.shape()));

            let ref xh = ag::matmul(x, &self.wx) + ag::matmul(last_output, &self.wh) + &self.b;

            let size = self.vector_dim as isize;
            let ref i = ag::slice(xh, &[0, 0 * size], &[-1, 1 * size]);
            let ref f = ag::slice(xh, &[0, 1 * size], &[-1, 2 * size]);
            let ref c = ag::slice(xh, &[0, 2 * size], &[-1, 3 * size]);
            let ref o = ag::slice(xh, &[0, 3 * size], &[-1, 4 * size]);

            let cell = ag::sigmoid(f) * last_cell + ag::sigmoid(i) * ag::tanh(c);
            let h = ag::sigmoid(o) * ag::tanh(&cell);
            (cell, h)
        };
        self.cells.push(cell);
        self.hs.push(h);
        self.hs.last().as_ref().unwrap()
    }
}

// TODO: Use real-world data
// TODO: Write in define-by-run style
pub fn main() {
    let vec_dim = 4;
    let max_sent = 3;
    let vocab_size = 5;

    let ref sentences = ag::placeholder(&[-1, max_sent]);
    let ref mut rnn = LSTM::new(vec_dim);

    let lookup_table = &ag::variable(ag::ndarray_ext::random_normal(
        &[vocab_size, vec_dim],
        0.,
        0.01,
    ));
    let w_pred = &ag::variable(ag::ndarray_ext::random_uniform(
        &[vec_dim, vocab_size],
        0.,
        0.01,
    ));

    // Compute cross entropy losses for each LSTM step
    let losses: Vec<Tensor> = (0..max_sent)
        .map(|i| {
            let cur_id = ag::slice(sentences, &[0, i], &[-1, i + 1]);
            let next_id = ag::slice(sentences, &[0, i + 1], &[-1, i + 2]);
            let x = ag::gather(lookup_table, &cur_id, 0);
            let h = rnn.step(&x);
            let prediction = ag::matmul(h, w_pred);
            ag::sparse_softmax_cross_entropy(prediction, next_id)
        })
        .collect();

    // Aggregate losses of generated words
    let ref loss = ag::add_n(losses.iter().map(|a| a).collect::<Vec<_>>().as_slice());

    // Compute gradients
    let vars = &[&rnn.wh, &rnn.wx, &rnn.b, lookup_table, w_pred];
    let grads = ag::grad(&[loss], vars);

    // test with toy data
    ag::test_helper::check_theoretical_grads(
        loss,
        &grads,
        vars,
        &[ag::Feed(
            sentences,
            ndarray::arr2(&[[2., 3., 1.], [3., 0., 1.]])
                .into_dyn()
                .view(),
        )],
        1e-3,
        1e-3,
    );
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate cnx;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate log;

use std::env;

use env_logger::LogBuilder;
use log::LogLevelFilter;

use cnx::*;
use cnx::widgets::*;

// This will not be needed in error-chain 0.11:
#[allow(unused_doc_comment)]
mod errors {
    error_chain! {
        links {
            Cnx(::cnx::errors::Error, ::cnx::errors::ErrorKind);
        }
        foreign_links {
            SetLogger(::log::SetLoggerError);
        }
    }
}

fn init_log() -> errors::Result<()> {
    let mut builder = LogBuilder::new();
    builder.filter(Some("cnx"), LogLevelFilter::Trace);
    if let Ok(rust_log) = env::var("RUST_LOG") {
       builder.parse(&rust_log);
    }
    Ok(builder.init()?)
}

fn run() -> errors::Result<()> {
    init_log()?;

    let attr = Attributes {
        font: Font::new("SourceCodePro 21"),
        fg_color: Color::white(),
        bg_color: None,
        padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    };
    let mut active_attr = attr.clone();
    active_attr.bg_color = Some(Color::blue());

    let mut cnx = Cnx::new(Position::Top)?;

    cnx_add_widget!(cnx, Pager::new(&cnx, active_attr, attr.clone()));
    cnx_add_widget!(cnx, ActiveWindowTitle::new(&cnx, attr.clone()));
    cnx_add_widget!(
        cnx,
        Sensors::new(&cnx, attr.clone(), vec!["Core 0", "Core 1"])
    );
    cnx_add_widget!(cnx, Volume::new(&cnx, attr.clone()));
    cnx_add_widget!(cnx, Battery::new(&cnx, attr.clone(), Color::red()));
    cnx_add_widget!(cnx, Clock::new(&cnx, attr.clone()));

    Ok(cnx.run()?)
}

quick_main!(run);
<commit_msg>unused_doc_comment is nightly only.<commit_after>#[macro_use]
extern crate cnx;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate log;

use std::env;

use env_logger::LogBuilder;
use log::LogLevelFilter;

use cnx::*;
use cnx::widgets::*;

// This will not be needed in error-chain 0.11:
#[allow(unknown_lints, unused_doc_comment)]
mod errors {
    error_chain! {
        links {
            Cnx(::cnx::errors::Error, ::cnx::errors::ErrorKind);
        }
        foreign_links {
            SetLogger(::log::SetLoggerError);
        }
    }
}

fn init_log() -> errors::Result<()> {
    let mut builder = LogBuilder::new();
    builder.filter(Some("cnx"), LogLevelFilter::Trace);
    if let Ok(rust_log) = env::var("RUST_LOG") {
       builder.parse(&rust_log);
    }
    Ok(builder.init()?)
}

fn run() -> errors::Result<()> {
    init_log()?;

    let attr = Attributes {
        font: Font::new("SourceCodePro 21"),
        fg_color: Color::white(),
        bg_color: None,
        padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    };
    let mut active_attr = attr.clone();
    active_attr.bg_color = Some(Color::blue());

    let mut cnx = Cnx::new(Position::Top)?;

    cnx_add_widget!(cnx, Pager::new(&cnx, active_attr, attr.clone()));
    cnx_add_widget!(cnx, ActiveWindowTitle::new(&cnx, attr.clone()));
    cnx_add_widget!(
        cnx,
        Sensors::new(&cnx, attr.clone(), vec!["Core 0", "Core 1"])
    );
    cnx_add_widget!(cnx, Volume::new(&cnx, attr.clone()));
    cnx_add_widget!(cnx, Battery::new(&cnx, attr.clone(), Color::red()));
    cnx_add_widget!(cnx, Clock::new(&cnx, attr.clone()));

    Ok(cnx.run()?)
}

quick_main!(run);
<|endoftext|>


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

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;
use std::cmp::Ordering;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                if let Some(result) = symbol_a.partial_cmp(symbol_b) {
                    result
                } else {
                    // Unordered input symbols won't work well
                    Ordering::Equal
                }
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);
        let state_zero_output = if let Some(output_symbol) = self.ndfa.output_symbol_for_state(0) { vec![output_symbol.clone()] } else { vec![] };

        states.push(DfaTransitions { state_id: 0, transitions: vec![], output: state_zero_output });
        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::build(ndfa, builder);
    }
}
<commit_msg>Try expanding our test into one that actually runs the DFA<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;
use std::cmp::Ordering;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    /// List of the states from the NDFA that make up this DFA state (will be ordered if `dedupe` is called)
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol, OutputSymbol: Ord> {
    /// ID of this state in the resulting DFA
    state_id: StateId,

    /// Transitions for this state (will be unique if `merge_states` is called)
    transitions: Vec<(InputSymbol, DfaState)>,

    /// The output symbols for this state (empty if this is not an accepting state)
    output: Vec<OutputSymbol>
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord> DfaTransitions<InputSymbol, OutputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                if let Some(result) = symbol_a.partial_cmp(symbol_b) {
                    result
                } else {
                    // Unordered input symbols won't work well
                    Ordering::Equal
                }
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }

    ///
    /// Finds the output symbol that corresponds to this state
    ///
    /// Rule is that if there is more than one output symbol then the symbol whose value is ordered lowest is the output for this state
    ///
    fn output_symbol(&mut self) -> Option<&OutputSymbol> {
        if self.output.len() > 0 {
            self.output.sort();
            Some(&self.output[0])
        } else {
            None
        }
    }
}

impl<InputSymbol: PartialOrd+Clone, OutputSymbol: Ord+Clone, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);
        let state_zero_output = if let Some(output_symbol) = self.ndfa.output_symbol_for_state(0) { vec![output_symbol.clone()] } else { vec![] };

        states.push(DfaTransitions { state_id: 0, transitions: vec![], output: state_zero_output });
        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];
            let mut output      = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }

                if let Some(source_output) = self.ndfa.output_symbol_for_state(*source_state) {
                    output.push(source_output.clone());
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions, output: output };
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for mut dfa_state in states {
            builder.start_state();

            if let Some(output_symbol) = dfa_state.output_symbol() {
                builder.accept(output_symbol.clone());
            }

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;
    use super::super::pattern_matcher::*;
    use super::super::symbol_reader::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        let ndfa     = "abc".into_pattern().to_ndfa("Success");
        let builder  = SymbolRangeDfaBuilder::new();

        let state_machine = DfaCompiler::build(ndfa, builder);

        let mut state = More(state_machine.start());
        let mut input = "abc".read_symbols();

        while let More(this_state) = state {
            let next_state =
                if let Some(next_char) = input.next_symbol() {
                    this_state.next(next_char)
                } else {
                    this_state.finish()
                };

            state = next_state;
        }

        if let Accept(count, output) = state {
            assert!(count == 3);
            assert!(output == &"Success");
        } else {
            assert!(false);
        }
    }
}
<|endoftext|>


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

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd, OutputSymbol, DfaType, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>, Ndfa: StateMachine<InputSymbol, OutputSymbol>> {
    ndfa: Ndfa,
    builder: Builder
}

impl<InputSymbol: PartialOrd, OutputSymbol, DfaType, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>, Ndfa: StateMachine<InputSymbol, OutputSymbol>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Builder, Ndfa> {
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder }
    }
}
<commit_msg>Can make the DFA compiler work using annoying references<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a, DfaType: 'a> {
    //
    // Would like to do this without the references and weird lifetime stuff. There's a bunch of limitations about what you can do
    // when calling references to traits vs concrete types that make designing rust code very annoying. However, if you have a struct
    // declared thusly: struct Foo<Bar, Quux: Baz<Bar>> and only use a field of type Quux then it'll moan that 'Bar' is unused, which
    // is incorrect (it's used wherever Quux is used by definition), so you have to declare Foo<Bar> and use a reference to Baz<Bar>
    // which means a lot of code won't work due to the whole mess around things needing to be sized.
    //
    // This basically means we can't declare ndfa or builder here using their real types. PhantomData also doesn't work because rust
    // isn't smart enough to work out that if it knows the type of the state machine it also knows what InputSymbol and OutputSymbol
    // are.
    //

    ndfa: &'a StateMachine<InputSymbol, OutputSymbol>,
    builder: &'a mut DfaBuilder<InputSymbol, OutputSymbol, DfaType>,
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a, DfaType: 'a> DfaCompiler<'a, InputSymbol, OutputSymbol, DfaType> {
    pub fn new(ndfa: &'a StateMachine<InputSymbol, OutputSymbol>, builder: &'a mut DfaBuilder<InputSymbol, OutputSymbol, DfaType>) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder }
    }
}
<|endoftext|>