<commit_before>use nom::{alphanumeric, digit, eof, is_alphanumeric, line_ending, multispace};
use nom::{IResult, Err, ErrorKind, Needed};
use std::fmt::{self, Display};
use std::str;
use std::str::FromStr;

use column::{Column, FunctionExpression};
use keywords::sql_keyword;
use table::Table;

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum SqlType {
    Char(u16),
    Varchar(u16),
    Int(u16),
    Bigint(u16),
    Tinyint(u16),
    Blob,
    Longblob,
    Mediumblob,
    Tinyblob,
    Double,
    Float,
    Real,
    Tinytext,
    Mediumtext,
    Text,
    Date,
    Timestamp,
    Varbinary(u16),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Literal {
    Null,
    Integer(i64),
    String(String),
    Blob(Vec<u8>),
    CurrentTime,
    CurrentDate,
    CurrentTimestamp,
}

impl From<i64> for Literal {
    fn from(i: i64) -> Self {
        Literal::Integer(i)
    }
}

impl From<String> for Literal {
    fn from(s: String) -> Self {
        Literal::String(s)
    }
}

impl<'a> From<&'a str> for Literal {
    fn from(s: &'a str) -> Self {
        Literal::String(String::from(s))
    }
}

impl ToString for Literal {
    fn to_string(&self) -> String {
        match *self {
            Literal::Null => "NULL".to_string(),
            Literal::Integer(ref i) => format!("{}", i),
            Literal::String(ref s) => s.clone(),
            Literal::Blob(ref bv) => {
                format!("{}",
                        bv.iter()
                            .map(|v| format!("{:x}", v))
                            .collect::<Vec<String>>()
                            .join(" "))
            }
            Literal::CurrentTime => "CURRENT_TIME".to_string(),
            Literal::CurrentDate => "CURRENT_DATE".to_string(),
            Literal::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum Operator {
    Not,
    And,
    Or,
    Like,
    NotLike,
    Equal,
    NotEqual,
    Greater,
    GreaterOrEqual,
    Less,
    LessOrEqual,
}

impl Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op = match *self {
            Operator::Not => "not",
            Operator::And => "and",
            Operator::Or => "or",
            Operator::Like => "like",
            Operator::NotLike => "not_like",
            Operator::Equal => "=",
            Operator::NotEqual => "!=",
            Operator::Greater => ">",
            Operator::GreaterOrEqual => ">=",
            Operator::Less => "<",
            Operator::LessOrEqual => "<=",
        };
        write!(f, "{}", op)
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum TableKey {
    PrimaryKey(Vec<Column>),
    UniqueKey(Option<String>, Vec<Column>),
    FulltextKey(Option<String>, Vec<Column>),
    Key(String, Vec<Column>),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum FieldExpression {
    All,
    AllInTable(String),
    Col(Column),
}

impl Display for FieldExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FieldExpression::All => write!(f, "*"),
            FieldExpression::AllInTable(ref table) => write!(f, "{}.*", table),
            FieldExpression::Col(ref col) => write!(f, "{}", col.name.as_str()),
        }
    }
}

impl Default for FieldExpression {
    fn default() -> FieldExpression {
        FieldExpression::All
    }
}

#[inline]
pub fn is_sql_identifier(chr: u8) -> bool {
    is_alphanumeric(chr) || chr == '_' as u8
}

/// Parses the arguments for an agregation function, and also returns whether the distinct flag is
/// present.
named!(pub function_arguments<&[u8], (Column, bool)>,
       chain!(
           distinct: opt!(chain!(
               caseless_tag!("distinct") ~
               multispace,
               ||{}
           )) ~
           column: column_identifier_no_alias,
           || {
               (column, distinct.is_some())
           }
       )
);

named!(pub column_function<&[u8], FunctionExpression>,
    alt_complete!(
        chain!(
            caseless_tag!("count(*)"),
            || {
                FunctionExpression::CountStar
            }
        )
    |   chain!(
            caseless_tag!("count") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Count(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("sum") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Sum(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("avg") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Avg(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("max") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Max(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("min") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Min(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("group_concat") ~
            spec: delimited!(tag!("("),
                       complete!(chain!(
                               column: column_identifier_no_alias ~
                               seperator: opt!(
                                   chain!(
                                       multispace? ~
                                       caseless_tag!("separator") ~
                                       sep: delimited!(tag!("'"), opt!(alphanumeric), tag!("'")) ~
                                       multispace?,
                                       || { sep.unwrap_or("".as_bytes()) }
                                   )
                               ),
                               || { (column, seperator) }
                       )),
                       tag!(")")),
            || {
                let (ref col, ref sep) = spec;
                let sep = match *sep {
                    // default separator is a comma, see MySQL manual §5.7
                    None => String::from(","),
                    Some(s) => String::from_utf8(s.to_vec()).unwrap(),
                };

                FunctionExpression::GroupConcat(col.clone(), sep)
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier_no_alias<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function,
            || {
                Column {
                    name: format!("{}", function),
                    alias: None,
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8),
            || {
                Column {
                    name: String::from(column),
                    alias: None,
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: match alias {
                        None => format!("{}", function),
                        Some(a) => String::from(a),
                    },
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8) ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: String::from(column),
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL identifier (alphanumeric and "_").
named!(pub sql_identifier<&[u8], &[u8]>,
    alt_complete!(
          chain!(
                not!(peek!(sql_keyword)) ~
                ident: take_while1!(is_sql_identifier),
                || { ident }
          )
        | delimited!(tag!("`"), take_while1!(is_sql_identifier), tag!("`"))
        | delimited!(tag!("'"), take_while1!(is_sql_identifier), tag!("'"))
    )
);

/// Parse an unsigned integer.
named!(pub unsigned_number<&[u8], u64>,
    map_res!(
        map_res!(digit, str::from_utf8),
        FromStr::from_str
    )
);

/// Parse a terminator that ends a SQL statement.
named!(pub statement_terminator,
    delimited!(opt!(multispace),
               alt_complete!(tag!(";") | line_ending | eof),
               opt!(multispace)
    )
);

/// Parse binary comparison operators
named!(pub binary_comparison_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("not_like"), |_| Operator::NotLike)
         | map!(caseless_tag!("like"), |_| Operator::Like)
         | map!(caseless_tag!("!="), |_| Operator::NotEqual)
         | map!(caseless_tag!("<>"), |_| Operator::NotEqual)
         | map!(caseless_tag!(">="), |_| Operator::GreaterOrEqual)
         | map!(caseless_tag!("<="), |_| Operator::LessOrEqual)
         | map!(caseless_tag!("="), |_| Operator::Equal)
         | map!(caseless_tag!("<"), |_| Operator::Less)
         | map!(caseless_tag!(">"), |_| Operator::Greater)
    )
);

/// Parse rule for AS-based aliases for SQL entities.
named!(pub as_alias<&[u8], &str>,
    complete!(
        chain!(
            multispace ~
            opt!(chain!(caseless_tag!("as") ~ multispace, ||{})) ~
            alias: map_res!(sql_identifier, str::from_utf8),
            || { alias }
        )
    )
);

/// Parse rule for a comma-separated list of fields without aliases.
named!(pub field_list<&[u8], Vec<Column> >,
       many0!(
           chain!(
               fieldname: column_identifier_no_alias ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { fieldname }
           )
       )
);

/// Parse list of column/field definitions.
named!(pub field_definition_expr<&[u8], Vec<FieldExpression>>,
       many0!(
           chain!(
               field: alt_complete!(
                   chain!(
                       tag!("*"),
                       || {
                           FieldExpression::All
                       }
                   )
                 | chain!(
                     table: table_reference ~
                     tag!(".*"),
                     || {
                         FieldExpression::AllInTable(table.name.clone())
                     }
                 )
                 | chain!(
                     column: column_identifier,
                     || {
                         FieldExpression::Col(column)
                     }
                 )
               ) ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { field }
           )
       )
);

/// Parse list of table names.
/// XXX(malte): add support for aliases
named!(pub table_list<&[u8], Vec<Table> >,
       many0!(
           chain!(
               table: table_reference ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       || {}
                   ))
               ),
               || { table }
           )
       )
);

/// Integer literal value
named!(pub integer_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace), digit, opt!(multispace)),
        || {
            let intval = i64::from_str(str::from_utf8(val).unwrap()).unwrap();
            Literal::Integer(intval)
        }
    )
);

/// String literal value
named!(pub string_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace),
                 alt_complete!(
                       delimited!(tag!("\""), opt!(take_until!("\"")), tag!("\""))
                     | delimited!(tag!("'"), opt!(take_until!("'")), tag!("'"))
                 ),
                 opt!(multispace)
              ),
        || {
            let val = val.unwrap_or("".as_bytes());
            let s = String::from(str::from_utf8(val).unwrap());
            Literal::String(s)
        }
    )
);

/// Any literal value.
named!(pub literal<&[u8], Literal>,
    alt_complete!(
          integer_literal
        | string_literal
        | chain!(caseless_tag!("NULL"), || Literal::Null)
        | chain!(caseless_tag!("CURRENT_TIMESTAMP"), || Literal::CurrentTimestamp)
        | chain!(caseless_tag!("CURRENT_DATE"), || Literal::CurrentDate)
        | chain!(caseless_tag!("CURRENT_TIME"), || Literal::CurrentTime)
//        | float_literal
    )
);

/// Parse a list of values (e.g., for INSERT syntax).
named!(pub value_list<&[u8], Vec<Literal> >,
       many0!(
           chain!(
               val: literal ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { val }
           )
       )
);

/// Parse a reference to a named table
/// XXX(malte): add support for schema.table notation
named!(pub table_reference<&[u8], Table>,
    chain!(
        table: map_res!(sql_identifier, str::from_utf8) ~
        alias: opt!(as_alias),
        || {
            Table {
                name: String::from(table),
                alias: match alias {
                    Some(a) => Some(String::from(a)),
                    None => None,
                }
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sql_identifiers() {
        let id1 = b"foo";
        let id2 = b"f_o_o";
        let id3 = b"foo12";
        let id4 = b":fo oo";
        let id5 = b"primary ";
        let id6 = b"`primary`";

        assert!(sql_identifier(id1).is_done());
        assert!(sql_identifier(id2).is_done());
        assert!(sql_identifier(id3).is_done());
        assert!(sql_identifier(id4).is_err());
        assert!(sql_identifier(id5).is_err());
        assert!(sql_identifier(id6).is_done());
    }

    #[test]
    fn simple_column_function() {
        let qs = b"max(addr_id)";

        let res = column_identifier(qs);
        let expected = Column {
            name: String::from("max(addr_id)"),
            alias: None,
            table: None,
            function: Some(Box::new(FunctionExpression::Max(Column::from("addr_id")))),
        };
        assert_eq!(res.unwrap().1, expected);
    }
}
<commit_msg>Support literal values in field expression list<commit_after>use nom::{alphanumeric, digit, eof, is_alphanumeric, line_ending, multispace};
use nom::{IResult, Err, ErrorKind, Needed};
use std::fmt::{self, Display};
use std::str;
use std::str::FromStr;

use column::{Column, FunctionExpression};
use keywords::sql_keyword;
use table::Table;

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum SqlType {
    Char(u16),
    Varchar(u16),
    Int(u16),
    Bigint(u16),
    Tinyint(u16),
    Blob,
    Longblob,
    Mediumblob,
    Tinyblob,
    Double,
    Float,
    Real,
    Tinytext,
    Mediumtext,
    Text,
    Date,
    Timestamp,
    Varbinary(u16),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Literal {
    Null,
    Integer(i64),
    String(String),
    Blob(Vec<u8>),
    CurrentTime,
    CurrentDate,
    CurrentTimestamp,
}

impl From<i64> for Literal {
    fn from(i: i64) -> Self {
        Literal::Integer(i)
    }
}

impl From<String> for Literal {
    fn from(s: String) -> Self {
        Literal::String(s)
    }
}

impl<'a> From<&'a str> for Literal {
    fn from(s: &'a str) -> Self {
        Literal::String(String::from(s))
    }
}

impl ToString for Literal {
    fn to_string(&self) -> String {
        match *self {
            Literal::Null => "NULL".to_string(),
            Literal::Integer(ref i) => format!("{}", i),
            Literal::String(ref s) => s.clone(),
            Literal::Blob(ref bv) => {
                format!("{}",
                        bv.iter()
                            .map(|v| format!("{:x}", v))
                            .collect::<Vec<String>>()
                            .join(" "))
            }
            Literal::CurrentTime => "CURRENT_TIME".to_string(),
            Literal::CurrentDate => "CURRENT_DATE".to_string(),
            Literal::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum Operator {
    Not,
    And,
    Or,
    Like,
    NotLike,
    Equal,
    NotEqual,
    Greater,
    GreaterOrEqual,
    Less,
    LessOrEqual,
}

impl Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op = match *self {
            Operator::Not => "not",
            Operator::And => "and",
            Operator::Or => "or",
            Operator::Like => "like",
            Operator::NotLike => "not_like",
            Operator::Equal => "=",
            Operator::NotEqual => "!=",
            Operator::Greater => ">",
            Operator::GreaterOrEqual => ">=",
            Operator::Less => "<",
            Operator::LessOrEqual => "<=",
        };
        write!(f, "{}", op)
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
pub enum TableKey {
    PrimaryKey(Vec<Column>),
    UniqueKey(Option<String>, Vec<Column>),
    FulltextKey(Option<String>, Vec<Column>),
    Key(String, Vec<Column>),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum FieldExpression {
    All,
    AllInTable(String),
    Col(Column),
    Literal(Literal),
}

impl Display for FieldExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FieldExpression::All => write!(f, "*"),
            FieldExpression::AllInTable(ref table) => write!(f, "{}.*", table),
            FieldExpression::Col(ref col) => write!(f, "{}", col.name.as_str()),
            FieldExpression::Literal(ref lit) => write!(f, "{}", lit.to_string()),
        }
    }
}

impl Default for FieldExpression {
    fn default() -> FieldExpression {
        FieldExpression::All
    }
}

#[inline]
pub fn is_sql_identifier(chr: u8) -> bool {
    is_alphanumeric(chr) || chr == '_' as u8
}

/// Parses the arguments for an agregation function, and also returns whether the distinct flag is
/// present.
named!(pub function_arguments<&[u8], (Column, bool)>,
       chain!(
           distinct: opt!(chain!(
               caseless_tag!("distinct") ~
               multispace,
               ||{}
           )) ~
           column: column_identifier_no_alias,
           || {
               (column, distinct.is_some())
           }
       )
);

named!(pub column_function<&[u8], FunctionExpression>,
    alt_complete!(
        chain!(
            caseless_tag!("count(*)"),
            || {
                FunctionExpression::CountStar
            }
        )
    |   chain!(
            caseless_tag!("count") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Count(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("sum") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Sum(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("avg") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Avg(args.0.clone(), args.1)
            }
        )
    |   chain!(
            caseless_tag!("max") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Max(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("min") ~
            args: delimited!(tag!("("), function_arguments, tag!(")")),
            || {
                FunctionExpression::Min(args.0.clone())
            }
        )
    |   chain!(
            caseless_tag!("group_concat") ~
            spec: delimited!(tag!("("),
                       complete!(chain!(
                               column: column_identifier_no_alias ~
                               seperator: opt!(
                                   chain!(
                                       multispace? ~
                                       caseless_tag!("separator") ~
                                       sep: delimited!(tag!("'"), opt!(alphanumeric), tag!("'")) ~
                                       multispace?,
                                       || { sep.unwrap_or("".as_bytes()) }
                                   )
                               ),
                               || { (column, seperator) }
                       )),
                       tag!(")")),
            || {
                let (ref col, ref sep) = spec;
                let sep = match *sep {
                    // default separator is a comma, see MySQL manual §5.7
                    None => String::from(","),
                    Some(s) => String::from_utf8(s.to_vec()).unwrap(),
                };

                FunctionExpression::GroupConcat(col.clone(), sep)
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier_no_alias<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function,
            || {
                Column {
                    name: format!("{}", function),
                    alias: None,
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8),
            || {
                Column {
                    name: String::from(column),
                    alias: None,
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: match alias {
                        None => format!("{}", function),
                        Some(a) => String::from(a),
                    },
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: None,
                    function: Some(Box::new(function)),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8) ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: String::from(column),
                    alias: match alias {
                        None => None,
                        Some(a) => Some(String::from(a)),
                    },
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL identifier (alphanumeric and "_").
named!(pub sql_identifier<&[u8], &[u8]>,
    alt_complete!(
          chain!(
                not!(peek!(sql_keyword)) ~
                ident: take_while1!(is_sql_identifier),
                || { ident }
          )
        | delimited!(tag!("`"), take_while1!(is_sql_identifier), tag!("`"))
        | delimited!(tag!("'"), take_while1!(is_sql_identifier), tag!("'"))
    )
);

/// Parse an unsigned integer.
named!(pub unsigned_number<&[u8], u64>,
    map_res!(
        map_res!(digit, str::from_utf8),
        FromStr::from_str
    )
);

/// Parse a terminator that ends a SQL statement.
named!(pub statement_terminator,
    delimited!(opt!(multispace),
               alt_complete!(tag!(";") | line_ending | eof),
               opt!(multispace)
    )
);

/// Parse binary comparison operators
named!(pub binary_comparison_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("not_like"), |_| Operator::NotLike)
         | map!(caseless_tag!("like"), |_| Operator::Like)
         | map!(caseless_tag!("!="), |_| Operator::NotEqual)
         | map!(caseless_tag!("<>"), |_| Operator::NotEqual)
         | map!(caseless_tag!(">="), |_| Operator::GreaterOrEqual)
         | map!(caseless_tag!("<="), |_| Operator::LessOrEqual)
         | map!(caseless_tag!("="), |_| Operator::Equal)
         | map!(caseless_tag!("<"), |_| Operator::Less)
         | map!(caseless_tag!(">"), |_| Operator::Greater)
    )
);

/// Parse rule for AS-based aliases for SQL entities.
named!(pub as_alias<&[u8], &str>,
    complete!(
        chain!(
            multispace ~
            opt!(chain!(caseless_tag!("as") ~ multispace, ||{})) ~
            alias: map_res!(sql_identifier, str::from_utf8),
            || { alias }
        )
    )
);

/// Parse rule for a comma-separated list of fields without aliases.
named!(pub field_list<&[u8], Vec<Column> >,
       many0!(
           chain!(
               fieldname: column_identifier_no_alias ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { fieldname }
           )
       )
);

/// Parse list of column/field definitions.
named!(pub field_definition_expr<&[u8], Vec<FieldExpression>>,
       many0!(
           chain!(
               field: alt_complete!(
                   chain!(
                       tag!("*"),
                       || {
                           FieldExpression::All
                       }
                   )
                 | chain!(
                     table: table_reference ~
                     tag!(".*"),
                     || {
                         FieldExpression::AllInTable(table.name.clone())
                     }
                 )
                 | chain!(
                     column: column_identifier,
                     || {
                         FieldExpression::Col(column)
                     }
                 )
                 | chain!(
                     literal: literal,
                     || {
                         FieldExpression::Literal(literal)
                     }
                 )
               ) ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { field }
           )
       )
);

/// Parse list of table names.
/// XXX(malte): add support for aliases
named!(pub table_list<&[u8], Vec<Table> >,
       many0!(
           chain!(
               table: table_reference ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       || {}
                   ))
               ),
               || { table }
           )
       )
);

/// Integer literal value
named!(pub integer_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace), digit, opt!(multispace)),
        || {
            let intval = i64::from_str(str::from_utf8(val).unwrap()).unwrap();
            Literal::Integer(intval)
        }
    )
);

/// String literal value
named!(pub string_literal<&[u8], Literal>,
    chain!(
        val: delimited!(opt!(multispace),
                 alt_complete!(
                       delimited!(tag!("\""), opt!(take_until!("\"")), tag!("\""))
                     | delimited!(tag!("'"), opt!(take_until!("'")), tag!("'"))
                 ),
                 opt!(multispace)
              ),
        || {
            let val = val.unwrap_or("".as_bytes());
            let s = String::from(str::from_utf8(val).unwrap());
            Literal::String(s)
        }
    )
);

/// Any literal value.
named!(pub literal<&[u8], Literal>,
    alt_complete!(
          integer_literal
        | string_literal
        | chain!(caseless_tag!("NULL"), || Literal::Null)
        | chain!(caseless_tag!("CURRENT_TIMESTAMP"), || Literal::CurrentTimestamp)
        | chain!(caseless_tag!("CURRENT_DATE"), || Literal::CurrentDate)
        | chain!(caseless_tag!("CURRENT_TIME"), || Literal::CurrentTime)
//        | float_literal
    )
);

/// Parse a list of values (e.g., for INSERT syntax).
named!(pub value_list<&[u8], Vec<Literal> >,
       many0!(
           chain!(
               val: literal ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { val }
           )
       )
);

/// Parse a reference to a named table
/// XXX(malte): add support for schema.table notation
named!(pub table_reference<&[u8], Table>,
    chain!(
        table: map_res!(sql_identifier, str::from_utf8) ~
        alias: opt!(as_alias),
        || {
            Table {
                name: String::from(table),
                alias: match alias {
                    Some(a) => Some(String::from(a)),
                    None => None,
                }
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sql_identifiers() {
        let id1 = b"foo";
        let id2 = b"f_o_o";
        let id3 = b"foo12";
        let id4 = b":fo oo";
        let id5 = b"primary ";
        let id6 = b"`primary`";

        assert!(sql_identifier(id1).is_done());
        assert!(sql_identifier(id2).is_done());
        assert!(sql_identifier(id3).is_done());
        assert!(sql_identifier(id4).is_err());
        assert!(sql_identifier(id5).is_err());
        assert!(sql_identifier(id6).is_done());
    }

    #[test]
    fn simple_column_function() {
        let qs = b"max(addr_id)";

        let res = column_identifier(qs);
        let expected = Column {
            name: String::from("max(addr_id)"),
            alias: None,
            table: None,
            function: Some(Box::new(FunctionExpression::Max(Column::from("addr_id")))),
        };
        assert_eq!(res.unwrap().1, expected);
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(macro_rules, slicing_syntax)]

extern crate curl;
extern crate getopts;
extern crate num;
extern crate "rustc-serialize" as rustc_serialize;
extern crate term;
extern crate time;

use std::error::{Error, FromError};
use std::{fmt, os};
use std::io::{mod, IoResult, File};
use std::io::fs::{mod, PathExtensions};
use std::str::CowString;
use curl::http;
use num::Integer;
use rustc_serialize::{json, Encodable};
use term::{color, Terminal};
use term::color::Color;

type OutputPair<'a> = (Option<Color>, CowString<'a>);

const NSEC_PER_SEC:    u64 = 1000000000;
const NSEC_WARN_LIMIT: u64 = 1  * NSEC_PER_SEC;
const NSEC_NG_LIMIT:   u64 = 10 * NSEC_PER_SEC;

const COLOR_OK:   Color = color::GREEN;
const COLOR_NG:   Color = color::RED;
const COLOR_WARN: Color = color::YELLOW;

pub enum SolverError {
    Io(io::IoError),
    Http(curl::ErrCode)
}

impl FromError<io::IoError> for SolverError {
    fn from_error(err: io::IoError) -> SolverError { SolverError::Io(err) }
}
impl FromError<curl::ErrCode> for SolverError {
    fn from_error(err: curl::ErrCode) -> SolverError { SolverError::Http(err) }
}

impl Error for SolverError {
    fn description(&self) -> &str {
        match *self {
            SolverError::Io(ref err) => err.description(),
            SolverError::Http(ref err) => err.description()
        }
    }

    fn detail(&self) -> Option<String> {
        match *self {
            SolverError::Io(ref err) => err.detail(),
            SolverError::Http(ref err) => err.detail()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            SolverError::Io(ref err) => Some(err as &Error),
            SolverError::Http(ref err) => Some(err as &Error)
        }
    }
}

impl fmt::Show for SolverError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SolverError::Io(ref err) => write!(f, "{}", err),
            SolverError::Http(ref err) => write!(f, "{}", err)
        }
    }
}

#[deriving(Show, RustcEncodable, RustcDecodable)]
pub struct SolverResult<T> {
    pub time: u64,
    pub answer: T,
    pub is_ok: bool
}

impl<'a, T: Encodable<json::Encoder<'a>, io::IoError>> SolverResult<T> {
    pub fn print_json<W: Writer>(&self, out: &mut W) -> IoResult<()> {
        out.write_line(json::encode(self)[])
    }
}

fn print_items(items: &[OutputPair]) {
    match term::stdout() {
        None => {
            let mut out = io::stdout();
            for &(_, ref s) in items.iter() {
                let _ = out.write_str(s.as_slice());
            }
            let _ = out.flush();
        }
        Some(mut t) => {
            for &(c, ref s) in items.iter() {
                match c {
                    Some(c) => {
                        let _ = t.fg(c);
                        let _ = t.write_str(s.as_slice());
                        let _ = t.reset();
                    }
                    None => {
                        let _ = t.write_str(s.as_slice());
                    }
                }
            }
            let _ = t.flush();
        }
    }
}

impl<T: fmt::Show> SolverResult<T> {
    pub fn print_pretty(&self, name: &str, enable_time_color: bool) -> IoResult<()> {
        let mut items = vec![];
        if self.is_ok {
            items.push(normal(format!("{} ", name)));
        } else {
            items.push(normal(format!("{} ", name)));
        }

        items.push(normal("["));
        if self.is_ok {
            items.push(ok("OK"));
        } else {
            items.push(ng("NG"));
        }
        items.push(normal("] "));

        let (sec, nsec) = self.time.div_rem(&NSEC_PER_SEC);
        let time_str = format!("{:3}.{:09} ", sec, nsec);
        if !enable_time_color || self.time < NSEC_WARN_LIMIT {
            items.push(normal(time_str));
        } else if self.time < NSEC_NG_LIMIT {
            items.push(warn(time_str));
        } else {
            items.push(ng(time_str));
        }

        items.push(normal(format!("{} ", self.answer)));

        items.push(normal("\n"));
        print_items(items[]);

        fn normal<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (None, s.into_cow())
        }
        fn ok<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (Some(COLOR_OK), s.into_cow())
        }
        fn warn<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (Some(COLOR_WARN), s.into_cow())
        }
        fn ng<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (Some(COLOR_NG), s.into_cow())
        }

        Ok(())
    }
}

enum SolverFn<'a> {
    FnOnly(fn() -> String),
    FnWithFile(&'a str, fn(File) -> IoResult<String>)
}

pub struct Solver<'a> {
    answer: &'a str,
    solver: SolverFn<'a>
}

impl<'a> Solver<'a> {
    pub fn new(answer: &'a str, solver: fn() -> String) -> Solver<'a> {
        Solver { answer: answer, solver: SolverFn::FnOnly(solver) }
    }

    pub fn new_with_file(
        answer: &'a str, file_name: &'a str, solver: fn(File) -> IoResult<String>
    ) -> Solver<'a> {
        Solver { answer: answer, solver: SolverFn::FnWithFile(file_name, solver) }
    }

    pub fn run(self) {
        let args = os::args();
        let program = &args[0];

        let opts = &[
            getopts::optflag("", "json", "Output JSON format"),
            getopts::optflag("h", "help", "Display this message")
        ];

        let matches = match getopts::getopts(args[1 ..], opts) {
            Ok(m) => m,
            Err(f) => {
                let _ = writeln!(&mut io::stderr(), "{}: {}", program, f);
                os::set_exit_status(255);
                return
            }
        };

        if matches.opt_present("h") {
            let short = getopts::short_usage(program[], opts);
            println!("{}", getopts::usage(short[], opts));
            return
        }

        match self.solve() {
            Err(err) => {
                let _ = writeln!(&mut io::stderr(), "{}: {}", program, err);
                os::set_exit_status(255);
            }
            Ok(result) => {
                if !result.is_ok {
                    os::set_exit_status(1);
                }
                if matches.opt_present("json") {
                    let _ = result.print_json(&mut io::stdout());
                } else {
                    let _ = result.print_pretty(program[], true);
                }
            }
        }
    }

    pub fn solve(&self) -> Result<SolverResult<String>, SolverError> {
        let (time, answer) = match self.solver {
            SolverFn::FnOnly(fun) => bench(move || fun()),
            SolverFn::FnWithFile(file_name, fun) => {
                let file = try!(setup_file(file_name));
                let (time, answer) = bench(move || fun(file));
                (time, try!(answer))
            }
        };

        let result = SolverResult {
            is_ok:  answer[] == self.answer,
            time:   time,
            answer: answer
        };
        Ok(result)
    }
}

fn bench<T, F: FnOnce() -> T>(f: F) -> (u64, T) {
    let start_time = time::precise_time_ns();
    let result     = f();
    let end_time   = time::precise_time_ns();
    let nsec       = end_time - start_time;
    (nsec, result)
}

fn setup_file(file_name: &str) -> Result<File, SolverError> {
    let path = Path::new(format!(".cache/{}", file_name));
    if !path.is_file() {
        let dir_path = path.dir_path();
        try!(fs::mkdir_recursive(&dir_path, io::USER_RWX));
        let mut file = try!(File::create(&path));
        let content = try!(download(file_name));
        try!(file.write(content[]));
    }

    let file = try!(File::open(&path));
    Ok(file)
}

const BASE_URL: &'static str = "https://projecteuler.net/project/resources/";
fn download(file_name: &str) -> Result<Vec<u8>, curl::ErrCode> {
    let url = format!("{}{}", BASE_URL, file_name);
    let resp = try!(http::handle()
                    .get(url)
                    .exec());
    Ok(resp.move_body())
}

#[macro_escape]

#[macro_export]
macro_rules! problem {
    ($answer:expr, $solver:expr) => (
        #[cfg(not(test))]
        fn main() {
            ::common::Solver::new($answer, $solver).run();
        }

        #[test]
        fn test_solve() {
            assert!(::common::Solver::new($answer, $solver).solve().is_ok());
        }
    );
    ($answer:expr, $file:expr, $solver:expr) => (
        #[cfg(not(test))]
        fn main() {
            ::common::Solver::new_with_file($answer, $file, $solver).run();
        }

        #[test]
        fn test_solve() {
            assert!(::common::Solver::new_with_file($answer, $file, $solver).solve().is_ok());
        }
     );
}
<commit_msg>common: fix solve result test<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(macro_rules, slicing_syntax)]

extern crate curl;
extern crate getopts;
extern crate num;
extern crate "rustc-serialize" as rustc_serialize;
extern crate term;
extern crate time;

use std::error::{Error, FromError};
use std::{fmt, os};
use std::io::{mod, IoResult, File};
use std::io::fs::{mod, PathExtensions};
use std::str::CowString;
use curl::http;
use num::Integer;
use rustc_serialize::{json, Encodable};
use term::{color, Terminal};
use term::color::Color;

type OutputPair<'a> = (Option<Color>, CowString<'a>);

const NSEC_PER_SEC:    u64 = 1000000000;
const NSEC_WARN_LIMIT: u64 = 1  * NSEC_PER_SEC;
const NSEC_NG_LIMIT:   u64 = 10 * NSEC_PER_SEC;

const COLOR_OK:   Color = color::GREEN;
const COLOR_NG:   Color = color::RED;
const COLOR_WARN: Color = color::YELLOW;

pub enum SolverError {
    Io(io::IoError),
    Http(curl::ErrCode)
}

impl FromError<io::IoError> for SolverError {
    fn from_error(err: io::IoError) -> SolverError { SolverError::Io(err) }
}
impl FromError<curl::ErrCode> for SolverError {
    fn from_error(err: curl::ErrCode) -> SolverError { SolverError::Http(err) }
}

impl Error for SolverError {
    fn description(&self) -> &str {
        match *self {
            SolverError::Io(ref err) => err.description(),
            SolverError::Http(ref err) => err.description()
        }
    }

    fn detail(&self) -> Option<String> {
        match *self {
            SolverError::Io(ref err) => err.detail(),
            SolverError::Http(ref err) => err.detail()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            SolverError::Io(ref err) => Some(err as &Error),
            SolverError::Http(ref err) => Some(err as &Error)
        }
    }
}

impl fmt::Show for SolverError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SolverError::Io(ref err) => write!(f, "{}", err),
            SolverError::Http(ref err) => write!(f, "{}", err)
        }
    }
}

#[deriving(Show, RustcEncodable, RustcDecodable)]
pub struct SolverResult<T> {
    pub time: u64,
    pub answer: T,
    pub is_ok: bool
}

impl<'a, T: Encodable<json::Encoder<'a>, io::IoError>> SolverResult<T> {
    pub fn print_json<W: Writer>(&self, out: &mut W) -> IoResult<()> {
        out.write_line(json::encode(self)[])
    }
}

fn print_items(items: &[OutputPair]) {
    match term::stdout() {
        None => {
            let mut out = io::stdout();
            for &(_, ref s) in items.iter() {
                let _ = out.write_str(s.as_slice());
            }
            let _ = out.flush();
        }
        Some(mut t) => {
            for &(c, ref s) in items.iter() {
                match c {
                    Some(c) => {
                        let _ = t.fg(c);
                        let _ = t.write_str(s.as_slice());
                        let _ = t.reset();
                    }
                    None => {
                        let _ = t.write_str(s.as_slice());
                    }
                }
            }
            let _ = t.flush();
        }
    }
}

impl<T: fmt::Show> SolverResult<T> {
    pub fn print_pretty(&self, name: &str, enable_time_color: bool) -> IoResult<()> {
        let mut items = vec![];
        if self.is_ok {
            items.push(normal(format!("{} ", name)));
        } else {
            items.push(normal(format!("{} ", name)));
        }

        items.push(normal("["));
        if self.is_ok {
            items.push(ok("OK"));
        } else {
            items.push(ng("NG"));
        }
        items.push(normal("] "));

        let (sec, nsec) = self.time.div_rem(&NSEC_PER_SEC);
        let time_str = format!("{:3}.{:09} ", sec, nsec);
        if !enable_time_color || self.time < NSEC_WARN_LIMIT {
            items.push(normal(time_str));
        } else if self.time < NSEC_NG_LIMIT {
            items.push(warn(time_str));
        } else {
            items.push(ng(time_str));
        }

        items.push(normal(format!("{} ", self.answer)));

        items.push(normal("\n"));
        print_items(items[]);

        fn normal<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (None, s.into_cow())
        }
        fn ok<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (Some(COLOR_OK), s.into_cow())
        }
        fn warn<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (Some(COLOR_WARN), s.into_cow())
        }
        fn ng<'a, T: IntoCow<'a, String, str>>(s: T) -> OutputPair<'a> {
            (Some(COLOR_NG), s.into_cow())
        }

        Ok(())
    }
}

enum SolverFn<'a> {
    FnOnly(fn() -> String),
    FnWithFile(&'a str, fn(File) -> IoResult<String>)
}

pub struct Solver<'a> {
    answer: &'a str,
    solver: SolverFn<'a>
}

impl<'a> Solver<'a> {
    pub fn new(answer: &'a str, solver: fn() -> String) -> Solver<'a> {
        Solver { answer: answer, solver: SolverFn::FnOnly(solver) }
    }

    pub fn new_with_file(
        answer: &'a str, file_name: &'a str, solver: fn(File) -> IoResult<String>
    ) -> Solver<'a> {
        Solver { answer: answer, solver: SolverFn::FnWithFile(file_name, solver) }
    }

    pub fn run(self) {
        let args = os::args();
        let program = &args[0];

        let opts = &[
            getopts::optflag("", "json", "Output JSON format"),
            getopts::optflag("h", "help", "Display this message")
        ];

        let matches = match getopts::getopts(args[1 ..], opts) {
            Ok(m) => m,
            Err(f) => {
                let _ = writeln!(&mut io::stderr(), "{}: {}", program, f);
                os::set_exit_status(255);
                return
            }
        };

        if matches.opt_present("h") {
            let short = getopts::short_usage(program[], opts);
            println!("{}", getopts::usage(short[], opts));
            return
        }

        match self.solve() {
            Err(err) => {
                let _ = writeln!(&mut io::stderr(), "{}: {}", program, err);
                os::set_exit_status(255);
            }
            Ok(result) => {
                if !result.is_ok {
                    os::set_exit_status(1);
                }
                if matches.opt_present("json") {
                    let _ = result.print_json(&mut io::stdout());
                } else {
                    let _ = result.print_pretty(program[], true);
                }
            }
        }
    }

    pub fn solve(&self) -> Result<SolverResult<String>, SolverError> {
        let (time, answer) = match self.solver {
            SolverFn::FnOnly(fun) => bench(move || fun()),
            SolverFn::FnWithFile(file_name, fun) => {
                let file = try!(setup_file(file_name));
                let (time, answer) = bench(move || fun(file));
                (time, try!(answer))
            }
        };

        let result = SolverResult {
            is_ok:  answer[] == self.answer,
            time:   time,
            answer: answer
        };
        Ok(result)
    }
}

fn bench<T, F: FnOnce() -> T>(f: F) -> (u64, T) {
    let start_time = time::precise_time_ns();
    let result     = f();
    let end_time   = time::precise_time_ns();
    let nsec       = end_time - start_time;
    (nsec, result)
}

fn setup_file(file_name: &str) -> Result<File, SolverError> {
    let path = Path::new(format!(".cache/{}", file_name));
    if !path.is_file() {
        let dir_path = path.dir_path();
        try!(fs::mkdir_recursive(&dir_path, io::USER_RWX));
        let mut file = try!(File::create(&path));
        let content = try!(download(file_name));
        try!(file.write(content[]));
    }

    let file = try!(File::open(&path));
    Ok(file)
}

const BASE_URL: &'static str = "https://projecteuler.net/project/resources/";
fn download(file_name: &str) -> Result<Vec<u8>, curl::ErrCode> {
    let url = format!("{}{}", BASE_URL, file_name);
    let resp = try!(http::handle()
                    .get(url)
                    .exec());
    Ok(resp.move_body())
}

#[macro_escape]

#[macro_export]
macro_rules! problem {
    ($answer:expr, $solver:expr) => (
        #[cfg(not(test))]
        fn main() {
            ::common::Solver::new($answer, $solver).run();
        }

        #[test]
        fn test_solve() {
            assert!(::common::Solver::new($answer, $solver).solve().unwrap().is_ok);
        }
    );
    ($answer:expr, $file:expr, $solver:expr) => (
        #[cfg(not(test))]
        fn main() {
            ::common::Solver::new_with_file($answer, $file, $solver).run();
        }

        #[test]
        fn test_solve() {
            assert!(::common::Solver::new_with_file($answer, $file, $solver).solve().unwrap().is_ok);
        }
     );
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::ascii::AsciiExt;
use std::fmt;

use clap::ArgMatches;

use error::{CliErrorKind, CliResult};

trait BoolArg {
    fn parse_arg(&self) -> CliResult<bool>;
}

impl<'a> BoolArg for &'a str {
    fn parse_arg(&self) -> CliResult<bool> {
        match &*self.to_ascii_lowercase() {
            "yes" |
            "true" |
            "y" |
            "t" => Ok(true),
            "no" |
            "false" |
            "n" |
            "f" => Ok(false),
            _ => Err(From::from(CliErrorKind::UnknownBoolArg)),
        }
    }
}

arg_enum! {
    #[derive(Debug, Copy, Clone)]
    pub enum DotLineShape {
        Solid,
        Dotted,
        Dashed
    }
}

impl DotLineShape {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DotLineShape::Solid => Ok(()),
            DotLineShape::Dotted => write!(f, ",style=dotted"),
            DotLineShape::Dashed => write!(f, ",style=dashed"),
        }
    }
}

arg_enum!{
    #[derive(Debug, Copy, Clone)]
    pub enum DotColor {
        Blue,
        Green,
        Red,
        Yellow,
        White,
        Black,
        Purple,
        Orange
    }
}

impl DotColor {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DotColor::Blue => write!(f, ",color=blue"),
            DotColor::Green => write!(f, ",color=green"),
            DotColor::Red => write!(f, ",color=red"),
            DotColor::Yellow => write!(f, ",color=yellow"),
            DotColor::White => write!(f, ",color=white"),
            DotColor::Black => Ok(()),
            DotColor::Purple => write!(f, ",color=purple"),
            DotColor::Orange => write!(f, ",color=orange"),
        }
    }
}

arg_enum!{
    #[derive(Debug, Copy, Clone)]
    pub enum DotShape {
        Box,
        Round,
        Diamond,
        Triangle
    }
}

impl DotShape {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DotShape::Round => Ok(()),
            DotShape::Box => write!(f, ",shape=box"),
            DotShape::Diamond => write!(f, ",shape=diamond"),
            DotShape::Triangle => write!(f, ",shape=triangle"),
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct DepStyle(DotShape, DotColor);

impl fmt::Display for DepStyle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(self.0.write(f));
        self.1.write(f)
    }
}

#[derive(Debug, Copy, Clone)]
pub struct LineStyle(DotLineShape, DotColor);

impl fmt::Display for LineStyle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(self.0.write(f));
        self.1.write(f)
    }
}

#[derive(Debug)]
pub struct Config<'a> {
    pub lock_file: &'a str,
    pub manifest_file: &'a str,
    pub dot_file: Option<&'a str>,
    pub dev_lines: LineStyle,
    pub build_lines: LineStyle,
    pub optional_lines: LineStyle,
    pub dev_deps: bool,
    pub build_deps: bool,
    pub optional_deps: bool,
    pub build_style: DepStyle,
    pub dev_style: DepStyle,
    pub optional_style: DepStyle,
    pub include_vers: bool,
}

impl<'a> Config<'a> {
    #[cfg_attr(feature = "lints", allow(cyclomatic_complexity))]
    pub fn from_matches(m: &'a ArgMatches) -> CliResult<Self> {
        Ok(Config {
            lock_file: m.value_of("lock-file").unwrap_or("Cargo.lock"),
            manifest_file: m.value_of("manifest-file").unwrap_or("Cargo.toml"),
            dot_file: m.value_of("dot-file"),
            dev_deps: try!(m.value_of("dev-deps").unwrap_or("false").parse_arg()),
            build_deps: try!(m.value_of("build-deps").unwrap_or("true").parse_arg()),
            optional_deps: try!(m.value_of("optional-deps").unwrap_or("true").parse_arg()),
            build_lines: LineStyle(value_t!(m.value_of("build-line-style"), DotLineShape)
                                       .unwrap_or(DotLineShape::Solid),
                                   value_t!(m.value_of("build-line-color"), DotColor)
                                       .unwrap_or(DotColor::Black)),
            optional_lines: LineStyle(value_t!(m.value_of("optional-line-style"), DotLineShape)
                                          .unwrap_or(DotLineShape::Solid),
                                      value_t!(m.value_of("optional-line-color"), DotColor)
                                          .unwrap_or(DotColor::Black)),
            dev_lines: LineStyle(value_t!(m.value_of("dev-line-style"), DotLineShape)
                                     .unwrap_or(DotLineShape::Solid),
                                 value_t!(m.value_of("dev-line-color"), DotColor)
                                     .unwrap_or(DotColor::Black)),
            build_style: DepStyle(value_t!(m.value_of("build-shape"), DotShape)
                                      .unwrap_or(DotShape::Round),
                                  value_t!(m.value_of("build-color"), DotColor)
                                      .unwrap_or(DotColor::Black)),
            optional_style: DepStyle(value_t!(m.value_of("optional-shape"), DotShape)
                                         .unwrap_or(DotShape::Round),
                                     value_t!(m.value_of("optional-color"), DotColor)
                                         .unwrap_or(DotColor::Black)),
            dev_style: DepStyle(value_t!(m.value_of("dev-shape"), DotShape)
                                    .unwrap_or(DotShape::Round),
                                value_t!(m.value_of("dev-color"), DotColor)
                                    .unwrap_or(DotColor::Black)),
            include_vers: m.is_present("include-versions"),
        })
    }
}
<commit_msg>style: fix unused import warning in src/config.rs<commit_after>use std::ascii::AsciiExt;
use std::fmt;

use clap::ArgMatches;

use error::{CliErrorKind, CliResult};

trait BoolArg {
    fn parse_arg(&self) -> CliResult<bool>;
}

impl<'a> BoolArg for &'a str {
    fn parse_arg(&self) -> CliResult<bool> {
        match &*self.to_ascii_lowercase() {
            "yes" |
            "true" |
            "y" |
            "t" => Ok(true),
            "no" |
            "false" |
            "n" |
            "f" => Ok(false),
            _ => Err(From::from(CliErrorKind::UnknownBoolArg)),
        }
    }
}

arg_enum! {
    #[derive(Debug, Copy, Clone)]
    pub enum DotLineShape {
        Solid,
        Dotted,
        Dashed
    }
}

impl DotLineShape {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DotLineShape::Solid => Ok(()),
            DotLineShape::Dotted => write!(f, ",style=dotted"),
            DotLineShape::Dashed => write!(f, ",style=dashed"),
        }
    }
}

arg_enum!{
    #[derive(Debug, Copy, Clone)]
    pub enum DotColor {
        Blue,
        Green,
        Red,
        Yellow,
        White,
        Black,
        Purple,
        Orange
    }
}

impl DotColor {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DotColor::Blue => write!(f, ",color=blue"),
            DotColor::Green => write!(f, ",color=green"),
            DotColor::Red => write!(f, ",color=red"),
            DotColor::Yellow => write!(f, ",color=yellow"),
            DotColor::White => write!(f, ",color=white"),
            DotColor::Black => Ok(()),
            DotColor::Purple => write!(f, ",color=purple"),
            DotColor::Orange => write!(f, ",color=orange"),
        }
    }
}

arg_enum!{
    #[derive(Debug, Copy, Clone)]
    pub enum DotShape {
        Box,
        Round,
        Diamond,
        Triangle
    }
}

impl DotShape {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DotShape::Round => Ok(()),
            DotShape::Box => write!(f, ",shape=box"),
            DotShape::Diamond => write!(f, ",shape=diamond"),
            DotShape::Triangle => write!(f, ",shape=triangle"),
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct DepStyle(DotShape, DotColor);

impl fmt::Display for DepStyle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(self.0.write(f));
        self.1.write(f)
    }
}

#[derive(Debug, Copy, Clone)]
pub struct LineStyle(DotLineShape, DotColor);

impl fmt::Display for LineStyle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(self.0.write(f));
        self.1.write(f)
    }
}

#[derive(Debug)]
pub struct Config<'a> {
    pub lock_file: &'a str,
    pub manifest_file: &'a str,
    pub dot_file: Option<&'a str>,
    pub dev_lines: LineStyle,
    pub build_lines: LineStyle,
    pub optional_lines: LineStyle,
    pub dev_deps: bool,
    pub build_deps: bool,
    pub optional_deps: bool,
    pub build_style: DepStyle,
    pub dev_style: DepStyle,
    pub optional_style: DepStyle,
    pub include_vers: bool,
}

impl<'a> Config<'a> {
    #[cfg_attr(feature = "lints", allow(cyclomatic_complexity))]
    pub fn from_matches(m: &'a ArgMatches) -> CliResult<Self> {
        Ok(Config {
            lock_file: m.value_of("lock-file").unwrap_or("Cargo.lock"),
            manifest_file: m.value_of("manifest-file").unwrap_or("Cargo.toml"),
            dot_file: m.value_of("dot-file"),
            dev_deps: try!(m.value_of("dev-deps").unwrap_or("false").parse_arg()),
            build_deps: try!(m.value_of("build-deps").unwrap_or("true").parse_arg()),
            optional_deps: try!(m.value_of("optional-deps").unwrap_or("true").parse_arg()),
            build_lines: LineStyle(value_t!(m.value_of("build-line-style"), DotLineShape)
                                       .unwrap_or(DotLineShape::Solid),
                                   value_t!(m.value_of("build-line-color"), DotColor)
                                       .unwrap_or(DotColor::Black)),
            optional_lines: LineStyle(value_t!(m.value_of("optional-line-style"), DotLineShape)
                                          .unwrap_or(DotLineShape::Solid),
                                      value_t!(m.value_of("optional-line-color"), DotColor)
                                          .unwrap_or(DotColor::Black)),
            dev_lines: LineStyle(value_t!(m.value_of("dev-line-style"), DotLineShape)
                                     .unwrap_or(DotLineShape::Solid),
                                 value_t!(m.value_of("dev-line-color"), DotColor)
                                     .unwrap_or(DotColor::Black)),
            build_style: DepStyle(value_t!(m.value_of("build-shape"), DotShape)
                                      .unwrap_or(DotShape::Round),
                                  value_t!(m.value_of("build-color"), DotColor)
                                      .unwrap_or(DotColor::Black)),
            optional_style: DepStyle(value_t!(m.value_of("optional-shape"), DotShape)
                                         .unwrap_or(DotShape::Round),
                                     value_t!(m.value_of("optional-color"), DotColor)
                                         .unwrap_or(DotColor::Black)),
            dev_style: DepStyle(value_t!(m.value_of("dev-shape"), DotShape)
                                    .unwrap_or(DotShape::Round),
                                value_t!(m.value_of("dev-color"), DotColor)
                                    .unwrap_or(DotColor::Black)),
            include_vers: m.is_present("include-versions"),
        })
    }
}
<|endoftext|>


<commit_before>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) | Err(Ignored(s)) | Err(Mismatch(s)) | Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(
    env: &Env,
    type_id: library::TypeId,
    nullable: Nullable,
    ref_mode: RefMode,
) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Short => ok("libc::c_short"),   //depends of target system
                UShort => ok("libc::c_ushort"), //depends of target system
                Long => ok("libc::c_long"),     //depends of target system
                ULong => ok("libc::c_ulong"),   //depends of target system

                Size => ok("usize"),     //depends of target system
                SSize => ok("isize"),    //depends of target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => {
                    if ref_mode.is_ref() {
                        ok("str")
                    } else {
                        ok("String")
                    }
                }
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    } else {
                        ok("std::path::PathBuf")
                    }
                }
                Type if env.namespaces.glib_ns_id == library::MAIN_NAMESPACE => ok("types::Type"),
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        }
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode).map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() {
                ok("VariantTy")
            } else {
                ok("VariantType")
            }
        }
        Enumeration(..) | Bitfield(..) | Record(..) | Union(..) | Class(..) | Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            } else {
                Ok(name)
            }
        }
        List(inner_tid) | SList(inner_tid) | CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) | Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE &&
        !implemented_in_main_namespace(&env.library, type_id)
    {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| {
            format!("{}::{}", env.namespaces[type_id.ns_id].higher_crate_name, s)
        });
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => {
            rust_type = rust_type.map_any(|s| format!("&{}", s))
        }
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
        Fundamental(library::Fundamental::Short) |
        Fundamental(library::Fundamental::UShort) |
        Fundamental(library::Fundamental::Long) |
        Fundamental(library::Fundamental::ULong) |
        Fundamental(library::Fundamental::Filename) |
        Alias(..) |
        Bitfield(..) |
        Record(..) |
        Union(..) |
        Class(..) |
        Enumeration(..) |
        Interface(..) => rust_type(env, type_id),
        List(inner_tid) | SList(inner_tid) | CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(
    env: &Env,
    type_id: library::TypeId,
    direction: library::ParameterDirection,
    nullable: Nullable,
    ref_mode: RefMode,
) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                if direction == library::ParameterDirection::InOut ||
                    (direction == library::ParameterDirection::Out &&
                         ref_mode == RefMode::ByRefMut)
                {
                    return Err(TypeError::Unimplemented(into_inner(rust_type)));
                }
            }
            rust_type.map_any(|s| format_parameter(s, direction))
        }

        Alias(ref alias) => {
            rust_type
                .and_then(|s| {
                    parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                        .map_any(|_| s)
                })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) | Union(..) | Bitfield(..) => {
            rust_type.map_any(|s| format_parameter(s, direction))
        }

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) | Interface(..) => {
            match direction {
                library::ParameterDirection::In |
                library::ParameterDirection::Out |
                library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) | SList(..) | CArray(..) => {
            match direction {
                library::ParameterDirection::In | library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

//TODO: remove
fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    type_id.full_name(library) == "GLib.Error"
}
<commit_msg>Add support for arrays of fundamental types<commit_after>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) | Err(Ignored(s)) | Err(Mismatch(s)) | Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(
    env: &Env,
    type_id: library::TypeId,
    nullable: Nullable,
    ref_mode: RefMode,
) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Short => ok("libc::c_short"),   //depends of target system
                UShort => ok("libc::c_ushort"), //depends of target system
                Long => ok("libc::c_long"),     //depends of target system
                ULong => ok("libc::c_ulong"),   //depends of target system

                Size => ok("usize"),     //depends of target system
                SSize => ok("isize"),    //depends of target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => {
                    if ref_mode.is_ref() {
                        ok("str")
                    } else {
                        ok("String")
                    }
                }
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    } else {
                        ok("std::path::PathBuf")
                    }
                }
                Type if env.namespaces.glib_ns_id == library::MAIN_NAMESPACE => ok("types::Type"),
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        }
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode).map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() {
                ok("VariantTy")
            } else {
                ok("VariantType")
            }
        }
        Enumeration(..) | Bitfield(..) | Record(..) | Union(..) | Class(..) | Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            } else {
                Ok(name)
            }
        }
        List(inner_tid) | SList(inner_tid) | CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) | Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        CArray(inner_tid) if ConversionType::of(&env.library, inner_tid) == ConversionType::Direct => {
            if let Fundamental(fund) = *env.library.type_(inner_tid) {
                let array_type = match fund {
                    Int8 => Some("i8"),
                    UInt8 => Some("u8"),
                    Int16 => Some("i16"),
                    UInt16 => Some("u16"),
                    Int32 => Some("i32"),
                    UInt32 => Some("u32"),
                    Int64 => Some("i64"),
                    UInt64 => Some("u64"),

                    Int => Some("i32"),      //maybe dependent on target system
                    UInt => Some("u32"),     //maybe dependent on target system

                    Float => Some("f32"),
                    Double => Some("f64"),
                    _ => Option::None,
                };

                if let Some(s) = array_type {
                    skip_option = true;
                    if ref_mode.is_ref() {
                        Ok(format!("[{}]", s))
                    } else {
                        Ok(format!("Vec<{}>", s))
                    }
                } else {
                    Err(TypeError::Unimplemented(type_.get_name().to_owned()))
                }
            } else {
                Err(TypeError::Unimplemented(type_.get_name().to_owned()))
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE &&
        !implemented_in_main_namespace(&env.library, type_id)
    {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| {
            format!("{}::{}", env.namespaces[type_id.ns_id].higher_crate_name, s)
        });
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => {
            rust_type = rust_type.map_any(|s| format!("&{}", s))
        }
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
        Fundamental(library::Fundamental::Short) |
        Fundamental(library::Fundamental::UShort) |
        Fundamental(library::Fundamental::Long) |
        Fundamental(library::Fundamental::ULong) |
        Fundamental(library::Fundamental::Filename) |
        Alias(..) |
        Bitfield(..) |
        Record(..) |
        Union(..) |
        Class(..) |
        Enumeration(..) |
        Interface(..) => rust_type(env, type_id),
        List(inner_tid) | SList(inner_tid) | CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(
    env: &Env,
    type_id: library::TypeId,
    direction: library::ParameterDirection,
    nullable: Nullable,
    ref_mode: RefMode,
) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                if direction == library::ParameterDirection::InOut ||
                    (direction == library::ParameterDirection::Out &&
                         ref_mode == RefMode::ByRefMut)
                {
                    return Err(TypeError::Unimplemented(into_inner(rust_type)));
                }
            }
            rust_type.map_any(|s| format_parameter(s, direction))
        }

        Alias(ref alias) => {
            rust_type
                .and_then(|s| {
                    parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                        .map_any(|_| s)
                })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) | Union(..) | Bitfield(..) => {
            rust_type.map_any(|s| format_parameter(s, direction))
        }

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) | Interface(..) => {
            match direction {
                library::ParameterDirection::In |
                library::ParameterDirection::Out |
                library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) | SList(..) | CArray(..) => {
            match direction {
                library::ParameterDirection::In | library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

//TODO: remove
fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    type_id.full_name(library) == "GLib.Error"
}
<|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 types::{Sectors, SectorOffset};

pub const REDUNDANCY: usize = 1;
pub const MIN_BLK_DEVS: usize = 2;

// Before increasing, either check if md-raid is good for wider, or
// change zone creation to limit width
pub const MAX_BLK_DEVS: usize = 8;

pub const SECTOR_SIZE: u64 = 512;
pub const HEADER_SIZE: u64 = 512;
pub const MDA_ZONE_SIZE: u64 = (1024 * 1024);
pub const MDA_ZONE_SECTORS: Sectors = Sectors::new(MDA_ZONE_SIZE / SECTOR_SIZE);
pub const MDAX_ZONE_SECTORS: Sectors = Sectors::new(1020);
pub const MDAA_ZONE_OFFSET: SectorOffset = SectorOffset::new(8);
pub const MDAB_ZONE_OFFSET: SectorOffset = SectorOffset::new(1028);

pub const FRO_MAGIC: &'static [u8] = b"!IamFroy0\x86\xffGO\x02^\x41";
pub const STRIPE_SECTORS: Sectors = Sectors::new(2048);

// No devs smaller than around a gig
const MIN_DATA_ZONE_SIZE: u64 = (1024 * 1024 * 1024);
pub const MIN_DATA_ZONE_SECTORS: Sectors = Sectors::new(MIN_DATA_ZONE_SIZE / SECTOR_SIZE);
pub const MIN_DEV_SIZE: u64 = MIN_DATA_ZONE_SIZE + (2 * MDA_ZONE_SIZE);

// But also no larger than 1 TiB
const MAX_DATA_ZONE_SIZE: u64 = (1024 * 1024 * 1024 * 1024);
pub const MAX_DATA_ZONE_SECTORS: Sectors = Sectors::new(MAX_DATA_ZONE_SIZE / SECTOR_SIZE);

//const MIN_DEV_SECTORS: u64 = MIN_DEV_SIZE / SECTOR_SIZE;

pub const MAX_REGIONS: u64 = (2 * 1024 * 1024);
const DEFAULT_REGION_SIZE: u64 = (4 * 1024 * 1024);
pub const DEFAULT_REGION_SECTORS: Sectors = Sectors::new(DEFAULT_REGION_SIZE / SECTOR_SIZE);

// Try to create this many raids in a Froyodev. Too many is wasteful
// but too few limits reshape options (at least until dn-raid supports
// reshape)
pub const IDEAL_RAID_COUNT: usize = 10;
<commit_msg>consts: Define MEGA, GIGA, and TERA<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 types::{Sectors, SectorOffset};

pub const REDUNDANCY: usize = 1;
pub const MIN_BLK_DEVS: usize = 2;

const MEGA: u64 = 1024 * 1024;
const GIGA: u64 = MEGA * 1024;
const TERA: u64 = GIGA * 1024;

// Before increasing, either check if md-raid is good for wider, or
// change zone creation to limit width
pub const MAX_BLK_DEVS: usize = 8;

pub const SECTOR_SIZE: u64 = 512;
pub const HEADER_SIZE: u64 = 512;
pub const MDA_ZONE_SIZE: u64 = MEGA;
pub const MDA_ZONE_SECTORS: Sectors = Sectors::new(MDA_ZONE_SIZE / SECTOR_SIZE);
pub const MDAX_ZONE_SECTORS: Sectors = Sectors::new(1020);
pub const MDAA_ZONE_OFFSET: SectorOffset = SectorOffset::new(8);
pub const MDAB_ZONE_OFFSET: SectorOffset = SectorOffset::new(1028);

pub const FRO_MAGIC: &'static [u8] = b"!IamFroy0\x86\xffGO\x02^\x41";
pub const STRIPE_SECTORS: Sectors = Sectors::new(2048);

// No devs smaller than around a gig
const MIN_DATA_ZONE_SIZE: u64 = GIGA;
pub const MIN_DATA_ZONE_SECTORS: Sectors = Sectors::new(MIN_DATA_ZONE_SIZE / SECTOR_SIZE);
pub const MIN_DEV_SIZE: u64 = MIN_DATA_ZONE_SIZE + (2 * MDA_ZONE_SIZE);

// But also no larger than 1 TiB
const MAX_DATA_ZONE_SIZE: u64 = TERA;
pub const MAX_DATA_ZONE_SECTORS: Sectors = Sectors::new(MAX_DATA_ZONE_SIZE / SECTOR_SIZE);

//const MIN_DEV_SECTORS: u64 = MIN_DEV_SIZE / SECTOR_SIZE;

pub const MAX_REGIONS: u64 = (2 * MEGA);
const DEFAULT_REGION_SIZE: u64 = (4 * MEGA);
pub const DEFAULT_REGION_SECTORS: Sectors = Sectors::new(DEFAULT_REGION_SIZE / SECTOR_SIZE);

// Try to create this many raids in a Froyodev. Too many is wasteful
// but too few limits reshape options (at least until dn-raid supports
// reshape)
pub const IDEAL_RAID_COUNT: usize = 10;
<|endoftext|>


<commit_before>use CreationError;
use CreationError::OsError;
use BuilderAttribs;
use GlContext;
use libc;
use std::ptr;

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
use cocoa::base::{id, nil};
use cocoa::appkit::*;

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

static mut framebuffer: u32 = 0;
static mut texture: u32 = 0;

pub struct HeadlessContext {
    width: u32,
    height: u32,
    context: id,
}

impl HeadlessContext {
    pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        let (width, height) = builder.dimensions.unwrap_or((1024, 768));
        let context = unsafe {
            let attributes = [
                NSOpenGLPFAAccelerated as u32,
                NSOpenGLPFAAllowOfflineRenderers as u32,
                NSOpenGLPFADoubleBuffer as u32,
                0
            ];

            let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes);
            if pixelformat == nil {
                return Err(OsError(format!("Could not create the pixel format")));
            }
            let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                return Err(OsError(format!("Could not create the rendering context")));
            }
            context
        };

        let headless = HeadlessContext {
            width: width,
            height: height,
            context: context,
        };

        // Load the function pointers as we need them to create the FBO
        gl::load_with(|s| headless.get_proc_address(s) as *const libc::c_void);

        Ok(headless)
    }
}

impl GlContext for HeadlessContext {
    unsafe fn make_current(&self) {
        self.context.makeCurrentContext();

        gl::GenFramebuffersEXT(1, &mut framebuffer);
        gl::BindFramebufferEXT(gl::FRAMEBUFFER_EXT, framebuffer);
        gl::GenTextures(1, &mut texture);
        gl::BindTexture(gl::TEXTURE_2D, texture);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA8 as i32, self.width as i32, self.height as i32,
                       0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null());
        gl::FramebufferTexture2DEXT(gl::FRAMEBUFFER_EXT, gl::COLOR_ATTACHMENT0_EXT,
                                    gl::TEXTURE_2D, texture, 0);
        let status = gl::CheckFramebufferStatusEXT(gl::FRAMEBUFFER_EXT);
        if status != gl::FRAMEBUFFER_COMPLETE_EXT {
            panic!("Error while creating the framebuffer");
        }
    }

    fn is_current(&self) -> bool {
        unimplemented!()
    }

    fn get_proc_address(&self, _addr: &str) -> *const () {
        let symbol_name: CFString = _addr.parse().unwrap();
        let framework_name: CFString = "com.apple.opengl".parse().unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const ()
    }

    fn swap_buffers(&self) {
    }

    fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    fn get_pixel_format(&self) -> PixelFormat {
        unimplemented!();
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl Drop for HeadlessContext {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &texture);
            gl::DeleteFramebuffersEXT(1, &framebuffer);
        }
    }
}
<commit_msg>Fix compiler errors on OSX<commit_after>use CreationError;
use CreationError::OsError;
use BuilderAttribs;
use GlContext;
use libc;
use std::ptr;

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
use cocoa::base::{id, nil};
use cocoa::appkit::*;
use PixelFormat;

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

static mut framebuffer: u32 = 0;
static mut texture: u32 = 0;

pub struct HeadlessContext {
    width: u32,
    height: u32,
    context: id,
}

impl HeadlessContext {
    pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        let (width, height) = builder.dimensions.unwrap_or((1024, 768));
        let context = unsafe {
            let attributes = [
                NSOpenGLPFAAccelerated as u32,
                NSOpenGLPFAAllowOfflineRenderers as u32,
                NSOpenGLPFADoubleBuffer as u32,
                0
            ];

            let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes);
            if pixelformat == nil {
                return Err(OsError(format!("Could not create the pixel format")));
            }
            let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                return Err(OsError(format!("Could not create the rendering context")));
            }
            context
        };

        let headless = HeadlessContext {
            width: width,
            height: height,
            context: context,
        };

        // Load the function pointers as we need them to create the FBO
        gl::load_with(|s| headless.get_proc_address(s) as *const libc::c_void);

        Ok(headless)
    }
}

impl GlContext for HeadlessContext {
    unsafe fn make_current(&self) {
        self.context.makeCurrentContext();

        gl::GenFramebuffersEXT(1, &mut framebuffer);
        gl::BindFramebufferEXT(gl::FRAMEBUFFER_EXT, framebuffer);
        gl::GenTextures(1, &mut texture);
        gl::BindTexture(gl::TEXTURE_2D, texture);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA8 as i32, self.width as i32, self.height as i32,
                       0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null());
        gl::FramebufferTexture2DEXT(gl::FRAMEBUFFER_EXT, gl::COLOR_ATTACHMENT0_EXT,
                                    gl::TEXTURE_2D, texture, 0);
        let status = gl::CheckFramebufferStatusEXT(gl::FRAMEBUFFER_EXT);
        if status != gl::FRAMEBUFFER_COMPLETE_EXT {
            panic!("Error while creating the framebuffer");
        }
    }

    fn is_current(&self) -> bool {
        unimplemented!()
    }

    fn get_proc_address(&self, _addr: &str) -> *const libc::c_void {
        let symbol_name: CFString = _addr.parse().unwrap();
        let framework_name: CFString = "com.apple.opengl".parse().unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const libc::c_void
    }

    fn swap_buffers(&self) {
    }

    fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    fn get_pixel_format(&self) -> PixelFormat {
        unimplemented!();
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl Drop for HeadlessContext {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &texture);
            gl::DeleteFramebuffersEXT(1, &framebuffer);
        }
    }
}
<|endoftext|>