<commit_before>extern crate rocket;

use rocket::request::{FromForm, FormItems};

pub struct StatementStructResult {sql: String}
pub struct WhereStructResult {
    sql: String, values: Vec<String>,
}

// My Results
type QueryOpResult = Result<&'static str, String>;
type StatementResult = Result<StatementStructResult, String>;
type WhereResult = Result<WhereStructResult, String>;

// TODO: Move there later
pub struct Params {
    pub k: String, pub v: String,
}
// implement QueryString
pub struct QueryString {
    pub query: Vec<Params>
}

impl<'f> FromForm<'f> for QueryString {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<QueryString, ()> {
        let mut qs: QueryString = QueryString{ query: Vec::new() };
        for (k, v) in items {
            qs.query.push(Params{k: k.to_string(), v: v.url_decode().unwrap()});
        }
        Ok(qs)
    }
}

pub fn query_operator(qop: &str) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("="),
        "$ne" => Ok("!="),
        "$gt" => Ok(">"),
        "$lt" => Ok("<"),
        "$gte" => Ok(">="),
        "$lte" => Ok("<="),
        "$in" => Ok("IN"),
        "$nin" => Ok("NOT IN"),
        "$notnull" => Ok("IS NOT NULL"),
        "$null" => Ok("IS NULL"),
         _ => Err(format!("operator {} not found", qop)),
    }
}

fn collect_params(v: &Vec<Params>, collect_values: bool) -> Result<Vec<String>,String> {
    let mut pid: i32 = 0;
    v.iter()
        .map(|param| {
            pid = pid + 1;
            let result = match param.v.contains(".") {
                true => {
                    let value_splited = param.v.split(".").collect::<Vec<&str>>();
                    let operator = match query_operator(value_splited[0]) {
                        Ok(op) => op,
                        Err(e) => return Err(e)
                    };
                    (operator, value_splited[1])
                },
                _ => ("=", param.v.as_str())
            };
            if collect_values {
                Ok(format!("{}", result.1))
            } else {
                Ok(format!("{}{}${}", param.k, result.0, pid))
            }
        })
        .collect()
}

// Get QueryString and return SELECT statement
pub fn ext_select(qs: QueryString) -> StatementResult {
    let mut select_syntax: String = "SELECT * FROM".to_string();
    let select_param = qs.query.iter().find(|param| param.k == "_select".to_string());
    let columns = match select_param {
        Some(param) => &param.v,
        _ => return Err("".to_string())
    };

    // empty string means that isn't `_select` command
    if columns != "" {
        select_syntax = format!("SELECT {} FROM", columns);
    }

    Ok(StatementStructResult{ sql: select_syntax })
}

// Get QueryString and return COUNT clause statement
pub fn ext_count(qs: QueryString) -> StatementResult {
    let mut count_syntax: String = String::new();
    let count_param = qs.query.iter().find(|param| param.k == "_count".to_string());
    let columns = match count_param {
        Some(param)=> {
            let vsplited = &param.v.split(",").collect::<Vec<&str>>();
            // FIXME, How to improve it?
            let u :usize = 2;
            if vsplited.len() >= u {
                return Err("could not use more than one column in count function".to_string())
            }
            &param.v
        },
        _ => return Err("".to_string())
    };

    if columns != "" {
        count_syntax = format!("SELECT COUNT({}) FROM", columns);
    }
    Ok(StatementStructResult{ sql: count_syntax })
}

// Get QueryString and return chunck WHERE statement with values
pub fn ext_where(qs: QueryString) -> WhereResult {
    let where_syntax: String;
    let ref iter_params = qs.query;
    let where_values = match collect_params(iter_params, true) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string())
    };
    let where_fields = match collect_params(iter_params, false) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string())
    };

    if where_fields.len() > 1 {
        where_syntax = format!("WHERE {}", where_fields.join(" AND "));
    } else {
        where_syntax = format!("WHERE {}", where_fields.join(" "));
    }

    Ok(WhereStructResult {
        sql: where_syntax,
        values: where_values
    })
}

// Get QueryString and return chunk ORDER BY statement
pub fn ext_order(qs: QueryString) -> StatementResult {
    let mut order_syntax: String = String::new();
    let order_params = qs.query.iter().find(|param| param.k == "_order".to_string());
    let columns = match order_params {
        Some(param) => {
            // need some refactor after!
            let vspl = &param.v.split(",").map(|s| s.to_string()).collect::<Vec<String>>();
            let od: Vec<String> = vspl.iter().map(|param| {
                let mut s = String::new();
                s.push_str(param); // omg
                if s.starts_with("-") {
                    s.remove(0);
                    s.push_str(" DESC")
                }
                format!("{}", s)
            }).collect();
            format!("{}", od.join(","))
        },
        _ => return Err("".to_string())
    };

    if columns != "" {
        order_syntax = format!("ORDER BY {}", columns);
    }
    Ok(StatementStructResult{ sql: order_syntax })
}

// Get QueryString and return chunk GROUP BY statement
pub fn ext_groupby(qs: QueryString) -> StatementResult {
    let mut groupby_syntax: String = String::new();
    let groupby_params = qs.query.iter().find(|param| param.k == String::from("_groupby"));
    let columns = match groupby_params {
        Some(param) => &param.v,
        _ => return Err(String::from(""))
    };

    if columns != "" {
        groupby_syntax = format!("GROUP BY {}", columns);
    }
    Ok(StatementStructResult{ sql: groupby_syntax })
}

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

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e)
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e)
        }
    }

    #[test]
    fn where_by_request_one_querystring() {
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "5".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_where(qs)
            .unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_n_querystring() {
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "5".to_string()});
        hm.push(Params{k: "name".to_string(), v: "goga".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_where(qs)
            .unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_operators(){
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "$ne.5".to_string()});
        hm.push(Params{k: "name".to_string(), v: "goga".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_where(qs)
            .unwrap();
        assert_eq!(result.sql, "WHERE user_id!=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_invalid_operators(){
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "$nt.5".to_string()});
        hm.push(Params{k: "name".to_string(), v: "goga".to_string()});

        let qs = QueryString{ query: hm };
        match ext_where(qs) {
            Err(e) => assert_eq!(e, "operator $nt not found"),
            Ok(_) => println!("no result")
        }
    }

    #[test]
    fn select_by_request_one_column() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_select".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_select(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT name FROM");
    }

    #[test]
    fn select_by_request_n_column() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_select".to_string(), v: "name,age".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_select(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT name,age FROM");
    }

    #[test]
    fn select_by_request_n_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_select".to_string(), v: "".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_select(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT * FROM");
    }

    #[test]
    fn count_by_request() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_count(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT COUNT(name) FROM");
    }

    #[test]
    fn count_by_request_all_fields() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "*".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_count(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT COUNT(*) FROM");
    }

    #[test]
    fn count_by_request_two_fields() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "name,age".to_string()});

        let qs = QueryString{ query: hm };
        match ext_count(qs) {
            Err(e) => assert_eq!(e, "could not use more than one column in count function"),
            Ok(_) => println!("no result")
        }
    }

    #[test]
    fn count_by_request_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_count(qs)
            .unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name")
    }

    #[test]
    fn order_by_request_desc() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "-name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name DESC")
    }

    #[test]
    fn order_by_request_empty_params() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request_multiples_columns() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "name,age".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name,age")
    }

    #[test]
    fn order_by_request_multiples_columns_with_orders() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "name,-age".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name,age DESC")
    }

    #[test]
    fn groupby_by_request() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_groupby".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_groupby(qs)
            .unwrap();
        assert_eq!(result.sql, "GROUP BY name")
    }

    #[test]
    fn groupby_by_request_empty_param() {
        let mut hm = Vec::new();
        hm.push(Params{k: String::from("_groupby"), v: String::from("")});

        let qs = QueryString{ query: hm };
        let result = ext_groupby(qs)
            .unwrap();
        assert_eq!(result.sql, "")
    }
}
<commit_msg>Refactor in statements<commit_after>extern crate rocket;

use rocket::request::{FromForm, FormItems};

#[derive(Debug)]
pub struct StatementStructResult {sql: String}
pub struct WhereStructResult {
    sql: String, values: Vec<String>,
}

// My Results
type QueryOpResult = Result<&'static str, String>;
type StatementResult = Result<StatementStructResult, String>;
type WhereResult = Result<WhereStructResult, String>;

// TODO: Move there later
pub struct Params {
    pub k: String, pub v: String,
}
// implement QueryString
pub struct QueryString {
    pub query: Vec<Params>
}

impl<'f> FromForm<'f> for QueryString {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<QueryString, ()> {
        let mut qs: QueryString = QueryString{ query: Vec::new() };
        for (k, v) in items {
            qs.query.push(Params{k: k.to_string(), v: v.url_decode().unwrap()});
        }
        Ok(qs)
    }
}

pub fn query_operator(qop: &str) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("="),
        "$ne" => Ok("!="),
        "$gt" => Ok(">"),
        "$lt" => Ok("<"),
        "$gte" => Ok(">="),
        "$lte" => Ok("<="),
        "$in" => Ok("IN"),
        "$nin" => Ok("NOT IN"),
        "$notnull" => Ok("IS NOT NULL"),
        "$null" => Ok("IS NULL"),
         _ => Err(format!("operator {} not found", qop)),
    }
}

fn collect_params(v: &Vec<Params>, collect_values: bool) -> Result<Vec<String>,String> {
    let mut pid: i32 = 0;
    v.iter()
        .map(|param| {
            pid = pid + 1;
            let result = match param.v.contains(".") {
                true => {
                    let value_splited = param.v.split(".").collect::<Vec<&str>>();
                    let operator = match query_operator(value_splited[0]) {
                        Ok(op) => op,
                        Err(e) => return Err(e)
                    };
                    (operator, value_splited[1])
                },
                _ => ("=", param.v.as_str())
            };
            if collect_values {
                Ok(format!("{}", result.1))
            } else {
                Ok(format!("{}{}${}", param.k, result.0, pid))
            }
        })
        .collect()
}

// generic function to process statements: _select, _groupby, _order, _count
fn process_statement<F>(qs: &QueryString, stm: &str, stm_default: &str, stm_fmt: &str, stm_fn: F) -> StatementResult
    where F: Fn(&str) -> String
{
    let mut statement_syntax: String = String::from(stm_default);
    let statement_params = qs.query.iter().find(|p| p.k == String::from(stm));
    let columns = match statement_params {
        Some(param) => stm_fn(&param.v),
        _ => return Err("".to_string())
    };
    if columns != "" {
        statement_syntax = format!("{}", String::from(stm_fmt).replace("{}", &columns));
    }
    Ok(StatementStructResult{ sql: statement_syntax })
}

// Get QueryString and return chunck WHERE statement with values
pub fn ext_where(qs: QueryString) -> WhereResult {
    let where_syntax: String;
    let ref iter_params = qs.query;
    let where_values = match collect_params(iter_params, true) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string())
    };
    let where_fields = match collect_params(iter_params, false) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string())
    };

    if where_fields.len() > 1 {
        where_syntax = format!("WHERE {}", where_fields.join(" AND "));
    } else {
        where_syntax = format!("WHERE {}", where_fields.join(" "));
    }

    Ok(WhereStructResult {
        sql: where_syntax,
        values: where_values
    })
}

// Get QueryString and return SELECT statement
pub fn ext_select(qs: QueryString) -> StatementResult {
    Ok(process_statement(&qs, "_select", "SELECT * FROM", "SELECT {} FROM", |x| String::from(x)).unwrap())
}

// Get QueryString and return COUNT clause statement
pub fn ext_count(qs: QueryString) -> StatementResult {
    // FIXME: Need handle errors
    Ok(process_statement(&qs, "_count", "", "SELECT COUNT({}) FROM", |x| {
        let vs = x.split(",").collect::<Vec<&str>>();
        let result = if vs.len() > 1 {
            ""
        } else {
            x
        };
        String::from(result)
    }).unwrap())
}

// Get QueryString and return chunk ORDER BY statement
pub fn ext_order(qs: QueryString) -> StatementResult {
    Ok(process_statement(&qs, "_order", "", "ORDER BY {}", |x| {
        let vspl = &x.split(",").collect::<Vec<&str>>();
        let od: Vec<String> = vspl.iter().map(|param| {
            let mut s = String::new();
            s.push_str(param); // omg
            if s.starts_with("-") {
                s.remove(0);
                s.push_str(" DESC")
            }
            format!("{}", s)
        }).collect();
        format!("{}", od.join(","))
    }).unwrap())

}

// Get QueryString and return chunk GROUP BY statement
pub fn ext_groupby(qs: QueryString) -> StatementResult {
    Ok(process_statement(&qs, "_groupby", "", "GROUP BY {}", |x| String::from(x)).unwrap())
}

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

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e)
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e)
        }
    }

    #[test]
    fn where_by_request_one_querystring() {
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "5".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_where(qs)
            .unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_n_querystring() {
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "5".to_string()});
        hm.push(Params{k: "name".to_string(), v: "goga".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_where(qs)
            .unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_operators(){
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "$ne.5".to_string()});
        hm.push(Params{k: "name".to_string(), v: "goga".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_where(qs)
            .unwrap();
        assert_eq!(result.sql, "WHERE user_id!=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_invalid_operators(){
        let mut hm = Vec::new();
        hm.push(Params{k: "user_id".to_string(), v: "$nt.5".to_string()});
        hm.push(Params{k: "name".to_string(), v: "goga".to_string()});

        let qs = QueryString{ query: hm };
        match ext_where(qs) {
            Err(e) => assert_eq!(e, "operator $nt not found"),
            Ok(_) => println!("no result")
        }
    }

    #[test]
    fn select_by_request_one_column() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_select".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_select(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT name FROM");
    }

    #[test]
    fn select_by_request_n_column() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_select".to_string(), v: "name,age".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_select(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT name,age FROM");
    }

    #[test]
    fn select_by_request_n_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_select".to_string(), v: "".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_select(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT * FROM");
    }

    #[test]
    fn count_by_request() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_count(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT COUNT(name) FROM");
    }

    #[test]
    fn count_by_request_all_fields() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "*".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_count(qs)
            .unwrap();
        assert_eq!(result.sql, "SELECT COUNT(*) FROM");
    }

    #[test]
    fn count_by_request_two_fields() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "name,age".to_string()});

        let qs = QueryString{ query: hm };
        match ext_count(qs) {
            Err(e) => assert_eq!(e, "could not use more than one column in count function"),
            Ok(s) => assert_eq!(s.sql, "")
        }
    }

    #[test]
    fn count_by_request_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_count".to_string(), v: "".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_count(qs)
            .unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name")
    }

    #[test]
    fn order_by_request_desc() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "-name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name DESC")
    }

    #[test]
    fn order_by_request_empty_params() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request_multiples_columns() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "name,age".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name,age")
    }

    #[test]
    fn order_by_request_multiples_columns_with_orders() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_order".to_string(), v: "name,-age".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_order(qs)
            .unwrap();
        assert_eq!(result.sql, "ORDER BY name,age DESC")
    }

    #[test]
    fn groupby_by_request() {
        let mut hm = Vec::new();
        hm.push(Params{k: "_groupby".to_string(), v: "name".to_string()});

        let qs = QueryString{ query: hm };
        let result = ext_groupby(qs)
            .unwrap();
        assert_eq!(result.sql, "GROUP BY name")
    }

    #[test]
    fn groupby_by_request_empty_param() {
        let mut hm = Vec::new();
        hm.push(Params{k: String::from("_groupby"), v: String::from("")});

        let qs = QueryString{ query: hm };
        let result = ext_groupby(qs)
            .unwrap();
        assert_eq!(result.sql, "")
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::fmt;

use enum_primitive::FromPrimitive;
use byteorder::{NetworkEndian, ReadBytesExt};

use ::protocol::{Magic, Command, DataType};

enum_from_primitive! {
    /// Response status variants
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Ok = 0x0000,
        KeyNotFound = 0x0001,
        KeyExists = 0x0002,
        ValueTooLarge = 0x0003,
        InvalidArguments = 0x0004,
        ItemNotStored = 0x0005,
        IncrDecrOnNonNumericValue = 0x0006,
        VBucketBelongsToAnotherServer = 0x0007,
        AuthenticationError = 0x0008,
        AuthenticationContinue = 0x0009,
        UnknownCommand = 0x0081,
        OutOfMemory = 0x0082,
        NotSupported = 0x00083,
        InternalError = 0x0084,
        Busy = 0x0085,
        TemporaryFailure = 0x0086,
    }
}

/// Parsed `memcached` response.
pub struct Response {
    // We are not storing `magic` byte, because it is always the same and is not required by clients
    opcode: Command,
    key_length: u16,
    extras_length: u8,
    data_type: DataType,
    status: Status,
    body_length: u32,
    opaque: u32,
    cas: u64,
    body: Vec<u8>,
}

impl Response {
    pub fn command(&self) -> &Command {
        &self.opcode
    }

    pub fn status(&self) -> &Status {
        &self.status
    }

    pub fn data_type(&self) -> &DataType {
        &self.data_type
    }

    pub fn opaque(&self) -> &u32 {
        &self.opaque
    }

    pub fn cas(&self) -> &u64 {
        &self.cas
    }

    pub fn extras(&self) -> Option<&[u8]> {
        if self.extras_length > 0 {
            let end = self.extras_length as usize;
            return Some(&self.body[..end]);
        }
        None
    }

    pub fn key(&self) -> Option<&[u8]> {
        if self.key_length > 0 {
            let start = self.extras_length as usize;
            let end = start + self.key_length as usize;

            return Some(&self.body[start..end]);
        }

        None
    }

    pub fn value(&self) -> Option<&[u8]> {
        let start: usize = self.extras_length as usize + self.key_length as usize;
        if self.body_length as usize > start {
            return Some(&self.body[start..]);
        }

        None
    }

    pub fn try_from(raw: &[u8]) -> Result<Response, io::Error> {
        let mut cursor = io::Cursor::new(raw);
        let magic = cursor.read_u8()?;
        if magic != Magic::Response as u8 {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid packet received"));
        }

        let mut response = Response {
            opcode: Command::from_u8(cursor.read_u8()?).unwrap(),
            key_length: cursor.read_u16::<NetworkEndian>()?,
            extras_length: cursor.read_u8()?,
            data_type: DataType::from_u8(cursor.read_u8()?).unwrap(),
            // TODO: Get rid of `unwrap` here
            status: Status::from_u16(cursor.read_u16::<NetworkEndian>()?).unwrap(),
            body_length: cursor.read_u32::<NetworkEndian>()?,
            opaque: cursor.read_u32::<NetworkEndian>()?,
            cas: cursor.read_u64::<NetworkEndian>()?,
            body: vec![],
        };

        if response.body_length > 0 {
            cursor.read_to_end(&mut response.body)?;
        }

        Ok(response)
    }
}

impl fmt::Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut resp = f.debug_struct("Response");

        resp
            .field("command", &self.opcode)
            .field("status", &self.status);

        if let Some(ref key) = self.key() {
            resp.field("key", key);
        }

        if let Some(ref value) = self.value() {
            resp.field("value", value);
        }

        if let Some(ref extras) = self.extras() {
            resp.field("extras", extras);
        }

        resp.finish()
    }
}
<commit_msg>Removing unwraps in the response parser<commit_after>use std::io;
use std::io::Read;
use std::fmt;

use enum_primitive::FromPrimitive;
use byteorder::{NetworkEndian, ReadBytesExt};

use ::protocol::{Magic, Command, DataType};

enum_from_primitive! {
    /// Response status variants
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Ok = 0x0000,
        KeyNotFound = 0x0001,
        KeyExists = 0x0002,
        ValueTooLarge = 0x0003,
        InvalidArguments = 0x0004,
        ItemNotStored = 0x0005,
        IncrDecrOnNonNumericValue = 0x0006,
        VBucketBelongsToAnotherServer = 0x0007,
        AuthenticationError = 0x0008,
        AuthenticationContinue = 0x0009,
        UnknownCommand = 0x0081,
        OutOfMemory = 0x0082,
        NotSupported = 0x00083,
        InternalError = 0x0084,
        Busy = 0x0085,
        TemporaryFailure = 0x0086,
    }
}

/// Parsed `memcached` response.
pub struct Response {
    // We are not storing `magic` byte, because it is always the same and is not required by clients
    opcode: Command,
    key_length: u16,
    extras_length: u8,
    data_type: DataType,
    status: Status,
    body_length: u32,
    opaque: u32,
    cas: u64,
    body: Vec<u8>,
}

impl Response {
    pub fn command(&self) -> &Command {
        &self.opcode
    }

    pub fn status(&self) -> &Status {
        &self.status
    }

    pub fn data_type(&self) -> &DataType {
        &self.data_type
    }

    pub fn opaque(&self) -> &u32 {
        &self.opaque
    }

    pub fn cas(&self) -> &u64 {
        &self.cas
    }

    pub fn extras(&self) -> Option<&[u8]> {
        if self.extras_length > 0 {
            let end = self.extras_length as usize;
            return Some(&self.body[..end]);
        }
        None
    }

    pub fn key(&self) -> Option<&[u8]> {
        if self.key_length > 0 {
            let start = self.extras_length as usize;
            let end = start + self.key_length as usize;

            return Some(&self.body[start..end]);
        }

        None
    }

    pub fn value(&self) -> Option<&[u8]> {
        let start: usize = self.extras_length as usize + self.key_length as usize;
        if self.body_length as usize > start {
            return Some(&self.body[start..]);
        }

        None
    }

    pub fn try_from(raw: &[u8]) -> Result<Response, io::Error> {
        let mut cursor = io::Cursor::new(raw);
        let magic = cursor.read_u8()?;
        if magic != Magic::Response as u8 {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid packet received"));
        }

        let mut response = Response {
            opcode: Command::from_u8(cursor.read_u8()?)
                .ok_or(io::Error::new(io::ErrorKind::InvalidData, "Unknown command"))?,
            key_length: cursor.read_u16::<NetworkEndian>()?,
            extras_length: cursor.read_u8()?,
            data_type: DataType::from_u8(cursor.read_u8()?)
                .ok_or(io::Error::new(io::ErrorKind::InvalidData, "Unknown data type"))?,
            status: Status::from_u16(cursor.read_u16::<NetworkEndian>()?)
                .ok_or(io::Error::new(io::ErrorKind::InvalidData, "Unknown status"))?,
            body_length: cursor.read_u32::<NetworkEndian>()?,
            opaque: cursor.read_u32::<NetworkEndian>()?,
            cas: cursor.read_u64::<NetworkEndian>()?,
            body: vec![],
        };

        if response.body_length > 0 {
            cursor.read_to_end(&mut response.body)?;
        }

        Ok(response)
    }
}

impl fmt::Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut resp = f.debug_struct("Response");

        resp
            .field("command", &self.opcode)
            .field("status", &self.status);

        if let Some(ref key) = self.key() {
            resp.field("key", key);
        }

        if let Some(ref value) = self.value() {
            resp.field("value", value);
        }

        if let Some(ref extras) = self.extras() {
            resp.field("extras", extras);
        }

        resp.finish()
    }
}
<|endoftext|>


<commit_before>use internals::{Value, Node};
use self::Value::Leaf;
use metric::Line;

#[test]
fn line_split_test_1() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_2() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_3() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    if let Leaf(ref s) = **left {
        assert_eq!(&s[..], "asdf\n");
    } else { assert!(false) }
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "qwer\n");
    } else { assert!(false) }
}

#[test]
#[should_panic(expected = "invalid index!")]
fn line_split_test_4() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(1));
}

#[test]
fn line_split_test_5() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(1));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_6() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(1));
    assert_eq!(left.strings().collect::<String>(), "asdf\nqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_7() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    if let Leaf(ref s) = **left {
        assert_eq!(&s[..], "asdf\n");
    } else { assert!(false) }
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "qwer\n");
    } else { assert!(false) }
}

#[test]
fn line_split_test_8() {
    let l1 = Node::new_leaf("");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "qwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_9() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer");
    let l3 = Node::new_leaf("yxcv\n");
    let b1 = Node::new_branch(l1, l2);
    let b2 = Node::new_branch(b1, l3);
    let (left, right) = b2.split(Line(0));
    if let Leaf(ref s) = **left {
        assert_eq!(&s[..], "asdf\n");
    } else { assert!(false) }
    assert_eq!(right.strings().collect::<String>(), "qweryxcv\n");
}

#[test]
fn line_split_test_10() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer\n");
    let l3 = Node::new_leaf("yxcv\n");
    let b1 = Node::new_branch(l2, l3);
    let b2 = Node::new_branch(l1, b1);
    let (left, right) = b2.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "yxcv\n");
    } else { assert!(false) }
}
<commit_msg>test: additional attempt to fix build on stable<commit_after>use internals::Node;
use internals::Value::Leaf;
use metric::Line;

#[test]
fn line_split_test_1() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_2() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_3() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    if let Leaf(ref s) = **left {
        assert_eq!(&s[..], "asdf\n");
    } else { assert!(false) }
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "qwer\n");
    } else { assert!(false) }
}

#[test]
#[should_panic(expected = "invalid index!")]
fn line_split_test_4() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(1));
}

#[test]
fn line_split_test_5() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(1));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_6() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(1));
    assert_eq!(left.strings().collect::<String>(), "asdf\nqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_7() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    if let Leaf(ref s) = **left {
        assert_eq!(&s[..], "asdf\n");
    } else { assert!(false) }
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "qwer\n");
    } else { assert!(false) }
}

#[test]
fn line_split_test_8() {
    let l1 = Node::new_leaf("");
    let l2 = Node::new_leaf("qwer\n");
    let b = Node::new_branch(l1, l2);
    let (left, right) = b.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "qwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "");
    } else { assert!(false) }
}

#[test]
fn line_split_test_9() {
    let l1 = Node::new_leaf("asdf\n");
    let l2 = Node::new_leaf("qwer");
    let l3 = Node::new_leaf("yxcv\n");
    let b1 = Node::new_branch(l1, l2);
    let b2 = Node::new_branch(b1, l3);
    let (left, right) = b2.split(Line(0));
    if let Leaf(ref s) = **left {
        assert_eq!(&s[..], "asdf\n");
    } else { assert!(false) }
    assert_eq!(right.strings().collect::<String>(), "qweryxcv\n");
}

#[test]
fn line_split_test_10() {
    let l1 = Node::new_leaf("asdf");
    let l2 = Node::new_leaf("qwer\n");
    let l3 = Node::new_leaf("yxcv\n");
    let b1 = Node::new_branch(l2, l3);
    let b2 = Node::new_branch(l1, b1);
    let (left, right) = b2.split(Line(0));
    assert_eq!(left.strings().collect::<String>(), "asdfqwer\n");
    if let Leaf(ref s) = **right {
        assert_eq!(&s[..], "yxcv\n");
    } else { assert!(false) }
}
<|endoftext|>


<commit_before>//! Features and intervals for gene annotations.

use std::collections::HashMap;

use bio::io::Strand;

use self::error::FeatureError;

pub mod error {

    use std::error::Error;
    use std::fmt;

    #[derive(Debug)]
    pub enum FeatureError {
        InvalidCoords,
    }

    impl Error for FeatureError {
        fn description(&self) -> &str {
            match *self {
                FeatureError::InvalidCoords => "interval start coordinate larger than its end coordinate"
            }
        }

        fn cause(&self) -> Option<&Error> {
            None
        }
    }

    impl fmt::Display for FeatureError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "FeatureError: {}", self.description())
        }
    }
}

/// Interface for features with start and end coordinates.
///
/// The intervals represented here are zero-based, half open intervals.
/// Coordinates start from zero and start coordinates must be less than
/// or equal to the end coordinates.
pub trait Interval: Sized {

    /// Start coordinate of the interval.
    fn start(&self) -> u64;

    /// End coordinate of the interval.
    fn end(&self) -> u64;

    /// Name of the interval.
    fn name(&self) -> Option<&str>;

    /// Name setter that returns the struct itself.
    ///
    /// This function is expected to mutate the implementing struct.
    fn with_name<T: Into<String>>(self, name: T) -> Self;

    /// Performs various validation of the interval.
    fn validate(self) -> Result<Self, FeatureError> {
        self.validate_coords()
    }

    /// The number of bases covered by the interval.
    fn span(&self) -> u64 {
        self.end() - self.start()
    }

    /// Whether two intervals have an intersection or not.
    fn overlaps(&self, other: &Self) -> bool {
        (other.start() <= self.start() && self.start() <= other.end()) ||
        (other.start() <= self.end() && self.end() <= other.end())
    }

    /// Whether one interval completely contains the other.
    fn envelops(&self, other: &Self) -> bool {
        self.start() <= other.start() && self.end() >= other.end()
    }

    /// Whether two intervals cover a contiguous region without any overlaps.
    fn adjacent(&self, other: &Self) -> bool {
        self.end() == other.start() || self.start() == other.end()
    }

    /// Performs validation of the interval coordinates.
    ///
    /// If the validation fails, an error message is returned within
    /// the `Result` type.
    fn validate_coords(self) -> Result<Self, FeatureError> {
        if self.start() > self.end() {
            return Err(FeatureError::InvalidCoords)
        }

        Ok(self)
    }
}

/// Macro for default function implementations of interval types.
macro_rules! impl_interval {
    ($struct_ty:ty) => (

        impl Interval for $struct_ty {

            /// Name of the interval.
            fn name(&self) -> Option<&str> {
                self.name.as_ref().map(|n| n.as_str())
            }

            /// Start coordinate of the interval.
            fn start(&self) -> u64 {
                self.start
            }

            /// End coordinate of the interval.
            fn end(&self) -> u64 {
                self.end
            }

            fn with_name<T>(mut self, name: T) -> $struct_ty
                where T: Into<String>
            {
                self.name = Some(name.into());
                self
            }
        }

    );
}

/// Default implementation of the `Interval` trait.
///
/// This struct also provides static methods for creating exons, transcripts, and genes.
#[derive(Debug, Default)]
pub struct Feature {
    start: u64,
    end: u64,
    name: Option<String>,
}

impl Feature {

    /// Creates a gene interval with default values.
    ///
    /// A gene interval is a container for transcript intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// let gene = Feature::gene();
    ///
    /// assert_eq!(gene.transcript().len(), 0);
    /// assert_eq!(gene.start(), 0);
    /// assert_eq!(gene.end(), 0);
    /// assert_eq!(gene.name(), None);
    /// ```
    pub fn gene() -> Gene {
        Gene::default()
    }

    /// Creates a transcript interval with default values.
    ///
    /// A transcript interval is a container for exon intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// use bio::io::Strand;
    ///
    /// let transcript = Feature::transcript();
    ///
    /// assert_eq!(transcript.exons().len(), 0);
    /// assert_eq!(transcript.strand(), &Strand::Unknown)
    /// assert_eq!(transcript.start(), 0);
    /// assert_eq!(transcript.end(), 0);
    /// assert_eq!(transcript.name(), None);
    /// ```
    pub fn transcript() -> Transcript {
        Transcript::default()
    }

    /// Creates an exon interval with default values.
    ///
    /// # Examples
    ///
    /// ```
    /// let exon = Feature::exon();
    ///
    /// assert_eq!(exon.start(), 0);
    /// assert_eq!(exon.end(), 0);
    /// assert_eq!(exon.name(), None);
    /// ```
    pub fn exon() -> Exon {
        Exon::default()
    }

    pub fn with_coords(mut self, start: u64, end: u64) -> Feature {
        self.start = start;
        self.end = end;
        self
    }
}

impl_interval!(Feature);

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

    #[test]
    fn default() {
        let fx = Feature::default();
        assert_eq!(fx.start(), 0);
        assert_eq!(fx.end(), 0);
        assert!(fx.validate().is_ok());
    }

    #[test]
    fn with_name() {
        let fx1 = Feature::default()
            .with_name("fx1");
        assert_eq!(fx1.start(), 0);
        assert_eq!(fx1.end(), 0);
        assert_eq!(fx1.name(), Some("fx1"));

        let fx2 = Feature::default()
            .with_name("fx2".to_owned());
        assert_eq!(fx2.start(), 0);
        assert_eq!(fx2.end(), 0);
        assert_eq!(fx2.name(), Some("fx2"));
    }
}

/// Gene annotation.
#[derive(Debug, Default)]
pub struct Gene {
    name: Option<String>,
    start: u64,
    end: u64,
    transcripts: HashMap<String, Transcript>,
}

impl Gene {

    pub fn transcripts(&self) -> &HashMap<String, Transcript> {
        &self.transcripts
    }
}

impl_interval!(Gene);

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

    #[test]
    fn default() {
        let gene = Feature::gene();
        assert_eq!(gene.start(), 0);
        assert_eq!(gene.end(), 0);
        assert_eq!(gene.name(), None);
        assert_eq!(gene.transcripts().len(), 0);
    }
}

/// Transcript annotation.
#[derive(Debug)]
pub struct Transcript {
    name: Option<String>,
    strand: Strand,
    start: u64,
    end: u64,
    cds_start: Option<u64>,
    cds_end: Option<u64>,
    exons: Vec<Exon>,
}

impl Default for Transcript {

    fn default() -> Transcript {
        Transcript {
            name: None,
            strand: Strand::Unknown,
            start: 0,
            end: 0,
            cds_start: None,
            cds_end: None,
            exons: Vec::new(),
        }
    }
}

impl Transcript {

    pub fn strand(&self) -> &Strand {
        &self.strand
    }

    pub fn cds_start(&self) -> Option<u64> {
        self.cds_start
    }

    pub fn cds_end(&self) -> Option<u64> {
        self.cds_end
    }

    pub fn exons(&self) -> &Vec<Exon> {
        &self.exons
    }
}

impl_interval!(Transcript);

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

    #[test]
    fn default() {
        let trx = Feature::transcript();
        assert_eq!(trx.start(), 0);
        assert_eq!(trx.end(), 0);
        assert_eq!(trx.name(), None);
        assert_eq!(trx.strand(), &Strand::Unknown);
        assert_eq!(trx.cds_start(), None);
        assert_eq!(trx.cds_end(), None);
        assert_eq!(trx.exons().len(), 0);
    }
}

/// Exon annotation.
#[derive(Debug, Default)]
pub struct Exon {
    name: Option<String>,
    start: u64,
    end: u64,
}

impl_interval!(Exon);

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

    #[test]
    fn default() {
        let exon = Feature::exon();
        assert_eq!(exon.start(), 0);
        assert_eq!(exon.end(), 0);
        assert_eq!(exon.name(), None);
    }
}
<commit_msg>Add and test with_coords function<commit_after>//! Features and intervals for gene annotations.

use std::collections::HashMap;

use bio::io::Strand;

use self::error::FeatureError;

pub mod error {

    use std::error::Error;
    use std::fmt;

    #[derive(Debug)]
    pub enum FeatureError {
        InvalidCoords,
    }

    impl Error for FeatureError {
        fn description(&self) -> &str {
            match *self {
                FeatureError::InvalidCoords => "interval start coordinate larger than its end coordinate"
            }
        }

        fn cause(&self) -> Option<&Error> {
            None
        }
    }

    impl fmt::Display for FeatureError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "FeatureError: {}", self.description())
        }
    }
}

/// Interface for features with start and end coordinates.
///
/// The intervals represented here are zero-based, half open intervals.
/// Coordinates start from zero and start coordinates must be less than
/// or equal to the end coordinates.
pub trait Interval: Sized {

    /// Start coordinate of the interval.
    fn start(&self) -> u64;

    /// End coordinate of the interval.
    fn end(&self) -> u64;

    /// Name of the interval.
    fn name(&self) -> Option<&str>;

    /// Name setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_name<T: Into<String>>(self, name: T) -> Self;

    /// Coordinate setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_coords(self, start: u64, end: u64) -> Self;

    /// Performs various validation of the interval.
    fn validate(self) -> Result<Self, FeatureError> {
        self.validate_coords()
    }

    /// The number of bases covered by the interval.
    fn span(&self) -> u64 {
        self.end() - self.start()
    }

    /// Whether two intervals have an intersection or not.
    fn overlaps(&self, other: &Self) -> bool {
        (other.start() <= self.start() && self.start() <= other.end()) ||
        (other.start() <= self.end() && self.end() <= other.end())
    }

    /// Whether one interval completely contains the other.
    fn envelops(&self, other: &Self) -> bool {
        self.start() <= other.start() && self.end() >= other.end()
    }

    /// Whether two intervals cover a contiguous region without any overlaps.
    fn adjacent(&self, other: &Self) -> bool {
        self.end() == other.start() || self.start() == other.end()
    }

    /// Performs validation of the interval coordinates.
    ///
    /// If the validation fails, an error message is returned within
    /// the `Result` type.
    fn validate_coords(self) -> Result<Self, FeatureError> {
        if self.start() > self.end() {
            return Err(FeatureError::InvalidCoords)
        }

        Ok(self)
    }
}

/// Macro for default function implementations of interval types.
macro_rules! impl_interval {
    ($struct_ty:ty) => (

        impl Interval for $struct_ty {

            /// Name of the interval.
            fn name(&self) -> Option<&str> {
                self.name.as_ref().map(|n| n.as_str())
            }

            /// Start coordinate of the interval.
            fn start(&self) -> u64 {
                self.start
            }

            /// End coordinate of the interval.
            fn end(&self) -> u64 {
                self.end
            }

            fn with_name<T>(mut self, name: T) -> $struct_ty
                where T: Into<String>
            {
                self.name = Some(name.into());
                self
            }

            fn with_coords(mut self, start: u64, end: u64) -> $struct_ty {
                self.start = start;
                self.end = end;
                self
            }
        }

    );
}

/// Default implementation of the `Interval` trait.
///
/// This struct also provides static methods for creating exons, transcripts, and genes.
#[derive(Debug, Default)]
pub struct Feature {
    start: u64,
    end: u64,
    name: Option<String>,
}

impl Feature {

    /// Creates a gene interval with default values.
    ///
    /// A gene interval is a container for transcript intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// let gene = Feature::gene();
    ///
    /// assert_eq!(gene.transcript().len(), 0);
    /// assert_eq!(gene.start(), 0);
    /// assert_eq!(gene.end(), 0);
    /// assert_eq!(gene.name(), None);
    /// ```
    pub fn gene() -> Gene {
        Gene::default()
    }

    /// Creates a transcript interval with default values.
    ///
    /// A transcript interval is a container for exon intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// use bio::io::Strand;
    ///
    /// let transcript = Feature::transcript();
    ///
    /// assert_eq!(transcript.exons().len(), 0);
    /// assert_eq!(transcript.strand(), &Strand::Unknown)
    /// assert_eq!(transcript.start(), 0);
    /// assert_eq!(transcript.end(), 0);
    /// assert_eq!(transcript.name(), None);
    /// ```
    pub fn transcript() -> Transcript {
        Transcript::default()
    }

    /// Creates an exon interval with default values.
    ///
    /// # Examples
    ///
    /// ```
    /// let exon = Feature::exon();
    ///
    /// assert_eq!(exon.start(), 0);
    /// assert_eq!(exon.end(), 0);
    /// assert_eq!(exon.name(), None);
    /// ```
    pub fn exon() -> Exon {
        Exon::default()
    }

    pub fn with_coords(mut self, start: u64, end: u64) -> Feature {
        self.start = start;
        self.end = end;
        self
    }
}

impl_interval!(Feature);

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

    #[test]
    fn default() {
        let fx = Feature::default();
        assert_eq!(fx.start(), 0);
        assert_eq!(fx.end(), 0);
        assert!(fx.validate().is_ok());
    }

    #[test]
    fn with_name() {
        let fx1 = Feature::default()
            .with_name("fx1");
        assert_eq!(fx1.start(), 0);
        assert_eq!(fx1.end(), 0);
        assert_eq!(fx1.name(), Some("fx1"));

        let fx2 = Feature::default()
            .with_name("fx2".to_owned());
        assert_eq!(fx2.start(), 0);
        assert_eq!(fx2.end(), 0);
        assert_eq!(fx2.name(), Some("fx2"));
    }

    #[test]
    fn with_coords() {
        let fx = Feature::default()
            .with_coords(1, 3);
        assert_eq!(fx.start(), 1);
        assert_eq!(fx.end(), 3);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_multiples() {
        let fx = Feature::default()
            .with_name("fx")
            .with_coords(20, 30);
        assert_eq!(fx.start(), 20);
        assert_eq!(fx.end(), 30);
        assert_eq!(fx.name(), Some("fx"));
    }
}

/// Gene annotation.
#[derive(Debug, Default)]
pub struct Gene {
    name: Option<String>,
    start: u64,
    end: u64,
    transcripts: HashMap<String, Transcript>,
}

impl Gene {

    pub fn transcripts(&self) -> &HashMap<String, Transcript> {
        &self.transcripts
    }
}

impl_interval!(Gene);

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

    #[test]
    fn default() {
        let gene = Feature::gene();
        assert_eq!(gene.start(), 0);
        assert_eq!(gene.end(), 0);
        assert_eq!(gene.name(), None);
        assert_eq!(gene.transcripts().len(), 0);
    }
}

/// Transcript annotation.
#[derive(Debug)]
pub struct Transcript {
    name: Option<String>,
    strand: Strand,
    start: u64,
    end: u64,
    cds_start: Option<u64>,
    cds_end: Option<u64>,
    exons: Vec<Exon>,
}

impl Default for Transcript {

    fn default() -> Transcript {
        Transcript {
            name: None,
            strand: Strand::Unknown,
            start: 0,
            end: 0,
            cds_start: None,
            cds_end: None,
            exons: Vec::new(),
        }
    }
}

impl Transcript {

    pub fn strand(&self) -> &Strand {
        &self.strand
    }

    pub fn cds_start(&self) -> Option<u64> {
        self.cds_start
    }

    pub fn cds_end(&self) -> Option<u64> {
        self.cds_end
    }

    pub fn exons(&self) -> &Vec<Exon> {
        &self.exons
    }
}

impl_interval!(Transcript);

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

    #[test]
    fn default() {
        let trx = Feature::transcript();
        assert_eq!(trx.start(), 0);
        assert_eq!(trx.end(), 0);
        assert_eq!(trx.name(), None);
        assert_eq!(trx.strand(), &Strand::Unknown);
        assert_eq!(trx.cds_start(), None);
        assert_eq!(trx.cds_end(), None);
        assert_eq!(trx.exons().len(), 0);
    }
}

/// Exon annotation.
#[derive(Debug, Default)]
pub struct Exon {
    name: Option<String>,
    start: u64,
    end: u64,
}

impl_interval!(Exon);

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

    #[test]
    fn default() {
        let exon = Feature::exon();
        assert_eq!(exon.start(), 0);
        assert_eq!(exon.end(), 0);
        assert_eq!(exon.name(), None);
    }
}
<|endoftext|>


<commit_before>use std::ptr;
use glib::Error;
use glib::object::{Object, Upcast, Wrapper, Ref};
use glib::types::{StaticType, Type};
use glib::translate::*;
use glib::glib_container::GlibContainer;
use secret_service::SecretService;
use secret_item::SecretItem;
use SecretResult;
use ffi;

pub struct SecretCollection(Ref);

impl SecretCollection {

    /// Lookup which collection is assigned to this alias.
    /// Aliases help determine well known collections, such as 'default'.
    /// Returns the collection, or NULL if none assigned to the alias.
    pub fn for_alias(alias: &str) -> SecretResult<SecretCollection>{
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_for_alias_sync(ptr::null_mut(), alias.to_glib_none().0, SECRET_COLLECTION_LOAD_ITEMS, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Create a new collection in the secret service.
    /// If you specify an alias and a collection with that alias already exists, then a new collection will not be created. The previous one will be returned instead.
    /// Returns the created Collection.
    pub fn create(label: &str, alias: Option<&str>) -> SecretResult<SecretCollection> {
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_create_sync(ptr::null_mut(), label.to_glib_none().0, alias.to_glib_none().0, 0, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Get the created date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_created(&self) -> u64 {
        unsafe {ffi::secret_collection_get_created(self.to_glib_none().0)}
    }

    /// Get the modified date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_modified(&self) -> u64 {
        unsafe {ffi::secret_collection_get_modified(self.to_glib_none().0)}
    }

    /// Get the Secret Service object that this collection was created with.
    pub fn get_service(&self) -> SecretService { //TODO find out if this can return null
        unsafe {
            let ptr = ffi::secret_collection_get_service(self.to_glib_none().0);
            from_glib_none(ptr)
        }
    }

    pub fn are_items_loaded(&self) -> bool {
        let flags = unsafe {ffi::secret_collection_get_flags(self.to_glib_none().0)};
        flags & SECRET_COLLECTION_LOAD_ITEMS != 0
    }

    /// Get the label of this collection.
    pub fn get_label(&self) -> String {
        unsafe{
            let ptr = ffi::secret_collection_get_label(self.to_glib_none().0);
            from_glib_full(ptr)
        }
    }

    /// Get whether the collection is locked or not.
    pub fn get_locked(&self) -> bool {
        let gbool = unsafe{ffi::secret_collection_get_locked(self.to_glib_none().0)};
        from_glib(gbool)
    }

    /// Returns None, if the items have not yet been loaded.
    pub fn get_items(&self) -> Vec<SecretItem> {
        unsafe {
            let glist = ffi::secret_collection_get_items(self.to_glib_none().0);
            Vec::from_glib_full(glist)
        }
    }

    /// Ensure that the SecretCollection proxy has loaded all the items present in the Secret Service.
    pub fn load_items(&self) -> SecretResult<()>{
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_collection_load_items_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    //TODO set_alias from ss
}

impl StaticType for SecretCollection {
    fn static_type() -> Type{
        unsafe { from_glib(ffi::secret_collection_get_type()) }
    }
}

unsafe impl Upcast<Object> for SecretCollection { }

impl Wrapper for SecretCollection {
    type GlibType = ffi::SecretCollection;
    unsafe fn wrap(r: Ref) -> Self{
        SecretCollection(r)
    }

    fn as_ref(&self) -> &Ref{
        &self.0
    }

    fn unwrap(self) -> Ref{
        self.0
    }
}

#[allow(dead_code)]
const SECRET_COLLECTION_NONE: i32        = 0;
const SECRET_COLLECTION_LOAD_ITEMS: i32  = 1 << 1;
<commit_msg>Update documentation for SecretCollection<commit_after>use std::ptr;
use glib::Error;
use glib::object::{Object, Upcast, Wrapper, Ref};
use glib::types::{StaticType, Type};
use glib::translate::*;
use glib::glib_container::GlibContainer;
use secret_service::SecretService;
use secret_item::SecretItem;
use SecretResult;
use ffi;

pub struct SecretCollection(Ref);

impl SecretCollection {

    /// Lookup which collection is assigned to this alias.
    /// Aliases help determine well known collections, such as 'default'.
    /// Returns the collection, or NULL if none assigned to the alias.
    pub fn for_alias(alias: &str) -> SecretResult<SecretCollection>{
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_for_alias_sync(ptr::null_mut(), alias.to_glib_none().0, SECRET_COLLECTION_LOAD_ITEMS, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Create a new collection in the secret service.
    /// If you specify an alias and a collection with that alias already exists, then a new collection will not be created. The previous one will be returned instead.
    /// Returns the created Collection.
    pub fn create(label: &str, alias: Option<&str>) -> SecretResult<SecretCollection> {
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_collection_create_sync(ptr::null_mut(), label.to_glib_none().0, alias.to_glib_none().0, 0, ptr::null_mut(), &mut err)};
        if err.is_null(){
            Ok(unsafe { from_glib_full(ptr) })
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Get the created date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_created(&self) -> u64 {
        unsafe {ffi::secret_collection_get_created(self.to_glib_none().0)}
    }

    /// Get the modified date and time of the collection.
    /// The return value is the number of seconds since the unix epoch, January 1st 1970.
    pub fn get_modified(&self) -> u64 {
        unsafe {ffi::secret_collection_get_modified(self.to_glib_none().0)}
    }

    /// Get the Secret Service object that this collection was created with.
    pub fn get_service(&self) -> SecretService { //TODO find out if this can return null
        unsafe {
            let ptr = ffi::secret_collection_get_service(self.to_glib_none().0);
            from_glib_none(ptr)
        }
    }

    pub fn are_items_loaded(&self) -> bool {
        let flags = unsafe {ffi::secret_collection_get_flags(self.to_glib_none().0)};
        flags & SECRET_COLLECTION_LOAD_ITEMS != 0
    }

    /// Get the label of this collection.
    pub fn get_label(&self) -> String {
        unsafe{
            let ptr = ffi::secret_collection_get_label(self.to_glib_none().0);
            from_glib_full(ptr)
        }
    }

    /// Get whether the collection is locked or not.
    pub fn get_locked(&self) -> bool {
        let gbool = unsafe{ffi::secret_collection_get_locked(self.to_glib_none().0)};
        from_glib(gbool)
    }

    /// Get the SecretItems of the collection
    pub fn get_items(&self) -> Vec<SecretItem> {
        unsafe {
            let glist = ffi::secret_collection_get_items(self.to_glib_none().0);
            Vec::from_glib_full(glist)
        }
    }

    /// Ensure that the SecretCollection proxy has loaded all the items present in the Secret Service.
    pub fn load_items(&self) -> SecretResult<()>{
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_collection_load_items_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    //TODO set_alias from ss
}

impl StaticType for SecretCollection {
    fn static_type() -> Type{
        unsafe { from_glib(ffi::secret_collection_get_type()) }
    }
}

unsafe impl Upcast<Object> for SecretCollection { }

impl Wrapper for SecretCollection {
    type GlibType = ffi::SecretCollection;
    unsafe fn wrap(r: Ref) -> Self{
        SecretCollection(r)
    }

    fn as_ref(&self) -> &Ref{
        &self.0
    }

    fn unwrap(self) -> Ref{
        self.0
    }
}

#[allow(dead_code)]
const SECRET_COLLECTION_NONE: i32        = 0;
const SECRET_COLLECTION_LOAD_ITEMS: i32  = 1 << 1;
<|endoftext|>


<commit_before>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//!
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

use std::u64;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTK_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns 0.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// helpers::bpf_trace_printf(0, 0, 1, 15, 32);
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code needed to perform the call in this example would be nearly identical to the code
/// obtained by compiling the following code from C to eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     char *fmt = "bpf_trace_printk %lx %lx %lx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    0
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}
<commit_msg>src/helpers.rs: correct `bpf_trace_printf()`'s return value<commit_after>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//!
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

use std::u64;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTK_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns the number of bytes written.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
/// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code needed to perform the call in this example would be nearly identical to the code
/// obtained by compiling the following code from C to eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
///     // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
///     char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    let size_arg = | x | {
        if x == 0 {
            1
        } else {
            (x as f64).log(16.0).floor() as u64 + 1
        }
    };
    "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64
        + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}
<|endoftext|>


<commit_before>use edit::buffer::{SplitBuffer, TextBuffer};
use state::editor::{Buffer, Editor};
use std::fs::File;
use std::io::{Read, Write};

/// The status of a file IO operation.
pub enum FileStatus {
    /// Oll fino.
    Ok,
    /// File not found.
    NotFound,
    /// Other error.
    Other,
}

impl Editor {
    /// Open a file.
    pub fn open(&mut self, path: &str) -> FileStatus {
        if let Some(mut file) = File::open(path).ok() {
            let mut con = String::new();
            let _ = file.read_to_string(&mut con);

            if con.is_empty() {
                con.push('\n');
            }

            let mut new_buffer: Buffer = SplitBuffer::from_str(&con).into();
            new_buffer.title = Some(path.into());

            let new_buffer_index = self.buffers.new_buffer(new_buffer);
            self.buffers.switch_to(new_buffer_index);
            self.hint();
            FileStatus::Ok
        } else {
            FileStatus::NotFound
        }
    }

    /// Write the file.
    pub fn write<'a> (&'a mut self, mut path: &'a str) -> FileStatus {
        self.buffers.current_buffer_info_mut().title = Some(path.into());
        if path == "" {
            path = self.files[0].as_str();
        }
        if let Some(mut file) = File::create(path).ok() {
            if file.write(self.buffers.current_buffer().to_string().as_bytes())
                .is_ok()
            {
                FileStatus::Ok
            } else {
                FileStatus::Other
            }
        } else {
            FileStatus::NotFound
        }
    }
}
<commit_msg>Fix Issue #83<commit_after>use edit::buffer::{SplitBuffer, TextBuffer};
use state::editor::{Buffer, Editor};
use std::fs::File;
use std::io::{Read, Write};

/// The status of a file IO operation.
pub enum FileStatus {
    /// Oll fino.
    Ok,
    /// File not found.
    NotFound,
    /// Other error.
    Other,
}

impl Editor {
    /// Open a file.
    pub fn open(&mut self, path: &str) -> FileStatus {
        if let Some(mut file) = File::open(path).ok() {
            let mut con = String::new();
            let _ = file.read_to_string(&mut con);

            if con.is_empty() {
                con.push('\n');
            }

            let mut new_buffer: Buffer = SplitBuffer::from_str(&con).into();
            new_buffer.title = Some(path.into());

            let new_buffer_index = self.buffers.new_buffer(new_buffer);
            self.buffers.switch_to(new_buffer_index);
            self.hint();
            FileStatus::Ok
        } else {
            FileStatus::NotFound
        }
    }

    /// Write the file.
    pub fn write<'a> (&'a mut self, path: &'a str) -> FileStatus {
        self.buffers.current_buffer_info_mut().title = Some(path.into());
        if path == "" {
            return FileStatus::Other;
        }
        if let Some(mut file) = File::create(path).ok() {
            if file.write(self.buffers.current_buffer().to_string().as_bytes())
                .is_ok()
            {
                FileStatus::Ok
            } else {
                FileStatus::Other
            }
        } else {
            FileStatus::NotFound
        }
    }
}
<|endoftext|>