<commit_before>use columnvalueops::ColumnValueOps;
use databaseinfo::{DatabaseInfo, TableInfo};
use identifier::Identifier;
use sqlsyntax::ast;

use std::fmt;

mod columnnames;
mod execute;
mod sexpression;
mod source;
pub use self::columnnames::*;
pub use self::execute::*;
pub use self::sexpression::*;
use self::source::*;

pub enum QueryPlanCompileError {
    TableDoesNotExist(Identifier),
    /// ambiguous column name; two or more tables have a column of the same name
    AmbiguousColumnName(Identifier),
    BadIdentifier(String),
    BadStringLiteral(String),
    BadNumberLiteral(String)
}

impl fmt::Display for QueryPlanCompileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::QueryPlanCompileError::*;

        match self {
            &TableDoesNotExist(ref name) => {
                write!(f, "table does not exist: {}", name)
            },
            &AmbiguousColumnName(ref name) => {
                write!(f, "ambiguous column name: {}", name)
            },
            &BadIdentifier(ref name) => {
                write!(f, "bad identifier: {}", name)
            },
            &BadStringLiteral(ref s) => {
                write!(f, "bad string literal: {}", s)
            },
            &BadNumberLiteral(ref s) => {
                write!(f, "bad number literal: {}", s)
            },
        }
    }
}

pub struct QueryPlan<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    pub expr: SExpression<'a, DB>,
    pub out_column_names: ColumnNames
}

fn new_identifier(value: &str) -> Result<Identifier, QueryPlanCompileError> {
    Identifier::new(value).ok_or(QueryPlanCompileError::BadIdentifier(value.to_string()))
}

impl<'a, DB: DatabaseInfo> QueryPlan<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    pub fn compile_select(db: &'a DB, stmt: ast::SelectStatement)
    -> Result<QueryPlan<'a, DB>, QueryPlanCompileError>
    {
        let scope = SourceScope {
            parent: None,
            tables: Vec::new(),
            table_aliases: Vec::new()
        };

        let mut source_id: u32 = 0;

        let mut source_id_fn = || {
            let old_source_id = source_id;
            source_id += 1;
            old_source_id
        };

        QueryPlan::compile_select_recurse(db, stmt, &scope, &mut source_id_fn)
    }

    fn compile_select_recurse<'b, F>(db: &'a DB, stmt: ast::SelectStatement, scope: &'b SourceScope<'a, 'b, DB>, new_source_id: &mut F)
    -> Result<QueryPlan<'a, DB>, QueryPlanCompileError>
    where F: FnMut() -> u32
    {
        // Unimplemented syntaxes: GROUP BY, HAVING, ORDER BY
        // TODO - implement them!
        if !stmt.group_by.is_empty() { unimplemented!() }
        if stmt.having.is_some() { unimplemented!() }
        if !stmt.order_by.is_empty() { unimplemented!() }

        let mut arbitrary_column_count = 0;

        let mut arbitrary_column_name = || {
            let s = format!("_{}", arbitrary_column_count);
            arbitrary_column_count += 1;

            Identifier::new(&s).unwrap()
        };

        // FROM and WHERE are compiled together.
        // This makes sense for INNER and OUTER joins, which also
        // contain ON (conditional) expressions.

        let (new_scope, where_expr) = try!(QueryPlan::from_where(stmt.from, stmt.where_expr, db, scope, new_source_id));

        // prevent accidental use of the old scope
        drop(scope);

        // TODO: refactor this terrible mess.
        let (column_names, select_exprs) = {
            let mut a: Vec<_> = Vec::new();
            for c in stmt.result_columns {
                match c {
                    ast::SelectColumn::AllColumns => {
                        for (i, table) in new_scope.tables.iter().enumerate() {
                            match table {
                                &TableOrSubquery::Table { source_id, table} => {
                                    let it = table.get_column_names().into_iter().enumerate().map(|(i, name)| {
                                        (name, SExpression::ColumnField {
                                            source_id: source_id,
                                            column_offset: i as u32
                                        })
                                    });

                                    a.extend(it);
                                },
                                &TableOrSubquery::Subquery { source_id, ref out_column_names, .. } => {
                                    let it = out_column_names.iter().enumerate().map(|(i, name)| {
                                        (name.clone(), SExpression::ColumnField {
                                            source_id: source_id,
                                            column_offset: i as u32
                                        })
                                    });

                                    a.extend(it);
                                }
                            }
                        }
                    },
                    ast::SelectColumn::Expr { expr, alias } => {
                        let column_name = if let Some(alias) = alias {
                            try!(new_identifier(&alias))
                        } else {
                            // if the expression is a simple identifier, make that
                            // the column name. else, assign an arbitrary name.
                            if let &ast::Expression::Ident(ref n) = &expr {
                                try!(new_identifier(n))
                            } else {
                                arbitrary_column_name()
                            }
                        };

                        let e = try!(QueryPlan::ast_expression_to_sexpression(expr, db, &new_scope, new_source_id));
                        a.push((column_name, e));
                    }
                }
            }

            let (column_names, select_exprs) = a.into_iter().unzip();

            (ColumnNames::new(column_names), select_exprs)
        };

        let core_expr = if let Some(where_expr) = where_expr {
            SExpression::If {
                predicate: Box::new(where_expr),
                yield_fn: Box::new(SExpression::Yield { fields: select_exprs })
            }
        } else {
            SExpression::Yield { fields: select_exprs }
        };

        // table references and source ids need to be known at this point
        let expr = new_scope.tables.into_iter().fold(core_expr, |nested_expr, x| {
            match x {
                TableOrSubquery::Subquery { source_id, expr, .. } => {
                    SExpression::Map {
                        source_id: source_id,
                        yield_in_fn: Box::new(expr),
                        yield_out_fn: Box::new(nested_expr)
                    }
                },
                TableOrSubquery::Table { source_id, table } => {
                    SExpression::Scan {
                        source_id: source_id,
                        table: table,
                        yield_fn: Box::new(nested_expr)
                    }
                }
            }
        });

        Ok(QueryPlan {
            expr: expr,
            out_column_names: column_names
        })
    }

    fn from_where<'b, F>(from: ast::From, where_expr: Option<ast::Expression>, db: &'a DB, scope: &'b SourceScope<'a, 'b, DB>, new_source_id: &mut F)
    -> Result<(SourceScope<'a, 'b, DB>, Option<SExpression<'a, DB>>), QueryPlanCompileError>
    where F: FnMut() -> u32
    {
        // TODO - avoid naive nested scans when indices are available

        // All FROM subqueries are nested, never correlated.
        let ast_cross_tables = match from {
            ast::From::Cross(v) => v,
            ast::From::Join {..} => unimplemented!()
        };

        let a: Vec<_> = try!(ast_cross_tables.into_iter().map(|ast_table_or_subquery| {
            match ast_table_or_subquery {
                ast::TableOrSubquery::Subquery { subquery, alias } => {
                    let plan = try!(QueryPlan::compile_select_recurse(db, *subquery, scope, new_source_id));
                    let alias_identifier = try!(new_identifier(&alias));

                    let s = TableOrSubquery::Subquery {
                        source_id: new_source_id(),
                        expr: plan.expr,
                        out_column_names: plan.out_column_names
                    };

                    Ok((s, alias_identifier))
                },
                ast::TableOrSubquery::Table { table, alias } => {
                    let table_name_identifier = try!(new_identifier(&table.table_name));
                    let table = match db.find_table_by_name(&table_name_identifier) {
                        Some(table) => table,
                        None => return Err(QueryPlanCompileError::TableDoesNotExist(table_name_identifier))
                    };

                    let alias_identifier = if let Some(alias) = alias {
                        try!(new_identifier(&alias))
                    } else {
                        table_name_identifier
                    };

                    let s = TableOrSubquery::Table {
                        source_id: new_source_id(),
                        table: table
                    };

                    Ok((s, alias_identifier))
                }
            }
        }).collect());

        let (tables, table_aliases) = a.into_iter().unzip();

        let new_scope = SourceScope {
            parent: Some(scope),
            tables: tables,
            table_aliases: table_aliases
        };

        let where_expr = if let Some(where_expr) = where_expr {
            Some(try!(QueryPlan::ast_expression_to_sexpression(where_expr, db, &new_scope, new_source_id)))
        } else {
            None
        };

        Ok((new_scope, where_expr))
    }

    fn ast_expression_to_sexpression<'b, F>(ast: ast::Expression, db: &'a DB, scope: &'b SourceScope<'a, 'b, DB>, new_source_id: &mut F)
    -> Result<SExpression<'a, DB>, QueryPlanCompileError>
    where F: FnMut() -> u32
    {
        use std::borrow::IntoCow;

        match ast {
            ast::Expression::Ident(s) => {
                let column_identifier = try!(new_identifier(&s));

                let (source_id, column_offset) = match scope.get_column_offset(&column_identifier) {
                    Some(v) => v,
                    None => return Err(QueryPlanCompileError::AmbiguousColumnName(column_identifier))
                };

                Ok(SExpression::ColumnField {
                    source_id: source_id,
                    column_offset: column_offset
                })
            },
            ast::Expression::IdentMember(s1, s2) => {
                let table_identifier = try!(new_identifier(&s1));
                let column_identifier = try!(new_identifier(&s2));

                let (source_id, column_offset) = match scope.get_table_column_offset(&table_identifier, &column_identifier) {
                    Some(v) => v,
                    None => return Err(QueryPlanCompileError::AmbiguousColumnName(column_identifier))
                };

                Ok(SExpression::ColumnField {
                    source_id: source_id,
                    column_offset: column_offset
                })
            },
            ast::Expression::BinaryOp { lhs, rhs, op } => {
                let l = try!(QueryPlan::ast_expression_to_sexpression(*lhs, db, scope, new_source_id));
                let r = try!(QueryPlan::ast_expression_to_sexpression(*rhs, db, scope, new_source_id));

                Ok(SExpression::BinaryOp {
                    op: ast_binaryop_to_sexpression_binaryop(op),
                    lhs: Box::new(l),
                    rhs: Box::new(r)
                })
            },
            ast::Expression::StringLiteral(s) => {
                match DB::ColumnValue::from_string_literal(s.into_cow()) {
                    Ok(value) => Ok(SExpression::Value(value)),
                    Err(s) => Err(QueryPlanCompileError::BadStringLiteral(s.into_owned()))
                }
            },
            ast::Expression::Number(s) => {
                match DB::ColumnValue::from_number_literal(s.into_cow()) {
                    Ok(value) => Ok(SExpression::Value(value)),
                    Err(s) => Err(QueryPlanCompileError::BadNumberLiteral(s.into_owned()))
                }
            },
            ast::Expression::Subquery(subquery) => {
                let source_id = new_source_id();

                let plan = try!(QueryPlan::compile_select_recurse(db, *subquery, scope, new_source_id));

                Ok(SExpression::Map {
                    source_id: source_id,
                    yield_in_fn: Box::new(plan.expr),
                    yield_out_fn: Box::new(SExpression::ColumnField {
                        source_id: source_id,
                        column_offset: 0
                    })
                })
            }
            e => panic!("unimplemented: {:?}", e)
        }
    }
}

fn ast_binaryop_to_sexpression_binaryop(ast: ast::BinaryOp) -> BinaryOp {
    match ast {
        ast::BinaryOp::Equal => BinaryOp::Equal,
        ast::BinaryOp::NotEqual => BinaryOp::NotEqual,
        ast::BinaryOp::LessThan => BinaryOp::LessThan,
        ast::BinaryOp::LessThanOrEqual => BinaryOp::LessThanOrEqual,
        ast::BinaryOp::GreaterThan => BinaryOp::GreaterThan,
        ast::BinaryOp::GreaterThanOrEqual => BinaryOp::GreaterThanOrEqual,
        ast::BinaryOp::And => BinaryOp::And,
        ast::BinaryOp::Or => BinaryOp::Or,
        ast::BinaryOp::Add => BinaryOp::Add,
        ast::BinaryOp::Subtract => BinaryOp::Subtract,
        ast::BinaryOp::Multiply => BinaryOp::Multiply,
        ast::BinaryOp::BitAnd => BinaryOp::BitAnd,
        ast::BinaryOp::BitOr => BinaryOp::BitOr,
        ast::BinaryOp::Concatenate => BinaryOp::Concatenate,
    }
}

impl<'a, DB: DatabaseInfo> fmt::Display for QueryPlan<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let cn: Vec<_> = self.out_column_names.iter().map(|n| format!("`{}`", n)).collect();

        try!(writeln!(f, "query plan"));
        try!(writeln!(f, "column names: ({})", cn.connect(", ")));
        self.expr.fmt(f)
    }
}
<commit_msg>Refactor query plan compiler into a `Compiler` type<commit_after>use columnvalueops::ColumnValueOps;
use databaseinfo::{DatabaseInfo, TableInfo};
use identifier::Identifier;
use sqlsyntax::ast;

use std::fmt;

mod columnnames;
mod execute;
mod sexpression;
mod source;
pub use self::columnnames::*;
pub use self::execute::*;
pub use self::sexpression::*;
use self::source::*;

pub enum QueryPlanCompileError {
    TableDoesNotExist(Identifier),
    /// ambiguous column name; two or more tables have a column of the same name
    AmbiguousColumnName(Identifier),
    BadIdentifier(String),
    BadStringLiteral(String),
    BadNumberLiteral(String)
}

impl fmt::Display for QueryPlanCompileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::QueryPlanCompileError::*;

        match self {
            &TableDoesNotExist(ref name) => {
                write!(f, "table does not exist: {}", name)
            },
            &AmbiguousColumnName(ref name) => {
                write!(f, "ambiguous column name: {}", name)
            },
            &BadIdentifier(ref name) => {
                write!(f, "bad identifier: {}", name)
            },
            &BadStringLiteral(ref s) => {
                write!(f, "bad string literal: {}", s)
            },
            &BadNumberLiteral(ref s) => {
                write!(f, "bad number literal: {}", s)
            },
        }
    }
}

pub struct QueryPlan<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    pub expr: SExpression<'a, DB>,
    pub out_column_names: ColumnNames
}

fn new_identifier(value: &str) -> Result<Identifier, QueryPlanCompileError> {
    Identifier::new(value).ok_or(QueryPlanCompileError::BadIdentifier(value.to_string()))
}

impl<'a, DB: DatabaseInfo> QueryPlan<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    pub fn compile_select(db: &'a DB, stmt: ast::SelectStatement)
    -> Result<QueryPlan<'a, DB>, QueryPlanCompileError>
    {
        let scope = SourceScope {
            parent: None,
            tables: Vec::new(),
            table_aliases: Vec::new()
        };

        let mut source_id: u32 = 0;

        let source_id_fn = || {
            let old_source_id = source_id;
            source_id += 1;
            old_source_id
        };

        let mut compiler = Compiler {
            db: db,
            new_source_id: source_id_fn
        };

        compiler.compile_select_recurse(stmt, &scope)
    }
}

struct Compiler<'a, DB: DatabaseInfo, F>
where DB: 'a, <DB as DatabaseInfo>::Table: 'a, F: FnMut() -> u32
{
    db: &'a DB,
    new_source_id: F
}

impl<'a, DB: DatabaseInfo, F> Compiler<'a, DB, F>
where DB: 'a, <DB as DatabaseInfo>::Table: 'a, F: FnMut() -> u32
{
    fn new_source_id(&mut self) -> u32 {
        (&mut self.new_source_id)()
    }

    fn compile_select_recurse<'b>(&mut self, stmt: ast::SelectStatement, scope: &'b SourceScope<'a, 'b, DB>)
    -> Result<QueryPlan<'a, DB>, QueryPlanCompileError>
    {
        // Unimplemented syntaxes: GROUP BY, HAVING, ORDER BY
        // TODO - implement them!
        if !stmt.group_by.is_empty() { unimplemented!() }
        if stmt.having.is_some() { unimplemented!() }
        if !stmt.order_by.is_empty() { unimplemented!() }

        let mut arbitrary_column_count = 0;

        let mut arbitrary_column_name = || {
            let s = format!("_{}", arbitrary_column_count);
            arbitrary_column_count += 1;

            Identifier::new(&s).unwrap()
        };

        // FROM and WHERE are compiled together.
        // This makes sense for INNER and OUTER joins, which also
        // contain ON (conditional) expressions.

        let (new_scope, where_expr) = try!(self.from_where(stmt.from, stmt.where_expr, scope));

        // prevent accidental use of the old scope
        drop(scope);

        // TODO: refactor this terrible mess.
        let (column_names, select_exprs) = {
            let mut a: Vec<_> = Vec::new();
            for c in stmt.result_columns {
                match c {
                    ast::SelectColumn::AllColumns => {
                        for (i, table) in new_scope.tables.iter().enumerate() {
                            match table {
                                &TableOrSubquery::Table { source_id, table} => {
                                    let it = table.get_column_names().into_iter().enumerate().map(|(i, name)| {
                                        (name, SExpression::ColumnField {
                                            source_id: source_id,
                                            column_offset: i as u32
                                        })
                                    });

                                    a.extend(it);
                                },
                                &TableOrSubquery::Subquery { source_id, ref out_column_names, .. } => {
                                    let it = out_column_names.iter().enumerate().map(|(i, name)| {
                                        (name.clone(), SExpression::ColumnField {
                                            source_id: source_id,
                                            column_offset: i as u32
                                        })
                                    });

                                    a.extend(it);
                                }
                            }
                        }
                    },
                    ast::SelectColumn::Expr { expr, alias } => {
                        let column_name = if let Some(alias) = alias {
                            try!(new_identifier(&alias))
                        } else {
                            // if the expression is a simple identifier, make that
                            // the column name. else, assign an arbitrary name.
                            if let &ast::Expression::Ident(ref n) = &expr {
                                try!(new_identifier(n))
                            } else {
                                arbitrary_column_name()
                            }
                        };

                        let e = try!(self.ast_expression_to_sexpression(expr, &new_scope));
                        a.push((column_name, e));
                    }
                }
            }

            let (column_names, select_exprs) = a.into_iter().unzip();

            (ColumnNames::new(column_names), select_exprs)
        };

        let core_expr = if let Some(where_expr) = where_expr {
            SExpression::If {
                predicate: Box::new(where_expr),
                yield_fn: Box::new(SExpression::Yield { fields: select_exprs })
            }
        } else {
            SExpression::Yield { fields: select_exprs }
        };

        // table references and source ids need to be known at this point
        let expr = new_scope.tables.into_iter().fold(core_expr, |nested_expr, x| {
            match x {
                TableOrSubquery::Subquery { source_id, expr, .. } => {
                    SExpression::Map {
                        source_id: source_id,
                        yield_in_fn: Box::new(expr),
                        yield_out_fn: Box::new(nested_expr)
                    }
                },
                TableOrSubquery::Table { source_id, table } => {
                    SExpression::Scan {
                        source_id: source_id,
                        table: table,
                        yield_fn: Box::new(nested_expr)
                    }
                }
            }
        });

        Ok(QueryPlan {
            expr: expr,
            out_column_names: column_names
        })
    }

    fn from_where<'b>(&mut self, from: ast::From, where_expr: Option<ast::Expression>, scope: &'b SourceScope<'a, 'b, DB>)
    -> Result<(SourceScope<'a, 'b, DB>, Option<SExpression<'a, DB>>), QueryPlanCompileError>
    {
        // TODO - avoid naive nested scans when indices are available

        // All FROM subqueries are nested, never correlated.
        let ast_cross_tables = match from {
            ast::From::Cross(v) => v,
            ast::From::Join {..} => unimplemented!()
        };

        let a: Vec<_> = try!(ast_cross_tables.into_iter().map(|ast_table_or_subquery| {
            match ast_table_or_subquery {
                ast::TableOrSubquery::Subquery { subquery, alias } => {
                    let plan = try!(self.compile_select_recurse(*subquery, scope));
                    let alias_identifier = try!(new_identifier(&alias));

                    let s = TableOrSubquery::Subquery {
                        source_id: self.new_source_id(),
                        expr: plan.expr,
                        out_column_names: plan.out_column_names
                    };

                    Ok((s, alias_identifier))
                },
                ast::TableOrSubquery::Table { table, alias } => {
                    let table_name_identifier = try!(new_identifier(&table.table_name));
                    let table = match self.db.find_table_by_name(&table_name_identifier) {
                        Some(table) => table,
                        None => return Err(QueryPlanCompileError::TableDoesNotExist(table_name_identifier))
                    };

                    let alias_identifier = if let Some(alias) = alias {
                        try!(new_identifier(&alias))
                    } else {
                        table_name_identifier
                    };

                    let s = TableOrSubquery::Table {
                        source_id: self.new_source_id(),
                        table: table
                    };

                    Ok((s, alias_identifier))
                }
            }
        }).collect());

        let (tables, table_aliases) = a.into_iter().unzip();

        let new_scope = SourceScope {
            parent: Some(scope),
            tables: tables,
            table_aliases: table_aliases
        };

        let where_expr = if let Some(where_expr) = where_expr {
            Some(try!(self.ast_expression_to_sexpression(where_expr, &new_scope)))
        } else {
            None
        };

        Ok((new_scope, where_expr))
    }

    fn ast_expression_to_sexpression<'b>(&mut self, ast: ast::Expression, scope: &'b SourceScope<'a, 'b, DB>)
    -> Result<SExpression<'a, DB>, QueryPlanCompileError>
    {
        use std::borrow::IntoCow;

        match ast {
            ast::Expression::Ident(s) => {
                let column_identifier = try!(new_identifier(&s));

                let (source_id, column_offset) = match scope.get_column_offset(&column_identifier) {
                    Some(v) => v,
                    None => return Err(QueryPlanCompileError::AmbiguousColumnName(column_identifier))
                };

                Ok(SExpression::ColumnField {
                    source_id: source_id,
                    column_offset: column_offset
                })
            },
            ast::Expression::IdentMember(s1, s2) => {
                let table_identifier = try!(new_identifier(&s1));
                let column_identifier = try!(new_identifier(&s2));

                let (source_id, column_offset) = match scope.get_table_column_offset(&table_identifier, &column_identifier) {
                    Some(v) => v,
                    None => return Err(QueryPlanCompileError::AmbiguousColumnName(column_identifier))
                };

                Ok(SExpression::ColumnField {
                    source_id: source_id,
                    column_offset: column_offset
                })
            },
            ast::Expression::BinaryOp { lhs, rhs, op } => {
                let l = try!(self.ast_expression_to_sexpression(*lhs, scope));
                let r = try!(self.ast_expression_to_sexpression(*rhs, scope));

                Ok(SExpression::BinaryOp {
                    op: ast_binaryop_to_sexpression_binaryop(op),
                    lhs: Box::new(l),
                    rhs: Box::new(r)
                })
            },
            ast::Expression::StringLiteral(s) => {
                match DB::ColumnValue::from_string_literal(s.into_cow()) {
                    Ok(value) => Ok(SExpression::Value(value)),
                    Err(s) => Err(QueryPlanCompileError::BadStringLiteral(s.into_owned()))
                }
            },
            ast::Expression::Number(s) => {
                match DB::ColumnValue::from_number_literal(s.into_cow()) {
                    Ok(value) => Ok(SExpression::Value(value)),
                    Err(s) => Err(QueryPlanCompileError::BadNumberLiteral(s.into_owned()))
                }
            },
            ast::Expression::Subquery(subquery) => {
                let source_id = self.new_source_id();

                let plan = try!(self.compile_select_recurse(*subquery, scope));

                Ok(SExpression::Map {
                    source_id: source_id,
                    yield_in_fn: Box::new(plan.expr),
                    yield_out_fn: Box::new(SExpression::ColumnField {
                        source_id: source_id,
                        column_offset: 0
                    })
                })
            }
            e => panic!("unimplemented: {:?}", e)
        }
    }
}

fn ast_binaryop_to_sexpression_binaryop(ast: ast::BinaryOp) -> BinaryOp {
    match ast {
        ast::BinaryOp::Equal => BinaryOp::Equal,
        ast::BinaryOp::NotEqual => BinaryOp::NotEqual,
        ast::BinaryOp::LessThan => BinaryOp::LessThan,
        ast::BinaryOp::LessThanOrEqual => BinaryOp::LessThanOrEqual,
        ast::BinaryOp::GreaterThan => BinaryOp::GreaterThan,
        ast::BinaryOp::GreaterThanOrEqual => BinaryOp::GreaterThanOrEqual,
        ast::BinaryOp::And => BinaryOp::And,
        ast::BinaryOp::Or => BinaryOp::Or,
        ast::BinaryOp::Add => BinaryOp::Add,
        ast::BinaryOp::Subtract => BinaryOp::Subtract,
        ast::BinaryOp::Multiply => BinaryOp::Multiply,
        ast::BinaryOp::BitAnd => BinaryOp::BitAnd,
        ast::BinaryOp::BitOr => BinaryOp::BitOr,
        ast::BinaryOp::Concatenate => BinaryOp::Concatenate,
    }
}

impl<'a, DB: DatabaseInfo> fmt::Display for QueryPlan<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let cn: Vec<_> = self.out_column_names.iter().map(|n| format!("`{}`", n)).collect();

        try!(writeln!(f, "query plan"));
        try!(writeln!(f, "column names: ({})", cn.connect(", ")));
        self.expr.fmt(f)
    }
}
<|endoftext|>


<commit_before>mod samplers;
mod utils;
mod filters;
mod config;

use std::fmt;

use color::Color;
use datastructures::Matrix;
use geom::{UnitVector, Dot};
use scene::{Intersection, Scene, Texture};
use utils::time_it;
use self::filters::Filter;
use self::samplers::{Sampler, StratifiedSampler};

pub use self::config::TracerConfig;

pub type Pixel = [u32; 2];

pub type Image = Matrix<Color>;

pub struct TracingStats {
    pub rendering_time: f64,
    pub filtering_time: f64
}

impl fmt::Display for TracingStats {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "Rendering:   {:.2}s\nFiltering:   {:.2}s",
               self.rendering_time, self.filtering_time)
    }

}

pub struct Tracer<'a> {
    scene: &'a Scene,
    sampler: Box<Sampler>,
    filter: Box<Filter>,
}

impl<'a> Tracer<'a> {
    pub fn new(scene: &Scene, config: TracerConfig) -> Tracer {
        Tracer {
            scene: scene,
            sampler: Box::new(StratifiedSampler::new(config.resolution, config.sampler)),
            filter: Box::new(Filter::new(config.resolution, config.filter))
        }
    }

    pub fn render(&self) -> (Image, TracingStats) {

        let (samples, rendering_time) = time_it(|| {
            self.sampler.sample()
            .into_iter()
            .map(|s| {
                let ray = self.scene.camera.cast_ray(s.pixel);
                let radiance = match self.scene.find_obstacle(&ray) {
                    Some(ref intersection) => self.colorize(ray.direction, intersection),
                    None => self.scene.background_color
                };
                (s, radiance)
            }).collect()
        });

        let (image, filtering_time) = time_it(|| self.filter.apply(&samples));
        (image, TracingStats {rendering_time: rendering_time,
                              filtering_time: filtering_time})
    }

    fn colorize(&self, view_direction: UnitVector, intersection: &Intersection) -> Color {
        let mut result = intersection.colorize_ambient(self.scene.ambient_light);
        let visible_lights = self.scene.lights.iter()
            .filter(|&light| self.scene.is_visible(light.position(), &intersection));

        for light in visible_lights {
            let light_direction = light.position().direction_to(intersection.geom.point);
            let illumination = light.illuminate(intersection.geom.point);
            result = result
                + intersection.colorize_diffuse(illumination, light_direction)
                + intersection.colorize_specular(illumination, light_direction, view_direction);
        }
        result
    }
}

trait IntersectionExt {
    fn colorize_ambient(&self, illumination: Color) -> Color;

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color;

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color;
}

impl<'a> IntersectionExt for Intersection<'a> {
    fn colorize_ambient(&self, illumination: Color) -> Color {
        self.primitive.material.color.at(&self.geom) * illumination
    }

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color {

        let k = (-light_direction.dot(self.geom.normal)).max(0.0) * self.primitive.material.diffuse;
        self.primitive.material.color.at(&self.geom) * illumination * k
    }

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color {

        let r = light_direction.reflect(self.geom.normal);
        let k = (-r.dot(view_direction)).max(0.0).powf(self.primitive.material.specular);
        illumination * k
    }
}
<commit_msg>minor refactor<commit_after>mod samplers;
mod utils;
mod filters;
mod config;

use std::fmt;

use color::Color;
use datastructures::Matrix;
use geom::{UnitVector, Dot};
use geom::ray::Ray;
use scene::{Intersection, Scene, Texture};
use utils::time_it;
use self::filters::Filter;
use self::samplers::{Sampler, StratifiedSampler};

pub use self::config::TracerConfig;

pub type Pixel = [u32; 2];

pub type Image = Matrix<Color>;

pub struct TracingStats {
    pub rendering_time: f64,
    pub filtering_time: f64
}

impl fmt::Display for TracingStats {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "Rendering:   {:.2}s\nFiltering:   {:.2}s",
               self.rendering_time, self.filtering_time)
    }

}

pub struct Tracer<'a> {
    scene: &'a Scene,
    sampler: Box<Sampler>,
    filter: Box<Filter>,
}

impl<'a> Tracer<'a> {
    pub fn new(scene: &Scene, config: TracerConfig) -> Tracer {
        Tracer {
            scene: scene,
            sampler: Box::new(StratifiedSampler::new(config.resolution, config.sampler)),
            filter: Box::new(Filter::new(config.resolution, config.filter))
        }
    }

    pub fn render(&self) -> (Image, TracingStats) {

        let (samples, rendering_time) = time_it(|| {
            self.sampler.sample()
            .into_iter()
            .map(|s| {
                let ray = self.scene.camera.cast_ray(s.pixel);
                (s, self.radiace(&ray))
            }).collect()
        });

        let (image, filtering_time) = time_it(|| self.filter.apply(&samples));
        (image, TracingStats {rendering_time: rendering_time,
                              filtering_time: filtering_time})
    }

    pub fn radiace(&self, ray: &Ray) -> Color {
        match self.scene.find_obstacle(ray) {
            Some(ref intersection) => self.colorize(ray.direction, intersection),
            None => self.scene.background_color
        }
    }

    fn colorize(&self, view_direction: UnitVector, intersection: &Intersection) -> Color {
        let mut result = intersection.colorize_ambient(self.scene.ambient_light);
        let visible_lights = self.scene.lights.iter()
            .filter(|&light| self.scene.is_visible(light.position(), &intersection));

        for light in visible_lights {
            let light_direction = light.position().direction_to(intersection.geom.point);
            let illumination = light.illuminate(intersection.geom.point);
            result = result
                + intersection.colorize_diffuse(illumination, light_direction)
                + intersection.colorize_specular(illumination, light_direction, view_direction);
        }
        result
    }
}

trait IntersectionExt {
    fn colorize_ambient(&self, illumination: Color) -> Color;

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color;

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color;
}

impl<'a> IntersectionExt for Intersection<'a> {
    fn colorize_ambient(&self, illumination: Color) -> Color {
        self.primitive.material.color.at(&self.geom) * illumination
    }

    fn colorize_diffuse(&self,
                        illumination: Color,
                        light_direction: UnitVector)
                        -> Color {

        let k = (-light_direction.dot(self.geom.normal)).max(0.0) * self.primitive.material.diffuse;
        self.primitive.material.color.at(&self.geom) * illumination * k
    }

    fn colorize_specular(&self,
                         illumination: Color,
                         light_direction: UnitVector,
                         view_direction: UnitVector)
                         -> Color {

        let r = light_direction.reflect(self.geom.normal);
        let k = (-r.dot(view_direction)).max(0.0).powf(self.primitive.material.specular);
        illumination * k
    }
}
<|endoftext|>


<commit_before>use super::*;
use std::collections::HashMap;
use rand;
use core::geometry;
use backend::obj;
use backend::obj::Transformable;
use backend::obj::Identified;
use backend::world;
use backend::world::gen;
use backend::world::agent;
use backend::world::segment;
use backend::world::WorldState;
use backend::world::alert;
use backend::world::AlertReceiver;
use serialize::base64::{self, ToBase64};

type StateMap = HashMap<obj::Id, agent::State>;
type GeneMap = HashMap<obj::Id, gen::Dna>;

pub struct AlifeSystem {
	dt: Seconds,
	source: Box<[world::Emitter]>,
	eaten: StateMap,
	touched: GeneMap,
}

impl Updateable for AlifeSystem {
	fn update(&mut self, _: &WorldState, dt: Seconds) {
		self.dt = dt;
	}
}

impl System for AlifeSystem {
	fn get_from_world(&mut self, world: &world::World) {
		self.source = world.emitters().to_vec().into_boxed_slice();
		self.eaten = Self::find_eaten_resources(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Resource),
		);
		self.touched = Self::find_touched_spores(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Spore),
		);
	}

	fn put_to_world(&self, world: &mut world::World) {
		Self::update_resources(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Resource),
			&self.eaten,
		);

		let (spores, corpses) = Self::update_minions(
			self.dt,
			&world.extent.clone(),
			&mut world.agents_mut(agent::AgentType::Minion),
			&self.eaten,
		);
		let (hatch, fertilised) = Self::update_spores(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Spore),
			&self.touched,
		);

		for &(ref transform, ref dna) in spores.into_iter() {
			world.alert(alert::Alert::NewSpore);
			world.new_spore(transform, dna);
		}
		for &(ref transform, ref dna) in hatch.into_iter() {
			world.alert(alert::Alert::NewMinion);
			world.hatch_spore(transform, dna);
		}
		for &(ref transform, ref dna) in corpses.into_iter() {
			world.alert(alert::Alert::DieMinion);
			world.decay_to_resource(transform, dna);
		}
		for _ in 0..fertilised {
			world.alert(alert::Alert::Fertilised);
		}
	}
}

impl Default for AlifeSystem {
	fn default() -> Self {
		AlifeSystem {
			dt: Seconds::new(1. / 60.),
			source: Box::new([]),
			eaten: StateMap::new(),
			touched: GeneMap::new(),
		}
	}
}

impl AlifeSystem {
	fn find_eaten_resources(minions: &agent::AgentMap, resources: &agent::AgentMap) -> StateMap {
		let mut eaten = HashMap::new();
		for (_, agent) in minions.iter().filter(|&(_, a)| a.state.is_active()) {
			for segment in agent.segments.iter().filter(|&s| {
				s.flags.contains(segment::Flags::MOUTH)
			})
				{
					if let Some(key) = segment.state.last_touched {
						if let Some(&agent::Agent { ref state, .. }) = resources.get(&key.id()) {
							eaten.insert(key.id(), (*state).clone());
						}
					}
				}
		}
		eaten
	}

	fn find_touched_spores(minions: &agent::AgentMap, spores: &agent::AgentMap) -> GeneMap {
		let mut touched = HashMap::new();
		for (_, spore) in spores.iter().filter(|&(_, a)| {
			a.state.is_active() && !a.state.is_fertilised()
		})
			{
				for segment in spore.segments.iter() {
					if let Some(key) = segment.state.last_touched {
						if let Some(ref agent) = minions.get(&key.id()) {
							if agent.gender() != spore.gender() {
								touched.insert(key.id(), agent.dna().clone());
							}
						}
					}
				}
			}
		touched
	}

	fn update_minions(dt: Seconds, extent: &geometry::Rect, minions: &mut agent::AgentMap, eaten: &StateMap)
					  -> (Box<[(geometry::Transform, gen::Dna)]>, Box<[(geometry::Transform, gen::Dna)]>) {
		let mut spawns = Vec::new();
		let mut corpses = Vec::new();
		for (_, agent) in minions.iter_mut() {
			if agent.state.is_active() {
				if agent.state.lifecycle().is_expired() && agent.state.consume_ratio(0.75) {
					spawns.push((
						agent.last_segment().transform().clone(),
						agent.dna().clone(),
					));
					agent.state.renew();
				}
				for segment in agent.segments.iter_mut() {
					let p = segment.transform().position;
					if p.x < extent.min.x || p.x > extent.max.x || p.y < extent.min.y || p.y > extent.max.y {
						agent.state.die();
					}
					if segment.flags.contains(segment::Flags::MOUTH) {
						if let Some(id) = segment.state.last_touched {
							if let Some(eaten_state) = eaten.get(&id.id()) {
								agent.state.absorb(eaten_state.energy());
							}
						}
					}
					agent.state.consume(
						dt.get() as f32 * segment.state.get_charge() * segment.mesh.shape.radius(),
					);
					segment.state.update(dt);
				}

				if agent.state.energy() < 1. {
					for segment in agent.segments.iter() {
						corpses.push((segment.transform.clone(), agent.dna().clone()));
					}
					agent.state.die();
				}

				if let Some(segment) = agent.first_segment(segment::Flags::TRACKER) {
					agent.state.track_position(&segment.transform.position);
				}
			}
		}
		(spawns.into_boxed_slice(), corpses.into_boxed_slice())
	}

	fn update_resources(dt: Seconds, resources: &mut agent::AgentMap, eaten: &StateMap) {
		for (_, agent) in resources.iter_mut() {
			if eaten.get(&agent.id()).is_some() {
				agent.state.die();
			} else if agent.state.energy() <= 0. {
				agent.state.die();
			} else if agent.state.lifecycle().is_expired() {
				agent.state.die();
			} else if agent.state.is_active() {
				for segment in agent.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
	}

	fn crossover(dna: &gen::Dna, foreign_dna: &Option<gen::Dna>) -> gen::Dna {
		match foreign_dna {
			&Some(ref foreign) => {
				gen::Genome::new(&foreign)
					.crossover(&mut rand::thread_rng(), dna)
					.dna()
					.clone()
			}
			&None => dna.clone(),
		}
	}

	fn update_spores(dt: Seconds, spores: &mut agent::AgentMap, touched: &GeneMap)
					 -> (Box<[(geometry::Transform, gen::Dna)]>, usize) {
		let mut spawns = Vec::new();
		let mut fertilise_count = 0usize;
		for (spore_id, spore) in spores.iter_mut() {
			if spore.state.lifecycle().is_expired() {
				spore.state.die();
				spawns.push((
					spore.transform().clone(),
					Self::crossover(spore.dna(), spore.state.foreign_dna()),
				))
			} else if spore.state.is_active() {
				for segment in spore.segments.iter_mut() {
					if let Some(key) = segment.state.last_touched {
						if let Some(touched_dna) = touched.get(&key.id()) {
							info!(
								"fertilised: {} by {} as {}",
								spore_id,
								key.id(),
								touched_dna.to_base64(base64::STANDARD)
							);
							fertilise_count += 1;
							spore.state.fertilise(touched_dna);
						}
					}
				}
				for segment in spore.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
		(spawns.into_boxed_slice(), fertilise_count)
	}
}
<commit_msg>Alert for minion death only gets triggered once per minion<commit_after>use super::*;
use std::collections::HashMap;
use rand;
use core::geometry;
use backend::obj;
use backend::obj::Transformable;
use backend::obj::Identified;
use backend::world;
use backend::world::gen;
use backend::world::agent;
use backend::world::segment;
use backend::world::WorldState;
use backend::world::alert;
use backend::world::AlertReceiver;
use serialize::base64::{self, ToBase64};

type StateMap = HashMap<obj::Id, agent::State>;
type GeneMap = HashMap<obj::Id, gen::Dna>;

pub struct AlifeSystem {
	dt: Seconds,
	source: Box<[world::Emitter]>,
	eaten: StateMap,
	touched: GeneMap,
}

impl Updateable for AlifeSystem {
	fn update(&mut self, _: &WorldState, dt: Seconds) {
		self.dt = dt;
	}
}

impl System for AlifeSystem {
	fn get_from_world(&mut self, world: &world::World) {
		self.source = world.emitters().to_vec().into_boxed_slice();
		self.eaten = Self::find_eaten_resources(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Resource),
		);
		self.touched = Self::find_touched_spores(
			&world.agents(agent::AgentType::Minion),
			&world.agents(agent::AgentType::Spore),
		);
	}

	fn put_to_world(&self, world: &mut world::World) {
		Self::update_resources(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Resource),
			&self.eaten,
		);

		let (spores, corpses) = Self::update_minions(
			self.dt,
			&world.extent.clone(),
			&mut world.agents_mut(agent::AgentType::Minion),
			&self.eaten,
		);
		let (hatch, fertilised) = Self::update_spores(
			self.dt,
			&mut world.agents_mut(agent::AgentType::Spore),
			&self.touched,
		);

		for &(ref transform, ref dna) in spores.into_iter() {
			world.alert(alert::Alert::NewSpore);
			world.new_spore(transform, dna);
		}
		for &(ref transform, ref dna) in hatch.into_iter() {
			world.alert(alert::Alert::NewMinion);
			world.hatch_spore(transform, dna);
		}
		for &(ref transforms, ref dna) in corpses.into_iter() {
			world.alert(alert::Alert::DieMinion);
			for transform in transforms.iter() {
				world.decay_to_resource(transform, dna);
			}
		}
		for _ in 0..fertilised {
			world.alert(alert::Alert::Fertilised);
		}
	}
}

impl Default for AlifeSystem {
	fn default() -> Self {
		AlifeSystem {
			dt: Seconds::new(1. / 60.),
			source: Box::new([]),
			eaten: StateMap::new(),
			touched: GeneMap::new(),
		}
	}
}

impl AlifeSystem {
	fn find_eaten_resources(minions: &agent::AgentMap, resources: &agent::AgentMap) -> StateMap {
		let mut eaten = HashMap::new();
		for (_, agent) in minions.iter().filter(|&(_, a)| a.state.is_active()) {
			for segment in agent.segments.iter().filter(|&s| {
				s.flags.contains(segment::Flags::MOUTH)
			})
				{
					if let Some(key) = segment.state.last_touched {
						if let Some(&agent::Agent { ref state, .. }) = resources.get(&key.id()) {
							eaten.insert(key.id(), (*state).clone());
						}
					}
				}
		}
		eaten
	}

	fn find_touched_spores(minions: &agent::AgentMap, spores: &agent::AgentMap) -> GeneMap {
		let mut touched = HashMap::new();
		for (_, spore) in spores.iter().filter(|&(_, a)| {
			a.state.is_active() && !a.state.is_fertilised()
		})
			{
				for segment in spore.segments.iter() {
					if let Some(key) = segment.state.last_touched {
						if let Some(ref agent) = minions.get(&key.id()) {
							if agent.gender() != spore.gender() {
								touched.insert(key.id(), agent.dna().clone());
							}
						}
					}
				}
			}
		touched
	}

	fn update_minions(dt: Seconds, extent: &geometry::Rect, minions: &mut agent::AgentMap, eaten: &StateMap)
					  -> (Box<[(geometry::Transform, gen::Dna)]>,
						  Box<[(Box<[geometry::Transform]>, gen::Dna)]>,
					  ) {
		let mut spawns = Vec::new();
		let mut corpses = Vec::new();
		for (_, agent) in minions.iter_mut() {
			if agent.state.is_active() {
				if agent.state.lifecycle().is_expired() && agent.state.consume_ratio(0.75) {
					spawns.push((
						agent.last_segment().transform().clone(),
						agent.dna().clone(),
					));
					agent.state.renew();
				}
				for segment in agent.segments.iter_mut() {
					let p = segment.transform().position;
					if p.x < extent.min.x || p.x > extent.max.x || p.y < extent.min.y || p.y > extent.max.y {
						agent.state.die();
					}
					if segment.flags.contains(segment::Flags::MOUTH) {
						if let Some(id) = segment.state.last_touched {
							if let Some(eaten_state) = eaten.get(&id.id()) {
								agent.state.absorb(eaten_state.energy());
							}
						}
					}
					agent.state.consume(
						dt.get() as f32 * segment.state.get_charge() * segment.mesh.shape.radius(),
					);
					segment.state.update(dt);
				}

				if agent.state.energy() < 1. {
					let transforms = agent.segments.into_iter()
						.map(|segment| segment.transform.clone())
						.collect::<Vec<_>>();
					corpses.push((transforms.into_boxed_slice(), agent.dna().clone()));
					agent.state.die();
				}

				if let Some(segment) = agent.first_segment(segment::Flags::TRACKER) {
					agent.state.track_position(&segment.transform.position);
				}
			}
		}
		(spawns.into_boxed_slice(), corpses.into_boxed_slice())
	}

	fn update_resources(dt: Seconds, resources: &mut agent::AgentMap, eaten: &StateMap) {
		for (_, agent) in resources.iter_mut() {
			if eaten.get(&agent.id()).is_some() {
				agent.state.die();
			} else if agent.state.energy() <= 0. {
				agent.state.die();
			} else if agent.state.lifecycle().is_expired() {
				agent.state.die();
			} else if agent.state.is_active() {
				for segment in agent.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
	}

	fn crossover(dna: &gen::Dna, foreign_dna: &Option<gen::Dna>) -> gen::Dna {
		match foreign_dna {
			&Some(ref foreign) => {
				gen::Genome::new(&foreign)
					.crossover(&mut rand::thread_rng(), dna)
					.dna()
					.clone()
			}
			&None => dna.clone(),
		}
	}

	fn update_spores(dt: Seconds, spores: &mut agent::AgentMap, touched: &GeneMap)
					 -> (Box<[(geometry::Transform, gen::Dna)]>, usize) {
		let mut spawns = Vec::new();
		let mut fertilise_count = 0usize;
		for (spore_id, spore) in spores.iter_mut() {
			if spore.state.lifecycle().is_expired() {
				spore.state.die();
				spawns.push((
					spore.transform().clone(),
					Self::crossover(spore.dna(), spore.state.foreign_dna()),
				))
			} else if spore.state.is_active() {
				for segment in spore.segments.iter_mut() {
					if let Some(key) = segment.state.last_touched {
						if let Some(touched_dna) = touched.get(&key.id()) {
							info!(
								"fertilised: {} by {} as {}",
								spore_id,
								key.id(),
								touched_dna.to_base64(base64::STANDARD)
							);
							fertilise_count += 1;
							spore.state.fertilise(touched_dna);
						}
					}
				}
				for segment in spore.segments.iter_mut() {
					segment.state.update(dt)
				}
			}
		}
		(spawns.into_boxed_slice(), fertilise_count)
	}
}
<|endoftext|>


<commit_before>
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

pub enum ParseError {
    Eof(&'static str),
    NotFound(&'static str),
    Expected(Vec<u8>),
    ExpectedType(&'static str),
    Io(IoError),
    InvalidBodyChar(u8),
    LineTooLong(usize),
    TrailingInput(&'static str, usize),
    InternalError,
    Parse(&'static str, Box<ParseError>),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Eof(ref field) => write!(f, "{} while looking for \"{}\"",
                                                 self.description(), field),
            ParseError::NotFound(ref token) => write!(f, "\"{}\" {}",
                                                      token, self.description()),
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected \"{:?}\"",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            ParseError::Io(ref e) => write!(f, "{}: {}",
                                            self.description(), e),
            ParseError::InvalidBodyChar(ref c) => write!(f, "{}: {}",
                                                         self.description(), c),
            ParseError::LineTooLong(ref l) => write!(f, "Line {} is too long", l),
            ParseError::TrailingInput(ref field, ref c) => write!(
                f, "Trailing input at byte {} in {}", c, field),
            ParseError::Parse(ref field, ref inner) => write!(
                f, "{} {}: {}", self.description(), field, inner),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl fmt::Debug for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        <Self as fmt::Display>::fmt(self, f)
    }
}

impl StdError for ParseError {
    fn description(&self) -> &str
    {
        match *self {
            ParseError::Eof(_) => "End of File",
            ParseError::NotFound(_) => "Not Found",
            ParseError::Expected(_) => "Expectation Failed",
            ParseError::ExpectedType(_) => "Expectation Failed",
            ParseError::Io(_) => "I/O Error",
            ParseError::InvalidBodyChar(_) => "Invalid Body Character",
            ParseError::LineTooLong(_) => "Line too long",
            ParseError::TrailingInput(_,_) => "Trailing input",
            ParseError::InternalError => "Internal error",
            ParseError::Parse(_,_) => "Unable to parse",
        }
    }

    fn cause(&self) -> Option<&StdError>
    {
        match *self {
            ParseError::Io(ref e) => Some(e),
            ParseError::Parse(_, ref e) => Some(e),
            _ => None,
        }
    }
}
<commit_msg>improved description of InvalidBodyChar error<commit_after>
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

pub enum ParseError {
    Eof(&'static str),
    NotFound(&'static str),
    Expected(Vec<u8>),
    ExpectedType(&'static str),
    Io(IoError),
    InvalidBodyChar(u8),
    LineTooLong(usize),
    TrailingInput(&'static str, usize),
    InternalError,
    Parse(&'static str, Box<ParseError>),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Eof(ref field) => write!(f, "{} while looking for \"{}\"",
                                                 self.description(), field),
            ParseError::NotFound(ref token) => write!(f, "\"{}\" {}",
                                                      token, self.description()),
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected \"{:?}\"",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            ParseError::Io(ref e) => write!(f, "{}: {}",
                                            self.description(), e),
            ParseError::InvalidBodyChar(ref c) => write!(f, "{}: {} is not 7-bit ASCII",
                                                         self.description(), c),
            ParseError::LineTooLong(ref l) => write!(f, "Line {} is too long", l),
            ParseError::TrailingInput(ref field, ref c) => write!(
                f, "Trailing input at byte {} in {}", c, field),
            ParseError::Parse(ref field, ref inner) => write!(
                f, "{} {}: {}", self.description(), field, inner),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl fmt::Debug for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        <Self as fmt::Display>::fmt(self, f)
    }
}

impl StdError for ParseError {
    fn description(&self) -> &str
    {
        match *self {
            ParseError::Eof(_) => "End of File",
            ParseError::NotFound(_) => "Not Found",
            ParseError::Expected(_) => "Expectation Failed",
            ParseError::ExpectedType(_) => "Expectation Failed",
            ParseError::Io(_) => "I/O Error",
            ParseError::InvalidBodyChar(_) => "Invalid Body Character",
            ParseError::LineTooLong(_) => "Line too long",
            ParseError::TrailingInput(_,_) => "Trailing input",
            ParseError::InternalError => "Internal error",
            ParseError::Parse(_,_) => "Unable to parse",
        }
    }

    fn cause(&self) -> Option<&StdError>
    {
        match *self {
            ParseError::Io(ref e) => Some(e),
            ParseError::Parse(_, ref e) => Some(e),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate rusqlite;
#[macro_use]
extern crate log;
extern crate fern;

extern crate chrono;
extern crate rustc_serialize;
extern crate serde_yaml;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;
mod autoconf;
mod clap_actions;
mod actions_process;
mod actions_process_list_provides;
mod clap_fern;

use uuid::Uuid;

fn main() {
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    let actions = clap_actions::actions_get(&clap_matches);
    clap_fern::log_setup(&clap_matches);
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.hyphenated().to_string();
    trace!("session_uuid_string:{}", session_uuid_string);
    let conn = db::connect_deligate(&clap_matches);
    db::create_tables(&conn);
    loader::deligate(&conn, &actions, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
    actions_process::process(&conn, &actions)
}
<commit_msg>Apply rustfmt<commit_after>extern crate clap;
extern crate rusqlite;
#[macro_use]
extern crate log;
extern crate fern;
extern crate chrono;
extern crate rustc_serialize;
extern crate serde_yaml;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;
mod autoconf;
mod clap_actions;
mod actions_process;
mod actions_process_list_provides;
mod clap_fern;

use uuid::Uuid;

fn main() {
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    let actions = clap_actions::actions_get(&clap_matches);
    clap_fern::log_setup(&clap_matches);
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.hyphenated().to_string();
    trace!("session_uuid_string:{}", session_uuid_string);
    let conn = db::connect_deligate(&clap_matches);
    db::create_tables(&conn);
    loader::deligate(&conn, &actions, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
    actions_process::process(&conn, &actions)
}
<|endoftext|>


<commit_before>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CliError, CronError, CronErrorKind};
use lib::io::*;
use std::collections::BTreeSet;
use std::env;
use std::fmt::Display;
use std::io::Write;
use std::path::Path;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    upper  : String,
    my_area: String,
    lower  : String,
}

impl Cron {
    fn base_mark<D: Display>(keyword: &str, exec: D) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
{}"#,
            ME,
            keyword,
            exec,
        )
    }
    fn start_mark() -> String {
        Self::base_mark("from this", Self::patrol())
    }
    fn end_mark() -> String {
        Self::base_mark("up to here", "")
    }

    fn patrol() -> String {
        format!("0 0 * * *\t{} patrol\n", ME)
    }

    fn escape_asterisk<S: AsRef<str>>(s: S) -> String {
        let re = match Regex::new(r"\*") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake regular expression!!"),
        };
        re.replace_all(s.as_ref(), "\\*")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::InvalidCharacterCode)))
        } else {
            ""
        };

        let areas = format!(
            "^(?P<upper>(.|\n)*){}(?P<my_area>(.|\n)*){}(?P<lower>(.|\n)*)$",
            Self::escape_asterisk(Self::start_mark()),
            Self::end_mark(),
        );
        let re = match Regex::new(&areas) {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };

        let (upper, my_area, lower) = match re.captures(contents) {
            Some(caps) => match (caps.name("upper"), caps.name("my_area"), caps.name("lower")) {
                (Some(u), Some(m), Some(l)) => (u, m, l),
                _                           => unreachable!("Mistake regular expression!!"),
            },
            None => (contents, "", ""),
        };

        Ok(Cron { upper: upper.to_string(), my_area: my_area.to_string(), lower: lower.to_string() })
    }

    pub fn update(mut self, pairs: &[(&str, &str); 2]) -> Result<Self, CliError> {
        let current_dir = try!(Self::current_dir_string());
        self.delete(&current_dir);

        let my_new_area = pairs
            .iter()
            .fold(String::new(), |area, &(time, command)| {
                let line = format!("{}\tcd {} && {} {}\n", time, current_dir, ME, command);
                area + &line
            });

        self.my_area = self.my_area + &my_new_area;
        Ok(self)
    }

    fn re_for_matching_line<S: AsRef<str>>(core: S) -> String {
        format!(r".*cd\s+{}\s+&&\s+{}.*\n", core.as_ref(), ME)
    }

    pub fn delete<S: AsRef<str>>(&mut self, dir: S) {
        let re = Self::re_for_matching_line(dir);
        let re = match Regex::new(re.as_ref()) {
            Ok(re) => re,
            Err(_) => unreachable!("Wrong to use delete()!!"),
        };
        self.my_area = re.replace_all(&self.my_area, "");
    }

    pub fn discard(mut self) -> Result<Self, RegexError> {
        let re = Self::re_for_matching_line(r"(?P<path>[^\s]+)");
        let target_paths = try!(Regex::new(re.as_ref()))
            .captures_iter(&self.my_area)
            .map(|caps| match caps.name("path") {
                Some(p) => p.to_string(),
                None    => unreachable!("Mistake regular expression!!"),
            })
            .filter(|path| !Path::new(path).is_dir())
            .collect::<BTreeSet<String>>();
        if target_paths.len() == 0 {
            return Ok(self);
        }

        let re_core = target_paths
            .iter()
            .fold(String::new(), |core, path| core + "|" + path); // We want to use true "Iterator.reduce()".
        let re_core = re_core.trim_left_matches('|');
        let re = Self::re_for_matching_line(format!("({})", re_core));
        let re = try!(Regex::new(re.as_ref()));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(self)
    }

    pub fn set(self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        let contents = if self.my_area_is_empty() {
            self.upper + &self.lower
        } else {
            self.upper
                + &Self::start_mark()
                + &self.my_area
                + &Self::end_mark()
                + &self.lower
        };
        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(contents.as_bytes())),
            &mut None                => unreachable!("Please set Stdio::piped()!!"),
        };

        let output = try!(child.wait_with_output());
        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }

    pub fn current_dir_string() -> Result<String, CronError> {
        let current_dir = match env::current_dir() {
            Ok(d)  => d,
            Err(_) => unreachable!("There is a problem for current directory!!"),
        };
        current_dir
            .to_str()
            .ok_or(CronError::new(CronErrorKind::InvalidPath))
            .map(|s| s.to_string())
    }

    fn my_area_is_empty(&self) -> bool {
        let re = match Regex::new(r"^\s*$") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };
        re.is_match(self.my_area.as_ref())
    }
}

#[test]
fn my_area_is_empty_should_return_true() {
    let empties = [
        "",
        " ",
        "\t",
        "\r",
        "\n",
        " \t\r\n",
    ];

    for empty in &empties {
        let cron = Cron {
            upper: ""     .to_string(),
            my_area: empty.to_string(),
            lower: ""     .to_string(),
        };
        assert!(cron.my_area_is_empty());
    }
}
#[test]
fn my_area_is_empty_should_return_false() {
    let non_empties = [
        "a",
        "ab",
        " ab",
        "a b",
        "ab ",
        "\tab",
        "a\tb",
        "ab\t",
        "\rab",
        "a\rb",
        "ab\r",
        "\nab",
        "a\nb",
        "ab\n",
        " \t\r\nab",
        "a \t\r\nb",
        "ab \t\r\n",
    ];

    for non_empty in &non_empties {
        let cron = Cron {
            upper  : ""       .to_string(),
            my_area: non_empty.to_string(),
            lower  : ""       .to_string(),
        };
        assert!(!cron.my_area_is_empty());
    }
}

#[test]
fn delete_should_success() {
    fn wrap_by_extra_content<S: AsRef<str>>(target: S) -> String {
        let extra_content = "when cd path_to_extra && kic command\n";
        format!("{}{}{}", extra_content, target.as_ref(), extra_content)
    }

    let mut cron = Cron {
        upper  : "upper\n".to_string(),
        my_area: ""       .to_string(),
        lower  : "lower\n".to_string(),
    };

    let dir = "path_to_dir";

    let areas = vec![
        ("".to_string(), format!("cd {} && kic\n"             , dir)),
        ("".to_string(), format!("when cd {} && kic\n"        , dir)),
        ("".to_string(), format!("cd {} && kic command\n"     , dir)),
        ("".to_string(), format!("when cd {} && kic command\n", dir)),

        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic\n"             , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic\n"        , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic command\n"     , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic command\n", dir))),
    ];

    for (correct, area) in areas.into_iter() {
        cron.my_area = area;
        cron.delete(&dir);
        assert_eq!(correct, cron.my_area);
    }
}
#[test]
#[should_panic(expect = "entered unreachable code")]
fn delete_should_fail() {
    let mut cron = Cron {
        upper  : "upper\n".to_string(),
        my_area: ""       .to_string(),
        lower  : "lower\n".to_string(),
    };

    cron.delete("() <= mistaken Regular Expression!");
}
<commit_msg>[Test] Create tests for Cron.discard()<commit_after>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CliError, CronError, CronErrorKind};
use lib::io::*;
use std::collections::BTreeSet;
use std::env;
use std::fmt::Display;
use std::io::Write;
use std::path::Path;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    upper  : String,
    my_area: String,
    lower  : String,
}

impl Cron {
    fn base_mark<D: Display>(keyword: &str, exec: D) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
{}"#,
            ME,
            keyword,
            exec,
        )
    }
    fn start_mark() -> String {
        Self::base_mark("from this", Self::patrol())
    }
    fn end_mark() -> String {
        Self::base_mark("up to here", "")
    }

    fn patrol() -> String {
        format!("0 0 * * *\t{} patrol\n", ME)
    }

    fn escape_asterisk<S: AsRef<str>>(s: S) -> String {
        let re = match Regex::new(r"\*") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake regular expression!!"),
        };
        re.replace_all(s.as_ref(), "\\*")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::InvalidCharacterCode)))
        } else {
            ""
        };

        let areas = format!(
            "^(?P<upper>(.|\n)*){}(?P<my_area>(.|\n)*){}(?P<lower>(.|\n)*)$",
            Self::escape_asterisk(Self::start_mark()),
            Self::end_mark(),
        );
        let re = match Regex::new(&areas) {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };

        let (upper, my_area, lower) = match re.captures(contents) {
            Some(caps) => match (caps.name("upper"), caps.name("my_area"), caps.name("lower")) {
                (Some(u), Some(m), Some(l)) => (u, m, l),
                _                           => unreachable!("Mistake regular expression!!"),
            },
            None => (contents, "", ""),
        };

        Ok(Cron { upper: upper.to_string(), my_area: my_area.to_string(), lower: lower.to_string() })
    }

    pub fn update(mut self, pairs: &[(&str, &str); 2]) -> Result<Self, CliError> {
        let current_dir = try!(Self::current_dir_string());
        self.delete(&current_dir);

        let my_new_area = pairs
            .iter()
            .fold(String::new(), |area, &(time, command)| {
                let line = format!("{}\tcd {} && {} {}\n", time, current_dir, ME, command);
                area + &line
            });

        self.my_area = self.my_area + &my_new_area;
        Ok(self)
    }

    fn re_for_matching_line<S: AsRef<str>>(core: S) -> String {
        format!(r".*cd\s+{}\s+&&\s+{}.*\n", core.as_ref(), ME)
    }

    pub fn delete<S: AsRef<str>>(&mut self, dir: S) {
        let re = Self::re_for_matching_line(dir);
        let re = match Regex::new(re.as_ref()) {
            Ok(re) => re,
            Err(_) => unreachable!("Wrong to use delete()!!"),
        };
        self.my_area = re.replace_all(&self.my_area, "");
    }

    pub fn discard(mut self) -> Result<Self, RegexError> {
        let re = Self::re_for_matching_line(r"(?P<path>[^\s]+)");
        let target_paths = try!(Regex::new(re.as_ref()))
            .captures_iter(&self.my_area)
            .map(|caps| match caps.name("path") {
                Some(p) => p.to_string(),
                None    => unreachable!("Mistake regular expression!!"),
            })
            .filter(|path| !Path::new(path).is_dir())
            .collect::<BTreeSet<String>>();
        if target_paths.len() == 0 {
            return Ok(self);
        }

        let re_core = target_paths
            .iter()
            .fold(String::new(), |core, path| core + "|" + path); // We want to use true "Iterator.reduce()".
        let re_core = re_core.trim_left_matches('|');
        let re = Self::re_for_matching_line(format!("({})", re_core));
        let re = try!(Regex::new(re.as_ref()));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(self)
    }

    pub fn set(self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        let contents = if self.my_area_is_empty() {
            self.upper + &self.lower
        } else {
            self.upper
                + &Self::start_mark()
                + &self.my_area
                + &Self::end_mark()
                + &self.lower
        };
        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(contents.as_bytes())),
            &mut None                => unreachable!("Please set Stdio::piped()!!"),
        };

        let output = try!(child.wait_with_output());
        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }

    pub fn current_dir_string() -> Result<String, CronError> {
        let current_dir = match env::current_dir() {
            Ok(d)  => d,
            Err(_) => unreachable!("There is a problem for current directory!!"),
        };
        current_dir
            .to_str()
            .ok_or(CronError::new(CronErrorKind::InvalidPath))
            .map(|s| s.to_string())
    }

    fn my_area_is_empty(&self) -> bool {
        let re = match Regex::new(r"^\s*$") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };
        re.is_match(self.my_area.as_ref())
    }
}

#[test]
fn my_area_is_empty_should_return_true() {
    let empties = [
        "",
        " ",
        "\t",
        "\r",
        "\n",
        " \t\r\n",
    ];

    for empty in &empties {
        let cron = Cron {
            upper: ""     .to_string(),
            my_area: empty.to_string(),
            lower: ""     .to_string(),
        };
        assert!(cron.my_area_is_empty());
    }
}
#[test]
fn my_area_is_empty_should_return_false() {
    let non_empties = [
        "a",
        "ab",
        " ab",
        "a b",
        "ab ",
        "\tab",
        "a\tb",
        "ab\t",
        "\rab",
        "a\rb",
        "ab\r",
        "\nab",
        "a\nb",
        "ab\n",
        " \t\r\nab",
        "a \t\r\nb",
        "ab \t\r\n",
    ];

    for non_empty in &non_empties {
        let cron = Cron {
            upper  : ""       .to_string(),
            my_area: non_empty.to_string(),
            lower  : ""       .to_string(),
        };
        assert!(!cron.my_area_is_empty());
    }
}

#[test]
fn delete_should_success() {
    fn wrap_by_extra_content<S: AsRef<str>>(target: S) -> String {
        let extra_content = "when cd path_to_extra && kic command\n";
        format!("{}{}{}", extra_content, target.as_ref(), extra_content)
    }

    let mut cron = Cron {
        upper  : "upper" .to_string(),
        my_area: "middle".to_string(),
        lower  : "lower" .to_string(),
    };

    let dir = "path_to_dir";

    let areas = vec![
        ("".to_string(), format!("cd {} && kic\n"             , dir)),
        ("".to_string(), format!("when cd {} && kic\n"        , dir)),
        ("".to_string(), format!("cd {} && kic command\n"     , dir)),
        ("".to_string(), format!("when cd {} && kic command\n", dir)),

        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic\n"             , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic\n"        , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic command\n"     , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic command\n", dir))),
    ];

    for (correct, area) in areas.into_iter() {
        cron.my_area = area;
        cron.delete(&dir);
        assert_eq!(correct, cron.my_area);
    }
}
#[test]
#[should_panic(expect = "entered unreachable code")]
fn delete_should_panic() {
    let mut cron = Cron {
        upper  : "upper" .to_string(),
        my_area: "middle".to_string(),
        lower  : "lower" .to_string(),
    };

    cron.delete("() <= mistaken Regular Expression!");
}

#[test]
fn discard_should_remove_lines_including_non_existing_dir() {
    let mut cron = Cron {
        upper  : "upper" .to_string(),
        my_area: "middle".to_string(),
        lower  : "lower" .to_string(),
    };

    cron.my_area = format!("
        cd /path/to/non/existing/dir && {} command
        cd /path/to/non/existing/dir && {} command2
        cd /path/to/really/non/existing/dir && {} command
        cd /path/to/really/non/existing/dir && {} command2
    ", ME, ME, ME, ME);

    let cron = cron.discard();
    assert!(cron.is_ok());
    assert!(cron.unwrap().my_area_is_empty());
}
#[test]
fn discard_should_return_regex_err() {
    let mut cron = Cron {
        upper  : "upper" .to_string(),
        my_area: "middle".to_string(),
        lower  : "lower" .to_string(),
    };

    cron.my_area = format!("
        cd /()/<=/mischief/by/bad/user && {} command
    ", ME);

    let cron = cron.discard();
    assert!(cron.is_err());
    match cron {
        Err(RegexError::Syntax(_)) => (),
        _                          => panic!("test failed!!!"),
    };
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
use stdx::format_to;

pub(crate) trait ShortLabel {
    fn short_label(&self) -> Option<String>;
}

impl ShortLabel for ast::Fn {
    fn short_label(&self) -> Option<String> {
        Some(crate::display::function_declaration(self))
    }
}

impl ShortLabel for ast::Struct {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "struct ")
    }
}

impl ShortLabel for ast::Union {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "union ")
    }
}

impl ShortLabel for ast::Enum {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "enum ")
    }
}

impl ShortLabel for ast::Trait {
    fn short_label(&self) -> Option<String> {
        if self.unsafe_token().is_some() {
            short_label_from_node(self, "unsafe trait ")
        } else {
            short_label_from_node(self, "trait ")
        }
    }
}

impl ShortLabel for ast::Module {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "mod ")
    }
}

impl ShortLabel for ast::SourceFile {
    fn short_label(&self) -> Option<String> {
        None
    }
}

impl ShortLabel for ast::TypeAlias {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "type ")
    }
}

impl ShortLabel for ast::Const {
    fn short_label(&self) -> Option<String> {
        match short_label_from_ty(self, self.ty(), "const ") {
            Some(buf) => {
                let mut new_buf = buf;
                let body = self.body().unwrap();
                format_to!(new_buf, " = {}", body.syntax());
                Some(new_buf)
            }
            None => None,
        }
    }
}

impl ShortLabel for ast::Static {
    fn short_label(&self) -> Option<String> {
        short_label_from_ty(self, self.ty(), "static ")
    }
}

impl ShortLabel for ast::RecordField {
    fn short_label(&self) -> Option<String> {
        short_label_from_ty(self, self.ty(), "")
    }
}

impl ShortLabel for ast::Variant {
    fn short_label(&self) -> Option<String> {
        Some(self.name()?.text().to_string())
    }
}

fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner,
{
    let mut buf = short_label_from_node(node, prefix)?;

    if let Some(type_ref) = ty {
        format_to!(buf, ": {}", type_ref.syntax());
    }

    Some(buf)
}

fn short_label_from_node<T>(node: &T, label: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner,
{
    let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default();
    buf.push_str(label);
    buf.push_str(node.name()?.text().as_str());
    Some(buf)
}
<commit_msg>Better codes<commit_after>//! FIXME: write short doc here

use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
use stdx::format_to;

pub(crate) trait ShortLabel {
    fn short_label(&self) -> Option<String>;
}

impl ShortLabel for ast::Fn {
    fn short_label(&self) -> Option<String> {
        Some(crate::display::function_declaration(self))
    }
}

impl ShortLabel for ast::Struct {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "struct ")
    }
}

impl ShortLabel for ast::Union {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "union ")
    }
}

impl ShortLabel for ast::Enum {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "enum ")
    }
}

impl ShortLabel for ast::Trait {
    fn short_label(&self) -> Option<String> {
        if self.unsafe_token().is_some() {
            short_label_from_node(self, "unsafe trait ")
        } else {
            short_label_from_node(self, "trait ")
        }
    }
}

impl ShortLabel for ast::Module {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "mod ")
    }
}

impl ShortLabel for ast::SourceFile {
    fn short_label(&self) -> Option<String> {
        None
    }
}

impl ShortLabel for ast::TypeAlias {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "type ")
    }
}

impl ShortLabel for ast::Const {
    fn short_label(&self) -> Option<String> {
        let mut new_buf = short_label_from_ty(self, self.ty(), "const ")?;
        if let Some(expr) = self.body() {
            format_to!(new_buf, " = {}", expr.syntax());
        }
        Some(new_buf)
    }
}

impl ShortLabel for ast::Static {
    fn short_label(&self) -> Option<String> {
        short_label_from_ty(self, self.ty(), "static ")
    }
}

impl ShortLabel for ast::RecordField {
    fn short_label(&self) -> Option<String> {
        short_label_from_ty(self, self.ty(), "")
    }
}

impl ShortLabel for ast::Variant {
    fn short_label(&self) -> Option<String> {
        Some(self.name()?.text().to_string())
    }
}

fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner,
{
    let mut buf = short_label_from_node(node, prefix)?;

    if let Some(type_ref) = ty {
        format_to!(buf, ": {}", type_ref.syntax());
    }

    Some(buf)
}

fn short_label_from_node<T>(node: &T, label: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner,
{
    let mut buf = node.visibility().map(|v| format!("{} ", v.syntax())).unwrap_or_default();
    buf.push_str(label);
    buf.push_str(node.name()?.text().as_str());
    Some(buf)
}
<|endoftext|>