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

use std::fmt;

mod execute;
mod sexpression;
mod source;
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),
    UnknownFunctionName(Identifier),
    AggregateFunctionRequiresOneArgument
}

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)
            },
            &UnknownFunctionName(ref s) => {
                write!(f, "unknown function name: {}", s)
            },
            &AggregateFunctionRequiresOneArgument => {
                write!(f, "aggregate function requires exactly one argument")
            },
        }
    }
}

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

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::new(None, Vec::new(), 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
}

struct FromWhere<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    tables: Vec<FromWhereTableOrSubquery<'a, DB>>,
    where_expr: Option<SExpression<'a, DB>>
}

enum FromWhereTableOrSubquery<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    Table {
        source_id: u32,
        table: &'a <DB as DatabaseInfo>::Table
    },
    Subquery {
        source_id: u32,
        expr: SExpression<'a, DB>
    }
}

impl<'a, DB: DatabaseInfo> FromWhere<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn evaluate(self, inner_expr: SExpression<'a, DB>) -> SExpression<'a, DB> {
        let core_expr = if let Some(where_expr) = self.where_expr {
            SExpression::If {
                predicate: Box::new(where_expr),
                yield_fn: Box::new(inner_expr)
            }
        } else {
            inner_expr
        };

        self.tables.into_iter().fold(core_expr, |nested_expr, x| {
            match x {
                FromWhereTableOrSubquery::Subquery { source_id, expr } => {
                    SExpression::Map {
                        source_id: source_id,
                        yield_in_fn: Box::new(expr),
                        yield_out_fn: Box::new(nested_expr)
                    }
                },
                FromWhereTableOrSubquery::Table { source_id, table } => {
                    SExpression::Scan {
                        source_id: source_id,
                        table: table,
                        yield_fn: Box::new(nested_expr)
                    }
                }
            }
        })
    }
}

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, outer_scope: &'b SourceScope<'b>)
    -> 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!() }

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

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

        let (column_names, select_exprs) = try!(self.select(stmt.result_columns, &new_scope));

        let expr = from_where.evaluate(SExpression::Yield { fields: select_exprs });

        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<'b>)
    -> Result<(SourceScope<'b>, FromWhere<'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 source_id = self.new_source_id();

                    let s = TableOrSubquery {
                        source_id: source_id,
                        out_column_names: plan.out_column_names
                    };

                    let t = FromWhereTableOrSubquery::Subquery {
                        source_id: source_id,
                        expr: plan.expr
                    };

                    Ok(((s, t), 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 source_id = self.new_source_id();

                    let s = TableOrSubquery {
                        source_id: source_id,
                        out_column_names: table.get_column_names()
                    };

                    let t = FromWhereTableOrSubquery::Table {
                        source_id: source_id,
                        table: table
                    };

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

        let (tables, table_aliases): (Vec<_>, _) = a.into_iter().unzip();

        let (source_tables, fromwhere_tables) = tables.into_iter().unzip();

        let new_scope = SourceScope::new(Some(scope), source_tables, 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, FromWhere {
            tables: fromwhere_tables,
            where_expr: where_expr
        }))
    }

    fn select<'b>(&mut self, result_columns: Vec<ast::SelectColumn>, scope: &'b SourceScope<'b>)
    -> Result<(Vec<Identifier>, Vec<SExpression<'a, DB>>), QueryPlanCompileError>
    {
        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()
        };

        let mut a: Vec<_> = Vec::new();

        for c in result_columns {
            match c {
                ast::SelectColumn::AllColumns => {
                    a.extend(scope.tables().iter().flat_map(|table| {
                        let source_id = table.source_id;

                        table.out_column_names.iter().enumerate().map(move |(i, name)| {
                            (name.clone(), SExpression::ColumnField {
                                source_id: source_id,
                                column_offset: i as u32
                            })
                        })
                    }));
                },
                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, &scope));
                    a.push((column_name, e));
                }
            }
        }

        Ok(a.into_iter().unzip())
    }

    fn ast_expression_to_sexpression<'b>(&mut self, ast: ast::Expression, scope: &'b SourceScope<'b>)
    -> 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
                    })
                })
            },
            ast::Expression::FunctionCall { name, arguments } => {
                let ident = try!(new_identifier(&name));

                macro_rules! aggregate {
                    ($op:expr) => (
                        if arguments.len() != 1 {
                            Err(QueryPlanCompileError::AggregateFunctionRequiresOneArgument)
                        } else {
                            let arg = arguments.into_iter().nth(0).unwrap();
                            let value = try!(self.ast_expression_to_sexpression(arg, scope));
                            let source_id = unimplemented!();
                            Ok(SExpression::AggregateOp {
                                op: $op,
                                source_id: source_id,
                                value: Box::new(value)
                            })
                        }
                    )
                }

                match &ident as &str {
                    "count" => aggregate!(AggregateOp::Count),
                    "avg" => aggregate!(AggregateOp::Avg),
                    _ => Err(QueryPlanCompileError::UnknownFunctionName(ident))
                }
            },
            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>Use incrementing source id variable inside Compiler, not callback<commit_after>use columnvalueops::ColumnValueOps;
use databaseinfo::{DatabaseInfo, TableInfo};
use identifier::Identifier;
use sqlsyntax::ast;

use std::fmt;

mod execute;
mod sexpression;
mod source;
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),
    UnknownFunctionName(Identifier),
    AggregateFunctionRequiresOneArgument
}

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)
            },
            &UnknownFunctionName(ref s) => {
                write!(f, "unknown function name: {}", s)
            },
            &AggregateFunctionRequiresOneArgument => {
                write!(f, "aggregate function requires exactly one argument")
            },
        }
    }
}

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

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::new(None, Vec::new(), Vec::new());

        let mut compiler = Compiler {
            db: db,
            next_source_id: 0
        };

        compiler.compile_select_recurse(stmt, &scope)
    }
}

struct Compiler<'a, DB: DatabaseInfo>
where DB: 'a, <DB as DatabaseInfo>::Table: 'a
{
    db: &'a DB,
    next_source_id: u32
}

struct FromWhere<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    tables: Vec<FromWhereTableOrSubquery<'a, DB>>,
    where_expr: Option<SExpression<'a, DB>>
}

enum FromWhereTableOrSubquery<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    Table {
        source_id: u32,
        table: &'a <DB as DatabaseInfo>::Table
    },
    Subquery {
        source_id: u32,
        expr: SExpression<'a, DB>
    }
}

impl<'a, DB: DatabaseInfo> FromWhere<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn evaluate(self, inner_expr: SExpression<'a, DB>) -> SExpression<'a, DB> {
        let core_expr = if let Some(where_expr) = self.where_expr {
            SExpression::If {
                predicate: Box::new(where_expr),
                yield_fn: Box::new(inner_expr)
            }
        } else {
            inner_expr
        };

        self.tables.into_iter().fold(core_expr, |nested_expr, x| {
            match x {
                FromWhereTableOrSubquery::Subquery { source_id, expr } => {
                    SExpression::Map {
                        source_id: source_id,
                        yield_in_fn: Box::new(expr),
                        yield_out_fn: Box::new(nested_expr)
                    }
                },
                FromWhereTableOrSubquery::Table { source_id, table } => {
                    SExpression::Scan {
                        source_id: source_id,
                        table: table,
                        yield_fn: Box::new(nested_expr)
                    }
                }
            }
        })
    }
}

impl<'a, DB: DatabaseInfo> Compiler<'a, DB>
where DB: 'a, <DB as DatabaseInfo>::Table: 'a
{
    fn new_source_id(&mut self) -> u32 {
        let old_source_id = self.next_source_id;
        self.next_source_id += 1;
        old_source_id
    }

    fn compile_select_recurse<'b>(&mut self, stmt: ast::SelectStatement, outer_scope: &'b SourceScope<'b>)
    -> 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!() }

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

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

        let (column_names, select_exprs) = try!(self.select(stmt.result_columns, &new_scope));

        let expr = from_where.evaluate(SExpression::Yield { fields: select_exprs });

        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<'b>)
    -> Result<(SourceScope<'b>, FromWhere<'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 source_id = self.new_source_id();

                    let s = TableOrSubquery {
                        source_id: source_id,
                        out_column_names: plan.out_column_names
                    };

                    let t = FromWhereTableOrSubquery::Subquery {
                        source_id: source_id,
                        expr: plan.expr
                    };

                    Ok(((s, t), 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 source_id = self.new_source_id();

                    let s = TableOrSubquery {
                        source_id: source_id,
                        out_column_names: table.get_column_names()
                    };

                    let t = FromWhereTableOrSubquery::Table {
                        source_id: source_id,
                        table: table
                    };

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

        let (tables, table_aliases): (Vec<_>, _) = a.into_iter().unzip();

        let (source_tables, fromwhere_tables) = tables.into_iter().unzip();

        let new_scope = SourceScope::new(Some(scope), source_tables, 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, FromWhere {
            tables: fromwhere_tables,
            where_expr: where_expr
        }))
    }

    fn select<'b>(&mut self, result_columns: Vec<ast::SelectColumn>, scope: &'b SourceScope<'b>)
    -> Result<(Vec<Identifier>, Vec<SExpression<'a, DB>>), QueryPlanCompileError>
    {
        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()
        };

        let mut a: Vec<_> = Vec::new();

        for c in result_columns {
            match c {
                ast::SelectColumn::AllColumns => {
                    a.extend(scope.tables().iter().flat_map(|table| {
                        let source_id = table.source_id;

                        table.out_column_names.iter().enumerate().map(move |(i, name)| {
                            (name.clone(), SExpression::ColumnField {
                                source_id: source_id,
                                column_offset: i as u32
                            })
                        })
                    }));
                },
                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, &scope));
                    a.push((column_name, e));
                }
            }
        }

        Ok(a.into_iter().unzip())
    }

    fn ast_expression_to_sexpression<'b>(&mut self, ast: ast::Expression, scope: &'b SourceScope<'b>)
    -> 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
                    })
                })
            },
            ast::Expression::FunctionCall { name, arguments } => {
                let ident = try!(new_identifier(&name));

                macro_rules! aggregate {
                    ($op:expr) => (
                        if arguments.len() != 1 {
                            Err(QueryPlanCompileError::AggregateFunctionRequiresOneArgument)
                        } else {
                            let arg = arguments.into_iter().nth(0).unwrap();
                            let value = try!(self.ast_expression_to_sexpression(arg, scope));
                            let source_id = unimplemented!();
                            Ok(SExpression::AggregateOp {
                                op: $op,
                                source_id: source_id,
                                value: Box::new(value)
                            })
                        }
                    )
                }

                match &ident as &str {
                    "count" => aggregate!(AggregateOp::Count),
                    "avg" => aggregate!(AggregateOp::Avg),
                    _ => Err(QueryPlanCompileError::UnknownFunctionName(ident))
                }
            },
            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>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;

use result::Result;
use error::AnnotationErrorKind as AEK;

use module_path::ModuleEntryPath;

pub trait Annotateable {

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    fn annotate(&self, store: &Store) -> Result<Annotation> {
        self.annotate_with_path_generator(store, DefaultAnnotationPathGenerator::new())
    }

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    ///
    /// The `pg` is a AnnotationPathGenerator object which is used to generate a StoreId
    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator) -> Result<Annotation>;

}

/// A AnnotationPathGenerator generates a unique path for the annotation to be generated.
pub trait AnnotationPathGenerator {
    fn generate_annotation_path(&self) -> Result<StoreId>;
}

/// The DefaultAnnotationPathGenerator generates unique StoreIds for Annotations, where the
/// collection the annotations are stored in is `/annotation/`.
pub struct DefaultAnnotationPathGenerator;

impl AnnotationPathGenerator for DefaultAnnotationPathGenerator {

    fn generate_annotation_path(&self) -> Result<StoreId> {
        let id = Uuid::new_v4();
        ModuleEntryPath::new(format!("{}", id)).map_err_into(AEK::StoreIdGenerationError)
    }

}

pub struct Annotation<'a>(FileLockEntry<'a>);

impl Annotateable for FileLockEntry {

    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator)
        -> Result<Annotation>
    {
    }
}
<commit_msg>Add impl Annotateable::annotate_with_path_generator() for FileLockEntry<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;

use result::Result;
use error::AnnotationErrorKind as AEK;

use module_path::ModuleEntryPath;

pub trait Annotateable {

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    fn annotate(&self, store: &Store) -> Result<Annotation> {
        self.annotate_with_path_generator(store, DefaultAnnotationPathGenerator::new())
    }

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    ///
    /// The `pg` is a AnnotationPathGenerator object which is used to generate a StoreId
    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator) -> Result<Annotation>;

}

/// A AnnotationPathGenerator generates a unique path for the annotation to be generated.
pub trait AnnotationPathGenerator {
    fn generate_annotation_path(&self) -> Result<StoreId>;
}

/// The DefaultAnnotationPathGenerator generates unique StoreIds for Annotations, where the
/// collection the annotations are stored in is `/annotation/`.
pub struct DefaultAnnotationPathGenerator;

impl AnnotationPathGenerator for DefaultAnnotationPathGenerator {

    fn generate_annotation_path(&self) -> Result<StoreId> {
        let id = Uuid::new_v4();
        ModuleEntryPath::new(format!("{}", id)).map_err_into(AEK::StoreIdGenerationError)
    }

}

pub struct Annotation<'a>(FileLockEntry<'a>);

impl Annotateable for FileLockEntry {

    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator)
        -> Result<Annotation>
    {
        pb.generate_annotation_path()
            .and_then(|id| store.create(id).map_err_into(AEK::StoreWriteError))
            .and_then(|mut fle| {
                self.add_internal_link(&mut fle)
                    .map_err_into(AEK::LinkingError)
                    .map(|_| fle)
            })
            .map(Annotation)
    }
}
<|endoftext|>


<commit_before>use super::step::{ StepInfo, Message };
use super::step::Step::*;
use data::{ Type, Value };
use connection::{ Connection, ConnectionMessage };
use session::ValueID;
use vec_map::VecMap;
use super::matchset::MatchSet;
use std::i64;

pub fn run(step: &StepInfo, downwards: &mut Connection, upwards: &mut Connection) -> bool {
    let mut cx = RunCx { downwards, upwards, state: State::new() };
    run_inner(step, &mut cx)
}

struct RunCx<'a> {
//    fields_below: &'a Fields,
    downwards: &'a mut Connection,
//    fields_above: &'a Fields,
    upwards: &'a mut Connection,

    state: State,
}

impl<'a> RunCx<'a> {
    fn test(&mut self, m: &MatchSet) -> bool {
        for opt in &m.options {
            let dn_match = if let Some(ref msg) = opt.lower {
                if let Ok(rx) = self.downwards.peek() {
                    message_test(msg, rx)
                } else { false }
            } else { true };

            let up_match = if let Some(ref msg) = opt.upper {
                if let Ok(rx) = self.upwards.peek() {
                    message_test(msg, rx)
                } else { false }
            } else { true };

            if dn_match && up_match {
                return true;
            }
        }
        false
    }

    fn send_lower(&mut self, msg: &Message) -> Result<(), ()> {
        let tx = msg.iter().zip(self.downwards.sends.iter()).map(|(oe, sends)| {
            match (oe, sends) {
                (&Some(ref e), true) => Some(e.eval_down(&mut |var| self.state.get(var).clone())),
                _ => None
            }
        }).collect();
        debug!("{:?} Send lower {:?}", ::std::thread::current().id(), tx);
        self.downwards.send(tx)
    }

    fn send_upper(&mut self, msg: &Message) -> Result<(), ()> {
        let tx = msg.iter().zip(self.upwards.sends.iter()).map(|(oe, sends)| {
            match (oe, sends) {
                (&Some(ref e), true) => Some(e.eval_down(&mut |var| self.state.get(var).clone())),
                _ => None
            }
        }).collect();
        debug!("{:?} Send upper {:?}", ::std::thread::current().id(), tx);
        self.upwards.send(tx)
    }
}

/// Map of register IDs to values
pub struct State {
    registers: VecMap<Value>,
}

impl State {
    pub fn new() -> State {
        State {
            registers: VecMap::new(),
        }
    }

    pub fn get(&self, reg: ValueID) -> &Value {
        debug!("get {}: {:?}", reg, self.registers.get(reg));
        &self.registers[reg]
    }

    pub fn set(&mut self, reg: ValueID, v: Value) -> bool {
        debug!("set {}: {:?}", reg, v);
        self.registers.insert(reg, v);
        true
    }

    pub fn take(&mut self, reg: ValueID) -> Value {
        self.registers.remove(reg).expect("value not set")
    }
}

fn message_test(msg: &Message, rx: &ConnectionMessage) -> bool {
    debug!("{:?} Test {:?} into {:?}", ::std::thread::current().id(), rx, msg);
    msg.iter().zip(rx.iter()).all(|(oe, ov)| {
        match (oe, ov) {
            (&None, &None) => true,
            (&Some(ref e), &Some(ref v)) => e.eval_up(&mut |_, _| true, v.clone()),
            _ => false,
        }
    })
}

fn message_match(cx: &mut RunCx, msg: &Message, rx: Result<ConnectionMessage, ()>) -> bool {
    if let Ok(rx) = rx {
        debug!("{:?} Rx {:?} into {:?}", ::std::thread::current().id(), rx, msg);
        msg.iter().zip(rx.into_iter()).all(|(oe, ov)| {
            match (oe, ov) {
                (&None, None) => true,
                (&Some(ref e), Some(ref v)) => e.eval_up(&mut |var, val| cx.state.set(var, val), v.clone()),
                _ => false,
            }
        })
    } else {
        false
    }
}

fn run_inner(step: &StepInfo, cx: &mut RunCx) -> bool {
    match step.step {
        Nop => true,
        Token(ref msg) => {
            cx.send_lower(msg).ok();

            let rx = cx.downwards.recv();
            message_match(cx, msg, rx)
        }
        TokenTop(ref msg, ref inner) => {
            let rx = cx.upwards.recv();
            if !message_match(cx, msg, rx) {
                return false;
            }

            if !run_inner(inner, cx) { return false; }

            cx.send_upper(msg).ok();
            true
        }
        Seq(ref steps) => {
            for step in steps {
                if !run_inner(step, cx) { return false; }
            }
            true
        }
        Repeat(ref count, ref inner) => {
            if step.dir.repeat_up_heuristic {
                debug!("repeat up");
                let mut c = 0;

                let count_type = count.get_type();
                let hi = match count_type {
                    Type::Integer(_, hi) => hi,
                    _ => { warn!("Loop count type is {:?} not int", count_type); i64::MAX }
                };

                while c < hi && cx.test(&inner.first) {
                    if !run_inner(inner, cx) { return false; }
                    c += 1;
                }

                debug!("Repeat end {}", c);
                count.eval_up(&mut |var, val| cx.state.set(var, val), Value::Integer(c))
            } else {
                debug!("repeat down");

                let c = match count.eval_down(&mut |var| cx.state.get(var).clone()) {
                    Value::Integer(i) => i,
                    other => panic!("Count evaluated to non-integer {:?}", other)
                };
                for _ in 0..c {
                    if !run_inner(inner, cx) { return false; }
                }
                true
            }
        }
        Foreach(count, ref assigns, ref inner) => {
            let mut lstate = assigns.iter().map(|&(id, ref expr)| {
                let dir = step.dir.mode_of(id);
                let d = if dir.down {
                    match expr.eval_down(&mut |var| cx.state.get(var).clone()) {
                        Value::Vector(v) => Some(v.into_iter()),
                        other => panic!("For loop argument must be a vector, found {}", other)
                    }
                } else { None };

                let u = if dir.up { Some(Vec::new()) } else { None };

                (id, d, u, expr)
            }).collect::<Vec<_>>();

            for _ in 0..count {
                for &mut (id, ref mut down, _, _) in &mut lstate {
                    if let Some(d) = down {
                        cx.state.set(id, d.next().expect("not enough elements in loop"));
                    }
                }

                if !run_inner(inner, cx) { return false; }

                for &mut (id, _, ref mut up, _) in &mut lstate {
                    if let Some(u) = up {
                        u.push(cx.state.take(id))
                    }
                }
            }

            for (_, _, up, expr) in lstate {
                if let Some(u) = up {
                    if !expr.eval_up(&mut |var, val| cx.state.set(var, val), Value::Vector(u)) { return false; }
                }
            }

            true
        }
        Alt(ref opts) => {
            if step.dir.repeat_up_heuristic {
                for &(ref vals, ref inner) in opts {
                    if cx.test(&inner.first) {
                        for &(ref l, ref r) in vals {
                            let v = l.eval_down(&mut |var| cx.state.get(var).clone());
                            r.eval_up(&mut |var, val| cx.state.set(var, val), v);
                        }

                        return run_inner(inner, cx);
                    }
                }
                false
            } else {
                debug!("alt dn");

                for &(ref vals, ref inner) in opts {
                    let matches = vals.iter().all(|&(ref l, ref r)| {
                        let v = r.eval_down(&mut |var| cx.state.get(var).clone());
                        l.eval_up(&mut |var, val| cx.state.set(var, val), v)
                    });

                    if matches {
                        return run_inner(inner, cx);
                    }
                }
                false
            }
        }
    }
}
<commit_msg>Split runtime variables into up/down sets<commit_after>use super::step::{ StepInfo, Message };
use super::step::Step::*;
use data::{ Type, Value };
use connection::{ Connection, ConnectionMessage };
use session::ValueID;
use vec_map::VecMap;
use super::matchset::MatchSet;
use std::i64;

pub fn run(step: &StepInfo, downwards: &mut Connection, upwards: &mut Connection) -> bool {
    let mut cx = RunCx { downwards, upwards, vars_down: State::new(), vars_up: State::new() };
    run_inner(step, &mut cx)
}

struct RunCx<'a> {
//    fields_below: &'a Fields,
    downwards: &'a mut Connection,
//    fields_above: &'a Fields,
    upwards: &'a mut Connection,

    vars_down: State,
    vars_up: State,
}

impl<'a> RunCx<'a> {
    fn test(&mut self, m: &MatchSet) -> bool {
        for opt in &m.options {
            let dn_match = if let Some(ref msg) = opt.lower {
                if let Ok(rx) = self.downwards.peek() {
                    message_test(msg, rx)
                } else { false }
            } else { true };

            let up_match = if let Some(ref msg) = opt.upper {
                if let Ok(rx) = self.upwards.peek() {
                    message_test(msg, rx)
                } else { false }
            } else { true };

            if dn_match && up_match {
                return true;
            }
        }
        false
    }

    fn send_lower(&mut self, msg: &Message) -> Result<(), ()> {
        let tx = msg.iter().zip(self.downwards.sends.iter()).map(|(oe, sends)| {
            match (oe, sends) {
                (&Some(ref e), true) => Some(e.eval_down(&mut |var| self.vars_down.get(var).clone())),
                _ => None
            }
        }).collect();
        debug!("{:?} Send lower {:?}", ::std::thread::current().id(), tx);
        self.downwards.send(tx)
    }

    fn send_upper(&mut self, msg: &Message) -> Result<(), ()> {
        let tx = msg.iter().zip(self.upwards.sends.iter()).map(|(oe, sends)| {
            match (oe, sends) {
                (&Some(ref e), true) => Some(e.eval_down(&mut |var| self.vars_up.get(var).clone())),
                _ => None
            }
        }).collect();
        debug!("{:?} Send upper {:?}", ::std::thread::current().id(), tx);
        self.upwards.send(tx)
    }
}

/// Map of register IDs to values
pub struct State {
    registers: VecMap<Value>,
}

impl State {
    pub fn new() -> State {
        State {
            registers: VecMap::new(),
        }
    }

    pub fn get(&self, reg: ValueID) -> &Value {
        debug!("get {}: {:?}", reg, self.registers.get(reg));
        &self.registers[reg]
    }

    pub fn set(&mut self, reg: ValueID, v: Value) -> bool {
        debug!("set {}: {:?}", reg, v);
        self.registers.insert(reg, v);
        true
    }

    pub fn take(&mut self, reg: ValueID) -> Value {
        self.registers.remove(reg).expect("value not set")
    }
}

fn message_test(msg: &Message, rx: &ConnectionMessage) -> bool {
    debug!("{:?} Test {:?} into {:?}", ::std::thread::current().id(), rx, msg);
    msg.iter().zip(rx.iter()).all(|(oe, ov)| {
        match (oe, ov) {
            (&None, &None) => true,
            (&Some(ref e), &Some(ref v)) => e.eval_up(&mut |_, _| true, v.clone()),
            _ => false,
        }
    })
}

fn message_match(state: &mut State, msg: &Message, rx: Result<ConnectionMessage, ()>) -> bool {
    if let Ok(rx) = rx {
        debug!("{:?} Rx {:?} into {:?}", ::std::thread::current().id(), rx, msg);
        msg.iter().zip(rx.into_iter()).all(|(oe, ov)| {
            match (oe, ov) {
                (&None, None) => true,
                (&Some(ref e), Some(ref v)) => e.eval_up(&mut |var, val| state.set(var, val), v.clone()),
                _ => false,
            }
        })
    } else {
        false
    }
}

fn run_inner(step: &StepInfo, cx: &mut RunCx) -> bool {
    match step.step {
        Nop => true,
        Token(ref msg) => {
            cx.send_lower(msg).ok();

            let rx = cx.downwards.recv();
            message_match(&mut cx.vars_up, msg, rx)
        }
        TokenTop(ref msg, ref inner) => {
            let rx = cx.upwards.recv();
            if !message_match(&mut cx.vars_down, msg, rx) {
                return false;
            }

            if !run_inner(inner, cx) { return false; }

            cx.send_upper(msg).ok();
            true
        }
        Seq(ref steps) => {
            for step in steps {
                if !run_inner(step, cx) { return false; }
            }
            true
        }
        Repeat(ref count, ref inner) => {
            if step.dir.repeat_up_heuristic {
                debug!("repeat up");
                let mut c = 0;

                let count_type = count.get_type();
                let hi = match count_type {
                    Type::Integer(_, hi) => hi,
                    _ => { warn!("Loop count type is {:?} not int", count_type); i64::MAX }
                };

                while c < hi && cx.test(&inner.first) {
                    if !run_inner(inner, cx) { return false; }
                    c += 1;
                }

                debug!("Repeat end {}", c);
                count.eval_up(&mut |var, val| cx.vars_up.set(var, val), Value::Integer(c))
            } else {
                debug!("repeat down");

                let c = match count.eval_down(&mut |var| cx.vars_down.get(var).clone()) {
                    Value::Integer(i) => i,
                    other => panic!("Count evaluated to non-integer {:?}", other)
                };
                for _ in 0..c {
                    if !run_inner(inner, cx) { return false; }
                }
                true
            }
        }
        Foreach(count, ref assigns, ref inner) => {
            let mut lstate = assigns.iter().map(|&(id, ref expr)| {
                let dir = step.dir.mode_of(id);
                let d = if dir.down {
                    match expr.eval_down(&mut |var| cx.vars_down.get(var).clone()) {
                        Value::Vector(v) => Some(v.into_iter()),
                        other => panic!("For loop argument must be a vector, found {}", other)
                    }
                } else { None };

                let u = if dir.up { Some(Vec::new()) } else { None };

                (id, d, u, expr)
            }).collect::<Vec<_>>();

            for _ in 0..count {
                for &mut (id, ref mut down, _, _) in &mut lstate {
                    if let Some(d) = down {
                        cx.vars_down.set(id, d.next().expect("not enough elements in loop"));
                    }
                }

                if !run_inner(inner, cx) { return false; }

                for &mut (id, _, ref mut up, _) in &mut lstate {
                    if let Some(u) = up {
                        u.push(cx.vars_up.take(id))
                    }
                }
            }

            for (_, _, up, expr) in lstate {
                if let Some(u) = up {
                    if !expr.eval_up(&mut |var, val| cx.vars_up.set(var, val), Value::Vector(u)) { return false; }
                }
            }

            true
        }
        Alt(ref opts) => {
            if step.dir.repeat_up_heuristic {
                for &(ref vals, ref inner) in opts {
                    if cx.test(&inner.first) {
                        for &(ref l, ref r) in vals {
                            let v = l.eval_down(&mut |var| cx.vars_up.get(var).clone());
                            r.eval_up(&mut |var, val| cx.vars_up.set(var, val), v);
                        }

                        return run_inner(inner, cx);
                    }
                }
                false
            } else {
                debug!("alt dn");

                for &(ref vals, ref inner) in opts {
                    let matches = vals.iter().all(|&(ref l, ref r)| {
                        let v = r.eval_down(&mut |var| cx.vars_down.get(var).clone());
                        l.eval_up(&mut |var, val| cx.vars_down.set(var, val), v)
                    });

                    if matches {
                        return run_inner(inner, cx);
                    }
                }
                false
            }
        }

    }
}
<|endoftext|>


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

//! Private callback support functions.

use libc::{c_double, c_int, c_uint};
use std::mem;

use super::*;

macro_rules! callback(
    (
        type Args = ($($arg:ident: $arg_ty:ty),*);
        type Callback = $Callback:ident;
        let ext_set = $ext_set:expr;
        fn callback($($ext_arg:ident: $ext_arg_ty:ty),*) $call:expr
    ) => (
        local_data_key!(CALLBACK_KEY: Box<Object<Args>:'static>)

        type Args = ($($arg_ty),*,);

        trait Object<T> {
            fn call(&self, args: T);
        }

        impl<UserData> Object<Args> for ::Callback<fn($($arg_ty),*, &UserData), UserData> {
            fn call(&self, ($($arg),*,): Args) {
                (self.f)($($arg),*, &self.data);
            }
        }

        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            CALLBACK_KEY.replace(Some(box f as Box<Object<Args>:'static>));
            ($ext_set)(Some(callback));
        }

        pub fn unset() {
            CALLBACK_KEY.replace(None);
            ($ext_set)(None);
        }

        extern "C" fn callback($($ext_arg: $ext_arg_ty),*) {
            match CALLBACK_KEY.get() {
                Some(cb) => unsafe { cb.call($call) },
                _ => {}
            }
        }
    )
)

pub mod error {
    use libc::{c_int, c_char};
    use std::mem;
    use std::str;

    callback!(
        type Args = (error: ::Error, description: String);
        type Callback = ErrorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetErrorCallback(cb) };
        fn callback(error: c_int, description: *c_char) {
            (mem::transmute(error), str::raw::from_c_str(description))
        }
    )
}

pub mod monitor {
    use libc::{c_int};
    use std::mem;
    use std::kinds::marker;

    callback!(
        type Args = (monitor: ::Monitor, event: ::MonitorEvent);
        type Callback = MonitorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetMonitorCallback(cb) };
        fn callback(monitor: *::ffi::GLFWmonitor, event: c_int) {
            let monitor = ::Monitor {
                ptr: monitor,
                no_copy: marker::NoCopy,
                no_send: marker::NoSend,
                no_share: marker::NoShare,
            };
            (monitor, mem::transmute(event))
        }
    )
}

unsafe fn get_sender<'a>(window: &'a *ffi::GLFWwindow) -> &'a Sender<(f64, WindowEvent)> {
    mem::transmute(ffi::glfwGetWindowUserPointer(*window))
}

macro_rules! window_callback(
    (fn $name:ident () => $event:ident) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event)); }
        }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event($($arg_conv),*))); }
        }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => PosEvent(xpos as i32, ypos as i32))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => SizeEvent(width as i32, height as i32))
window_callback!(fn window_close_callback()                                                 => CloseEvent)
window_callback!(fn window_refresh_callback()                                               => RefreshEvent)
window_callback!(fn window_focus_callback(focused: c_int)                                   => FocusEvent(focused == ffi::TRUE))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => IconifyEvent(iconified == ffi::TRUE))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => FramebufferSizeEvent(width as i32, height as i32))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => MouseButtonEvent(mem::transmute(button), mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => CursorPosEvent(xpos as f64, ypos as f64))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => CursorEnterEvent(entered == ffi::TRUE))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => ScrollEvent(xpos as f64, ypos as f64))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => KeyEvent(mem::transmute(key), scancode, mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn char_callback(character: c_uint)                                        => CharEvent(::std::char::from_u32(character).unwrap()))
<commit_msg>Update to latest rustc<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private callback support functions.

use libc::{c_double, c_int, c_uint};
use std::mem;

use super::*;

macro_rules! callback(
    (
        type Args = ($($arg:ident: $arg_ty:ty),*);
        type Callback = $Callback:ident;
        let ext_set = $ext_set:expr;
        fn callback($($ext_arg:ident: $ext_arg_ty:ty),*) $call:expr
    ) => (
        local_data_key!(CALLBACK_KEY: Box<Object<Args> + 'static>)

        type Args = ($($arg_ty),*,);

        trait Object<T> {
            fn call(&self, args: T);
        }

        impl<UserData> Object<Args> for ::Callback<fn($($arg_ty),*, &UserData), UserData> {
            fn call(&self, ($($arg),*,): Args) {
                (self.f)($($arg),*, &self.data);
            }
        }

        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            CALLBACK_KEY.replace(Some(box f as Box<Object<Args> + 'static>));
            ($ext_set)(Some(callback));
        }

        pub fn unset() {
            CALLBACK_KEY.replace(None);
            ($ext_set)(None);
        }

        extern "C" fn callback($($ext_arg: $ext_arg_ty),*) {
            match CALLBACK_KEY.get() {
                Some(cb) => unsafe { cb.call($call) },
                _ => {}
            }
        }
    )
)

pub mod error {
    use libc::{c_int, c_char};
    use std::mem;
    use std::str;

    callback!(
        type Args = (error: ::Error, description: String);
        type Callback = ErrorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetErrorCallback(cb) };
        fn callback(error: c_int, description: *c_char) {
            (mem::transmute(error), str::raw::from_c_str(description))
        }
    )
}

pub mod monitor {
    use libc::{c_int};
    use std::mem;
    use std::kinds::marker;

    callback!(
        type Args = (monitor: ::Monitor, event: ::MonitorEvent);
        type Callback = MonitorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetMonitorCallback(cb) };
        fn callback(monitor: *::ffi::GLFWmonitor, event: c_int) {
            let monitor = ::Monitor {
                ptr: monitor,
                no_copy: marker::NoCopy,
                no_send: marker::NoSend,
                no_share: marker::NoShare,
            };
            (monitor, mem::transmute(event))
        }
    )
}

unsafe fn get_sender<'a>(window: &'a *ffi::GLFWwindow) -> &'a Sender<(f64, WindowEvent)> {
    mem::transmute(ffi::glfwGetWindowUserPointer(*window))
}

macro_rules! window_callback(
    (fn $name:ident () => $event:ident) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event)); }
        }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event($($arg_conv),*))); }
        }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => PosEvent(xpos as i32, ypos as i32))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => SizeEvent(width as i32, height as i32))
window_callback!(fn window_close_callback()                                                 => CloseEvent)
window_callback!(fn window_refresh_callback()                                               => RefreshEvent)
window_callback!(fn window_focus_callback(focused: c_int)                                   => FocusEvent(focused == ffi::TRUE))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => IconifyEvent(iconified == ffi::TRUE))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => FramebufferSizeEvent(width as i32, height as i32))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => MouseButtonEvent(mem::transmute(button), mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => CursorPosEvent(xpos as f64, ypos as f64))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => CursorEnterEvent(entered == ffi::TRUE))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => ScrollEvent(xpos as f64, ypos as f64))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => KeyEvent(mem::transmute(key), scancode, mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn char_callback(character: c_uint)                                        => CharEvent(::std::char::from_u32(character).unwrap()))
<|endoftext|>


<commit_before>extern crate difference;
extern crate quickcheck;

use difference::{Changeset, Difference};
use quickcheck::{TestResult, quickcheck, QuickCheck};
use std::fmt;

const DEBUG: bool = false;

struct Check<'a> {
    old: &'a str,
    new: &'a str,
    changeset: Changeset,
}

impl<'a> fmt::Display for Check<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Changeset::new({:?}, {:?}, {:?}) -> [",
            self.old,
            self.new,
            self.changeset.split)?;

        let mut iter = self.changeset.diffs.iter();
        if let Some(d) = iter.next() { write!(f, "{:?}", d)?; }
        for d in iter { write!(f, " {:?}", d)?; }
        write!(f, "]")
    }
}

fn check_changeset(old: &str, new: &str, split: &str) -> TestResult {
    Check::new(old, new, split).check()
}

impl<'a> Check<'a> {
    fn new(old: &'a str, new: &'a str, split: &'a str) -> Check<'a> {
        Check {
            old: old,
            new: new,
            changeset: Changeset::new(old, new, split),
        }
    }

    fn check(&self) -> TestResult {
        let split = &self.changeset.split;

        let mut old = self.old.trim_left_matches(split);
        let mut new = self.new.trim_left_matches(split);

        macro_rules! expect {
            ($ident:ident, $pattern:expr, $diff:expr, $split:expr) => {
                if !$ident.starts_with($pattern) {
                    return TestResult::error(format!("`{:?}` does not match `{}` at {:?} for {}",
                                                      $diff,
                                                      stringify!($ident),
                                                      $ident,
                                                      self));
                }
                $ident = &$ident[$pattern.len()..].trim_left_matches($split);
            }
        }

        for d in &self.changeset.diffs {
            if DEBUG {
                println!("assert `{:?}` (old: {:?}, new: {:?})", d, old, new);
            }

            match *d {
                Difference::Same(ref x) => {
                    expect!(old, x, d, split);
                    expect!(new, x, d, split);
                }
                Difference::Add(ref x) => {
                    expect!(new, x, d, split);
                }
                Difference::Rem(ref x) => {
                    expect!(old, x, d, split);
                }
            }
        }
        if !old.is_empty() {
            return TestResult::error(format!("expected end of string in `old` at {:?} for {}",
                                              old, self))
        }
        if !new.is_empty() {
            return TestResult::error(format!("expected end of string in `new` at {:?} for {}",
                                              new, self))
        }
        TestResult::passed()
    }
}

#[test]
fn simple() {
    quickcheck(check_changeset("a", "a a", " "));
}

#[test]
#[ignore]
fn issue_19() {
    // this should work but it doesn't
    // https://github.com/johannhof/difference.rs/issues/19
    quickcheck(check_changeset("a b : g",
                               "b a : b b : g g",
                               " "));
}

#[test]
#[ignore]
fn fuzzy() {
    fn prop(old: Vec<usize>, new: Vec<usize>, words: Vec<char>) -> TestResult {
        if words.is_empty() {
            return TestResult::discard()
        }

        fn map_to_words(input: &[usize], words: &[char]) -> String {
            input.iter()
                .enumerate()
                .fold(String::new(), |mut acc, (i, x)| {
                    if i > 0 {
                        acc.push(' ');
                    }
                    acc.push(words[x % words.len()]);
                    acc
                })
        }
        let old = map_to_words(&old, &words);
        let new = map_to_words(&new, &words);

        check_changeset(&old, &new, " ")
    }

    QuickCheck::new()
        .tests(100) // max successful tests
        .max_tests(10000) // max attempts
        .quickcheck(prop as fn(Vec<usize>, Vec<usize>, Vec<char>) -> TestResult);
}
<commit_msg>rustfmt<commit_after>extern crate difference;
extern crate quickcheck;

use difference::{Changeset, Difference};
use quickcheck::{TestResult, quickcheck, QuickCheck};
use std::fmt;

const DEBUG: bool = false;

struct Check<'a> {
    old: &'a str,
    new: &'a str,
    changeset: Changeset,
}

impl<'a> fmt::Display for Check<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Changeset::new({:?}, {:?}, {:?}) -> [",
            self.old,
            self.new,
            self.changeset.split
        )?;

        let mut iter = self.changeset.diffs.iter();
        if let Some(d) = iter.next() {
            write!(f, "{:?}", d)?;
        }
        for d in iter {
            write!(f, " {:?}", d)?;
        }
        write!(f, "]")
    }
}

fn check_changeset(old: &str, new: &str, split: &str) -> TestResult {
    Check::new(old, new, split).check()
}

impl<'a> Check<'a> {
    fn new(old: &'a str, new: &'a str, split: &'a str) -> Check<'a> {
        Check {
            old: old,
            new: new,
            changeset: Changeset::new(old, new, split),
        }
    }

    fn check(&self) -> TestResult {
        let split = &self.changeset.split;

        let mut old = self.old.trim_left_matches(split);
        let mut new = self.new.trim_left_matches(split);

        macro_rules! expect {
            ($ident:ident, $pattern:expr, $diff:expr, $split:expr) => {
                if !$ident.starts_with($pattern) {
                    return TestResult::error(format!("`{:?}` does not match `{}` at {:?} for {}",
                                                      $diff,
                                                      stringify!($ident),
                                                      $ident,
                                                      self));
                }
                $ident = &$ident[$pattern.len()..].trim_left_matches($split);
            }
        }

        for d in &self.changeset.diffs {
            if DEBUG {
                println!("assert `{:?}` (old: {:?}, new: {:?})", d, old, new);
            }

            match *d {
                Difference::Same(ref x) => {
                    expect!(old, x, d, split);
                    expect!(new, x, d, split);
                }
                Difference::Add(ref x) => {
                    expect!(new, x, d, split);
                }
                Difference::Rem(ref x) => {
                    expect!(old, x, d, split);
                }
            }
        }
        if !old.is_empty() {
            return TestResult::error(format!(
                "expected end of string in `old` at {:?} for {}",
                old,
                self
            ));
        }
        if !new.is_empty() {
            return TestResult::error(format!(
                "expected end of string in `new` at {:?} for {}",
                new,
                self
            ));
        }
        TestResult::passed()
    }
}

#[test]
fn simple() {
    quickcheck(check_changeset("a", "a a", " "));
}

#[test]
#[ignore]
fn issue_19() {
    // this should work but it doesn't
    // https://github.com/johannhof/difference.rs/issues/19
    quickcheck(check_changeset("a b : g", "b a : b b : g g", " "));
}

#[test]
#[ignore]
fn fuzzy() {
    fn prop(old: Vec<usize>, new: Vec<usize>, words: Vec<char>) -> TestResult {
        if words.is_empty() {
            return TestResult::discard();
        }

        fn map_to_words(input: &[usize], words: &[char]) -> String {
            input.iter().enumerate().fold(
                String::new(),
                |mut acc, (i, x)| {
                    if i > 0 {
                        acc.push(' ');
                    }
                    acc.push(words[x % words.len()]);
                    acc
                },
            )
        }
        let old = map_to_words(&old, &words);
        let new = map_to_words(&new, &words);

        check_changeset(&old, &new, " ")
    }

    QuickCheck::new()
        .tests(100) // max successful tests
        .max_tests(10000) // max attempts
        .quickcheck(prop as fn(Vec<usize>, Vec<usize>, Vec<char>) -> TestResult);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use fnv::FnvHasher;
use internal_types::{Glyph, GlyphKey, RasterItem};
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use webrender_traits::{FontKey, ImageKey, ImageRendering};

type RequiredImageSet = HashSet<(ImageKey, ImageRendering), BuildHasherDefault<FnvHasher>>;
type RequiredGlyphMap = HashMap<FontKey, HashSet<Glyph>, BuildHasherDefault<FnvHasher>>;
type RequiredRasterSet = HashSet<RasterItem, BuildHasherDefault<FnvHasher>>;

pub struct ResourceList {
    required_images: RequiredImageSet,
    required_glyphs: RequiredGlyphMap,
    required_rasters: RequiredRasterSet,
}

impl ResourceList {
    pub fn new() -> ResourceList {
        ResourceList {
            required_glyphs: HashMap::with_hasher(Default::default()),
            required_images: HashSet::with_hasher(Default::default()),
            required_rasters: HashSet::with_hasher(Default::default()),
        }
    }

    pub fn add_image(&mut self,
                     key: ImageKey,
                     image_rendering: ImageRendering) {
        self.required_images.insert((key, image_rendering));
    }

    pub fn add_glyph(&mut self, font_key: FontKey, glyph: Glyph) {
        self.required_glyphs.entry(font_key)
                            .or_insert_with(HashSet::new)
                            .insert(glyph);
    }

    pub fn for_each_image<F>(&self, mut f: F) where F: FnMut(ImageKey, ImageRendering) {
        for &(image_id, image_rendering) in &self.required_images {
            f(image_id, image_rendering);
        }
    }

    pub fn for_each_raster<F>(&self, mut f: F) where F: FnMut(&RasterItem) {
        for raster_item in &self.required_rasters {
            f(raster_item);
        }
    }

    pub fn for_each_glyph<F>(&self, mut f: F) where F: FnMut(&GlyphKey) {
        for (font_id, glyphs) in &self.required_glyphs {
            let mut glyph_key = GlyphKey::new(font_id.clone(), Au(0), Au(0), 0);

            for glyph in glyphs {
                glyph_key.size = glyph.size;
                glyph_key.index = glyph.index;
                glyph_key.blur_radius = glyph.blur_radius;

                f(&glyph_key);
            }
        }
    }
}
<commit_msg>Switch glyph hashset to use Fnv.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use fnv::FnvHasher;
use internal_types::{Glyph, GlyphKey, RasterItem};
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use webrender_traits::{FontKey, ImageKey, ImageRendering};

type RequiredImageSet = HashSet<(ImageKey, ImageRendering), BuildHasherDefault<FnvHasher>>;
type RequiredGlyphMap = HashMap<FontKey,
                                HashSet<Glyph, BuildHasherDefault<FnvHasher>>,
                                BuildHasherDefault<FnvHasher>>;
type RequiredRasterSet = HashSet<RasterItem, BuildHasherDefault<FnvHasher>>;

pub struct ResourceList {
    required_images: RequiredImageSet,
    required_glyphs: RequiredGlyphMap,
    required_rasters: RequiredRasterSet,
}

impl ResourceList {
    pub fn new() -> ResourceList {
        ResourceList {
            required_glyphs: HashMap::with_hasher(Default::default()),
            required_images: HashSet::with_hasher(Default::default()),
            required_rasters: HashSet::with_hasher(Default::default()),
        }
    }

    pub fn add_image(&mut self,
                     key: ImageKey,
                     image_rendering: ImageRendering) {
        self.required_images.insert((key, image_rendering));
    }

    pub fn add_glyph(&mut self, font_key: FontKey, glyph: Glyph) {
        self.required_glyphs.entry(font_key)
                            .or_insert_with(|| HashSet::with_hasher(Default::default()))
                            .insert(glyph);
    }

    pub fn for_each_image<F>(&self, mut f: F) where F: FnMut(ImageKey, ImageRendering) {
        for &(image_id, image_rendering) in &self.required_images {
            f(image_id, image_rendering);
        }
    }

    pub fn for_each_raster<F>(&self, mut f: F) where F: FnMut(&RasterItem) {
        for raster_item in &self.required_rasters {
            f(raster_item);
        }
    }

    pub fn for_each_glyph<F>(&self, mut f: F) where F: FnMut(&GlyphKey) {
        for (font_id, glyphs) in &self.required_glyphs {
            let mut glyph_key = GlyphKey::new(font_id.clone(), Au(0), Au(0), 0);

            for glyph in glyphs {
                glyph_key.size = glyph.size;
                glyph_key.index = glyph.index;
                glyph_key.blur_radius = glyph.blur_radius;

                f(&glyph_key);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![unstable(feature = "wake_trait", issue = "69912")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data used
/// to wake up a task is stored in an [`Arc`][arc]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
///
/// [arc]: ../../std/sync/struct.Arc.html
#[unstable(feature = "wake_trait", issue = "69912")]
pub trait Wake {
    /// Wake this task.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls `wake` on the clone.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        unsafe { Arc::incr_strong_count(waker as *const W) };
        RawWaker::new(
            waker as *const (),
            &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
        )
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: Arc<W> = unsafe { Arc::from_raw(waker as *const W) };
        <W as Wake>::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: ManuallyDrop<Arc<W>> =
            unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
        <W as Wake>::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        unsafe { Arc::decr_strong_count(waker as *const W) };
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    )
}
<commit_msg>Remove unnecessary type hints from the Wake impl<commit_after>#![unstable(feature = "wake_trait", issue = "69912")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data used
/// to wake up a task is stored in an [`Arc`][arc]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
///
/// [arc]: ../../std/sync/struct.Arc.html
#[unstable(feature = "wake_trait", issue = "69912")]
pub trait Wake {
    /// Wake this task.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls `wake` on the clone.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        unsafe { Arc::incr_strong_count(waker as *const W) };
        RawWaker::new(
            waker as *const (),
            &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
        )
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker = unsafe { Arc::from_raw(waker as *const W) };
        <W as Wake>::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker = unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
        <W as Wake>::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        unsafe { Arc::decr_strong_count(waker as *const W) };
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    )
}
<|endoftext|>


<commit_before>//! Support for fetching runtime state directly from the Docker daemon.

use boondock;
use regex::Regex;
use std::collections::BTreeMap;
use std::net;

use errors::*;
use project::Project;

/// Everything we know about the running application, based on querying Docker.
#[derive(Debug)]
pub struct RuntimeState {
    /// Map service names to information about associated containers.
    services: BTreeMap<String, Vec<ContainerInfo>>,
}

impl RuntimeState {
    /// Look up the runtime state for the specified project (and its
    /// current target).
    pub fn for_project(project: &Project) -> Result<RuntimeState> {
        // Standardize our error messages since this is going to fail a lot
        // until we debug all the Docker wire formats and undocumented
        // special cases.
        Self::for_project_inner(project)
            .chain_err(|| ErrorKind::CouldNotGetRuntimeState)
    }

    /// The actual implementation of `for_project`.
    fn for_project_inner(project: &Project) -> Result<RuntimeState> {
        let name = project.normalized_name();
        let target = project.current_target().name().to_owned();
        let docker = try!(boondock::Docker::connect_with_defaults());

        let mut services = BTreeMap::new();
        let containers = try!(docker.get_containers(true));
        for container in &containers {
            let info = try!(docker.get_container_info(&container));
            let labels = &info.Config.Labels;
            if labels.get("com.docker.compose.project") == Some(&name) &&
               labels.get("io.fdy.cage.target") == Some(&target) {
                if let Some(service) = labels.get("com.docker.compose.service") {
                    let our_info = try!(ContainerInfo::new(&info));
                    services.entry(service.to_owned())
                        .or_insert_with(Vec::new)
                        .push(our_info);
                }
            }
        }
        Ok(RuntimeState { services: services })
    }

    /// Get the containers associated with a service.  This will return the
    /// empty list if it can't find any containers related to the specified
    /// `service_name`.
    pub fn service_containers(&self, service_name: &str) -> &[ContainerInfo] {
        self.services
            .get(service_name)
            .map_or_else(|| &[] as &[ContainerInfo], |containers| &containers[..])
    }
}

/// Information about a specific container associated with a service.
#[derive(Debug, Clone)]
pub struct ContainerInfo {
    /// The current state of this container.
    state: ContainerState,

    /// An IP address at which we can access this container.
    ip_addr: Option<net::IpAddr>,

    /// The TCP ports this container is listening on (not the corresponding
    /// host ports!).
    container_tcp_ports: Vec<u16>,
}

impl ContainerInfo {
    /// Construct our summary from the raw data returned by Docker.
    fn new(info: &boondock::container::ContainerInfo) -> Result<ContainerInfo> {
        // Get an IP address for this running container.
        let raw_ip_addr = &info.NetworkSettings.IPAddress[..];
        let ip_addr = if raw_ip_addr != "" {
            Some(try!(raw_ip_addr.parse()
                .chain_err(|| ErrorKind::parse("IP address", raw_ip_addr))))
        } else {
            None
        };

        // Get the listening network ports.
        let mut ports = vec![];
        for port_str in info.NetworkSettings.Ports.keys() {
            lazy_static! {
                static ref TCP_PORT: Regex = Regex::new(r#"^(\d+)/tcp$"#).unwrap();
            }
            if let Some(caps) = TCP_PORT.captures(port_str) {
                let port = try!(caps.at(1)
                    .unwrap()
                    .parse()
                    .chain_err(|| ErrorKind::parse("TCP port", port_str.clone())));
                ports.push(port);
            }
        }

        Ok(ContainerInfo {
            state: ContainerState::new(&info.State),
            ip_addr: ip_addr,
            container_tcp_ports: ports,
        })
    }

    /// The current state of this container.
    pub fn state(&self) -> ContainerState {
        self.state
    }

    /// An IP address at which we can access this container.
    pub fn ip_addr(&self) -> Option<net::IpAddr> {
        self.ip_addr
    }

    /// The TCP ports this container is listening on (not the corresponding
    /// host ports!).
    pub fn container_tcp_ports(&self) -> &[u16] {
        &self.container_tcp_ports
    }

    /// The socket addresses this container is listening on.
    pub fn socket_addrs(&self) -> Vec<net::SocketAddr> {
        self.ip_addr()
            .map(|addr| {
                self.container_tcp_ports
                    .iter()
                    .map(|port| net::SocketAddr::new(addr, *port))
                    .collect()
            })
            .unwrap_or_else(Vec::new)
    }

    /// Is this container listening to its ports?
    pub fn is_listening_to_ports(&self) -> bool {
        for addr in self.socket_addrs() {
            if net::TcpListener::bind(addr).is_err() {
                trace!("scanned {}: CLOSED", addr);
                return false;
            }
            trace!("scanned {}: OPEN", addr);
        }
        true
    }
}

/// Is a Docker container running? Stopped?
#[derive(Debug, Clone, Copy)]
pub enum ContainerState {
    /// The container is current running.
    Running,
    /// The container is stopped with exit code 0.
    Done,
    /// The container is stopped with a non-zero exit code.
    Error(i64),
    /// The container is in some other state.
    Other,
}

impl ContainerState {
    /// Create a new `ContainerState` from Docker data.
    fn new(state: &boondock::container::State) -> ContainerState {
        if state.Running {
            ContainerState::Running
        } else if state.Dead && state.ExitCode == 0 {
            ContainerState::Done
        } else if state.Dead {
            ContainerState::Error(state.ExitCode)
        } else {
            ContainerState::Other
        }
    }
}
<commit_msg>Log more useful info about port scanning<commit_after>//! Support for fetching runtime state directly from the Docker daemon.

use boondock;
use regex::Regex;
use std::collections::BTreeMap;
use std::net;

use errors::*;
use project::Project;

/// Everything we know about the running application, based on querying Docker.
#[derive(Debug)]
pub struct RuntimeState {
    /// Map service names to information about associated containers.
    services: BTreeMap<String, Vec<ContainerInfo>>,
}

impl RuntimeState {
    /// Look up the runtime state for the specified project (and its
    /// current target).
    pub fn for_project(project: &Project) -> Result<RuntimeState> {
        // Standardize our error messages since this is going to fail a lot
        // until we debug all the Docker wire formats and undocumented
        // special cases.
        Self::for_project_inner(project)
            .chain_err(|| ErrorKind::CouldNotGetRuntimeState)
    }

    /// The actual implementation of `for_project`.
    fn for_project_inner(project: &Project) -> Result<RuntimeState> {
        let name = project.normalized_name();
        let target = project.current_target().name().to_owned();
        let docker = try!(boondock::Docker::connect_with_defaults());

        let mut services = BTreeMap::new();
        let containers = try!(docker.get_containers(true));
        for container in &containers {
            let info = try!(docker.get_container_info(&container));
            let labels = &info.Config.Labels;
            if labels.get("com.docker.compose.project") == Some(&name) &&
               labels.get("io.fdy.cage.target") == Some(&target) {
                if let Some(service) = labels.get("com.docker.compose.service") {
                    let our_info = try!(ContainerInfo::new(&info));
                    services.entry(service.to_owned())
                        .or_insert_with(Vec::new)
                        .push(our_info);
                }
            }
        }
        Ok(RuntimeState { services: services })
    }

    /// Get the containers associated with a service.  This will return the
    /// empty list if it can't find any containers related to the specified
    /// `service_name`.
    pub fn service_containers(&self, service_name: &str) -> &[ContainerInfo] {
        self.services
            .get(service_name)
            .map_or_else(|| &[] as &[ContainerInfo], |containers| &containers[..])
    }
}

/// Information about a specific container associated with a service.
#[derive(Debug, Clone)]
pub struct ContainerInfo {
    /// The name of this container.
    name: String,

    /// The current state of this container.
    state: ContainerState,

    /// An IP address at which we can access this container.
    ip_addr: Option<net::IpAddr>,

    /// The TCP ports this container is listening on (not the corresponding
    /// host ports!).
    container_tcp_ports: Vec<u16>,
}

impl ContainerInfo {
    /// Construct our summary from the raw data returned by Docker.
    fn new(info: &boondock::container::ContainerInfo) -> Result<ContainerInfo> {
        // Get an IP address for this running container.
        let raw_ip_addr = &info.NetworkSettings.IPAddress[..];
        let ip_addr = if raw_ip_addr != "" {
            Some(try!(raw_ip_addr.parse()
                .chain_err(|| ErrorKind::parse("IP address", raw_ip_addr))))
        } else {
            None
        };

        // Get the listening network ports.
        let mut ports = vec![];
        for port_str in info.NetworkSettings.Ports.keys() {
            lazy_static! {
                static ref TCP_PORT: Regex = Regex::new(r#"^(\d+)/tcp$"#).unwrap();
            }
            if let Some(caps) = TCP_PORT.captures(port_str) {
                let port = try!(caps.at(1)
                    .unwrap()
                    .parse()
                    .chain_err(|| ErrorKind::parse("TCP port", port_str.clone())));
                ports.push(port);
            }
        }

        Ok(ContainerInfo {
            name: info.Name.to_owned(),
            state: ContainerState::new(&info.State),
            ip_addr: ip_addr,
            container_tcp_ports: ports,
        })
    }

    /// The current state of this container.
    pub fn state(&self) -> ContainerState {
        self.state
    }

    /// An IP address at which we can access this container.
    pub fn ip_addr(&self) -> Option<net::IpAddr> {
        self.ip_addr
    }

    /// The TCP ports this container is listening on (not the corresponding
    /// host ports!).
    pub fn container_tcp_ports(&self) -> &[u16] {
        &self.container_tcp_ports
    }

    /// The socket addresses this container is listening on.
    pub fn socket_addrs(&self) -> Vec<net::SocketAddr> {
        self.ip_addr()
            .map(|addr| {
                self.container_tcp_ports
                    .iter()
                    .map(|port| net::SocketAddr::new(addr, *port))
                    .collect()
            })
            .unwrap_or_else(Vec::new)
    }

    /// Is this container listening to its ports?
    pub fn is_listening_to_ports(&self) -> bool {
        debug!("scanning container '{}'", &self.name);
        for addr in self.socket_addrs() {
            trace!("scanning container '{}' at {}", &self.name, addr);
            if net::TcpListener::bind(addr).is_err() {
                debug!("container '{}': {} is CLOSED", &self.name, addr);
                return false;
            }
        }
        debug!("container '{}' is listening on all ports", &self.name);
        true
    }
}

/// Is a Docker container running? Stopped?
#[derive(Debug, Clone, Copy)]
pub enum ContainerState {
    /// The container is current running.
    Running,
    /// The container is stopped with exit code 0.
    Done,
    /// The container is stopped with a non-zero exit code.
    Error(i64),
    /// The container is in some other state.
    Other,
}

impl ContainerState {
    /// Create a new `ContainerState` from Docker data.
    fn new(state: &boondock::container::State) -> ContainerState {
        if state.Running {
            ContainerState::Running
        } else if state.Dead && state.ExitCode == 0 {
            ContainerState::Done
        } else if state.Dead {
            ContainerState::Error(state.ExitCode)
        } else {
            ContainerState::Other
        }
    }
}
<|endoftext|>