<commit_before>use std::ascii::*;

use cases::snakecase::to_snake_case;
use string::singularize::to_singular;

/// Converts a `String` to `ClassCase` `String`
///
/// #Examples
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "FooBar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "FooBars".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "Foo Bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "foo-bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "fooBar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "FOO_BAR".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "foo_bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "foo_bars".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "Foo bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn to_class_case(non_class_case_string: String) -> String {
    to_class_from_snake(to_snake_case(non_class_case_string))
}
fn to_class_from_snake(non_class_case_string: String) -> String {
    let singularized_word: String = to_singular(non_class_case_string);
    let mut result: String = "".to_string();
    let mut new_word: bool = true;

    for character in singularized_word.chars() {
        if character.to_string() == "_" {
            new_word = true;
        } else if new_word {
            result = format!("{}{}", result, character.to_ascii_uppercase());
            new_word = false;
        } else {
            result = format!("{}{}", result, character.to_ascii_lowercase());
        }
    }
    result
}

/// Determines if a `String` is `ClassCase` `bool`
///
/// #Examples
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "Foo".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "FooBarIsAReallyReallyLongStrings".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "FooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo-bar-string-that-is-really-really-long".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo_bar_is_a_really_really_long_strings".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "fooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo_bar_string_that_is_really_really_long".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "Foo bar string that is really really long".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "Foo Bar Is A Really Really Long String".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
pub fn is_class_case(test_string: String) -> bool {
    test_string == to_class_case(test_string.clone())
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    #[bench]
    fn bench_class_case(b: &mut Bencher) {
        b.iter(|| super::to_class_case("Foo bar".to_string()));
    }

    #[bench]
    fn bench_is_class(b: &mut Bencher) {
        b.iter(|| super::is_class_case("Foo bar".to_string()));
    }

    #[bench]
    fn bench_class_from_snake(b: &mut Bencher) {
        b.iter(|| super::to_class_from_snake("foo_bar".to_string()));
    }
}
<commit_msg>Disabled class case since it takes soo long<commit_after>use std::ascii::*;

use cases::snakecase::to_snake_case;
use string::singularize::to_singular;

/// Converts a `String` to `ClassCase` `String`
///
/// #Examples
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "FooBar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "FooBars".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "Foo Bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "foo-bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "fooBar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "FOO_BAR".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "foo_bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "foo_bars".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::to_class_case;
///     let mock_string: String = "Foo bar".to_string();
///     let expected_string: String = "FooBar".to_string();
///     let asserted_string: String = to_class_case(mock_string);
///     assert!(asserted_string == expected_string);
///
/// ```
pub fn to_class_case(non_class_case_string: String) -> String {
    to_class_from_snake(to_snake_case(non_class_case_string))
}
fn to_class_from_snake(non_class_case_string: String) -> String {
    let singularized_word: String = to_singular(non_class_case_string);
    let mut result: String = "".to_string();
    let mut new_word: bool = true;

    for character in singularized_word.chars() {
        if character.to_string() == "_" {
            new_word = true;
        } else if new_word {
            result = format!("{}{}", result, character.to_ascii_uppercase());
            new_word = false;
        } else {
            result = format!("{}{}", result, character.to_ascii_lowercase());
        }
    }
    result
}

/// Determines if a `String` is `ClassCase` `bool`
///
/// #Examples
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "Foo".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "FooBarIsAReallyReallyLongStrings".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "FooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == true);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo-bar-string-that-is-really-really-long".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo_bar_is_a_really_really_long_strings".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "fooBarIsAReallyReallyLongString".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "FOO_BAR_STRING_THAT_IS_REALLY_REALLY_LONG".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "foo_bar_string_that_is_really_really_long".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "Foo bar string that is really really long".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
///
/// ```
///     use inflector::cases::classcase::is_class_case;
///     let mock_string: String = "Foo Bar Is A Really Really Long String".to_string();
///     let asserted_bool: bool = is_class_case(mock_string);
///     assert!(asserted_bool == false);
///
/// ```
pub fn is_class_case(test_string: String) -> bool {
    test_string == to_class_case(test_string.clone())
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    // #[bench]
    // fn bench_class_case(b: &mut Bencher) {
    //     b.iter(|| super::to_class_case("Foo bar".to_string()));
    // }
    //
    // #[bench]
    // fn bench_is_class(b: &mut Bencher) {
    //     b.iter(|| super::is_class_case("Foo bar".to_string()));
    // }
    //
    // #[bench]
    // fn bench_class_from_snake(b: &mut Bencher) {
    //     b.iter(|| super::to_class_from_snake("foo_bar".to_string()));
    // }
}
<|endoftext|>


<commit_before>use std::env;
use tougou_bot::commands::{ pic::PicCommand, ping::PingCommand, status::StatusCommand };
use tougou_bot::discord_client::*;

fn main() {
    let token: String =
        env::var("DISCORD_TOKEN").expect("Must set the environment variable `DISCORD_TOKEN`");

    let client = serenity_discord_client::SerenityDiscordClient::new(&token);
    client.register_command("pic", PicCommand).unwrap();
    client.register_command("ping", PingCommand).unwrap();
    client.register_command("status", StatusCommand).unwrap();

    let mut temp = String::new();
    std::io::stdin()
        .read_line(&mut temp)
        .expect("failed to read from console");
}
<commit_msg>Change process keep alive mechanism<commit_after>use std::env;
use std::sync::{ Condvar, Mutex };
use tougou_bot::commands::{ pic::PicCommand, ping::PingCommand, status::StatusCommand };
use tougou_bot::discord_client::*;

fn main() {
    let token: String =
        env::var("DISCORD_TOKEN").expect("Must set the environment variable `DISCORD_TOKEN`");

    let client = serenity_discord_client::SerenityDiscordClient::new(&token);
    client.register_command("pic", PicCommand).unwrap();
    client.register_command("ping", PingCommand).unwrap();
    client.register_command("status", StatusCommand).unwrap();

    let keep_alive = Condvar::new();
    let keep_alive_lock = Mutex::new(false);
    let _ = keep_alive.wait(keep_alive_lock.lock().unwrap()).expect("keep alive lock failed");
}
<|endoftext|>


<commit_before>use clap::Clap;
use std::cmp::Ordering;
use std::fs::File;

fn normalize_col(col: &str) -> String {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"\(.*?\)").unwrap();
    }
    let mut col = RE
        .replace_all(col, "")
        .to_lowercase()
        .trim()
        .replace(" ", "_")
        .replace(".", "_")
        .replace("-", "_")
        .replace("/", "_")
        .replace("?", "")
        .replace(",", "_")
        .replace("&", "_")
        .replace("#", "");
    if !col.chars().next().map(char::is_alphabetic).unwrap_or(true) {
        col = format!("c_{}", col)
    }
    col
}

fn _create_table(db: &mut rusqlite::Connection, table_name: &str, cols: &[String]) {
    let create_columns = cols
        .iter()
        .map(|c| format!("{} varchar", c))
        .collect::<Vec<String>>()
        .join(", ");
    db.execute(
        &format!("CREATE TABLE {} ({})", table_name, create_columns),
        &[] as &[&dyn rusqlite::types::ToSql],
    )
    .unwrap();
}

fn _load_table_from_path(
    db: &mut rusqlite::Connection,
    table_name: &str,
    path: &str,
    delimiter: u8,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut num_rows = 0;
    let f = File::open(path)?;
    let file_size = f.metadata().unwrap().len();
    let mut reader = csv::ReaderBuilder::new()
        .flexible(true)
        .delimiter(delimiter)
        .from_reader(f);

    let normalized_cols =
        reader
            .headers()?
            .iter()
            .map(normalize_col)
            .fold(vec![], |mut v, orig_col| {
                let mut col = orig_col.clone();
                let mut i = 1;
                while v.contains(&col) {
                    col = format!("{}_{}", orig_col, i);
                    i += 1
                }
                v.push(col);
                v
            });
    _create_table(db, table_name, &normalized_cols);

    let insert_query = format!(
        "INSERT INTO {} VALUES ({})",
        table_name,
        normalized_cols
            .iter()
            .map(|_| "?")
            .collect::<Vec<_>>()
            .join(", ")
    );
    let pb = indicatif::ProgressBar::new(file_size);
    pb.set_style(
        indicatif::ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
            .progress_chars("#>-"),
    );
    let mut records = reader.records();
    let tx = db.transaction().unwrap();
    {
        let mut stmt = tx.prepare(&insert_query).expect("tx.prepare() failed");
        while let Some(row) = records.next() {
            let mut row = row?;
            match row.len().cmp(&normalized_cols.len()) {
                Ordering::Less => {
                    for _ in 0..normalized_cols.len() - row.len() {
                        row.push_field("");
                    }
                }
                Ordering::Greater => {
                    panic!("Too many fields on row {}, fields: {:?}", num_rows + 1, row);
                }
                Ordering::Equal => {}
            }
            stmt.execute(&row).unwrap();

            num_rows += 1;
            if num_rows % 10000 == 0 {
                pb.set_position(records.reader().position().byte())
            }
        }
    }
    tx.commit().unwrap();
    pb.finish();

    println!(
        "Loaded {} rows into {}({}) from {:?}",
        num_rows,
        table_name,
        normalized_cols.join(", "),
        path,
    );
    Ok(normalized_cols)
}

struct FromAnySqlType {
    value: String,
}

impl rusqlite::types::FromSql for FromAnySqlType {
    fn column_result(
        value: rusqlite::types::ValueRef<'_>,
    ) -> Result<FromAnySqlType, rusqlite::types::FromSqlError> {
        let result = match value {
            rusqlite::types::ValueRef::Null => "null".to_string(),
            rusqlite::types::ValueRef::Integer(v) => v.to_string(),
            rusqlite::types::ValueRef::Real(v) => v.to_string(),
            rusqlite::types::ValueRef::Blob(v) | rusqlite::types::ValueRef::Text(v) => {
                String::from_utf8(v.to_vec()).unwrap()
            }
        };
        Ok(FromAnySqlType { value: result })
    }
}

fn _prepare_query<'a>(
    conn: &'a mut rusqlite::Connection,
    query: &str,
) -> Result<rusqlite::Statement<'a>, String> {
    conn.prepare(&query).map_err(|e| e.to_string())
}

fn _handle_query(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    let mut stmt = _prepare_query(conn, line)?;

    let mut table = comfy_table::Table::new();
    table.load_preset("││──╞═╪╡┆    ┬┴┌┐└┘");
    table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
    let mut title_row = comfy_table::Row::new();
    for col in stmt.column_names() {
        title_row.add_cell(comfy_table::Cell::new(col));
    }
    table.set_header(title_row);

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        let mut row = comfy_table::Row::new();
        for i in 0..r.column_count() {
            let cell: FromAnySqlType = r.get(i).unwrap();
            row.add_cell(comfy_table::Cell::new(&cell.value));
        }
        table.add_row(row);
    }
    println!("{}", table);
    Ok(())
}

fn _handle_export(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"^\.export\(([\w_\-\./]+)\) (.*)").unwrap();
    }
    let caps = RE
        .captures(line)
        .ok_or_else(|| "Must match `.export(file-name) SQL`".to_owned())?;
    let destination_path = &caps[1];
    let query = &caps[2];

    let mut stmt = _prepare_query(conn, query)?;

    let mut writer = csv::Writer::from_path(destination_path).unwrap();
    writer.write_record(stmt.column_names()).unwrap();

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        writer
            .write_record((0..r.column_count()).map(|i| {
                let cell: FromAnySqlType = r.get(i).unwrap();
                cell.value
            }))
            .unwrap();
    }

    Ok(())
}

fn _process_query(conn: &mut rusqlite::Connection, line: &str) {
    let result = if line.starts_with(".export") {
        _handle_export(conn, line)
    } else if line.starts_with(".schema") {
        _handle_query(
            conn,
            "SELECT sql AS schema FROM sqlite_master WHERE name like 't%'",
        )
    } else {
        _handle_query(conn, line)
    };
    if let Err(e) = result {
        println!("{}", e);
    }
}

struct SimpleWordCompleter {
    words: Vec<String>,
}

static BREAK_CHARS: [u8; 4] = [b' ', b'(', b')', b','];
impl SimpleWordCompleter {
    fn new(words: Vec<String>) -> SimpleWordCompleter {
        SimpleWordCompleter { words }
    }
}

impl rustyline::Helper for SimpleWordCompleter {}

impl rustyline::hint::Hinter for SimpleWordCompleter {
    type Hint = String;

    fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
        None
    }
}

impl rustyline::highlight::Highlighter for SimpleWordCompleter {}

impl rustyline::validate::Validator for SimpleWordCompleter {}

impl rustyline::completion::Completer for SimpleWordCompleter {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let (start, word) = rustyline::completion::extract_word(line, pos, None, &BREAK_CHARS);

        let matches = self
            .words
            .iter()
            .filter(|w| w.starts_with(word))
            .cloned()
            .collect();
        Ok((start, matches))
    }
}

#[derive(Clap)]
struct Opts {
    #[clap(long, about = "Use ',' as the delimiter for the CSV")]
    comma: bool,
    #[clap(long, about = "Use '|' as the delimiter for the CSV")]
    pipe: bool,
    #[clap(long, about = "Use '\\t' as the delimiter for the CSV")]
    tab: bool,
    #[clap(long, about = "Use ';' as the delimiter for the CSV")]
    semicolon: bool,

    #[clap()]
    paths: Vec<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let opts = Opts::parse();

    let delim = match (opts.comma, opts.pipe, opts.tab, opts.semicolon) {
        (true, false, false, false) | (false, false, false, false) => b',',
        (false, true, false, false) => b'|',
        (false, false, true, false) => b'\t',
        (false, false, false, true) => b';',
        _ => {
            eprintln!("Can't pass more than one of --comma, --pipe, and --tab");
            std::process::exit(1);
        }
    };

    let mut conn = rusqlite::Connection::open_in_memory().unwrap();

    let mut base_words = [
        "distinct", "select", "from", "group", "by", "order", "where", "count", "limit", "offset",
        ".export", ".schema",
    ]
    .iter()
    .map(|&s| s.to_string())
    .collect::<Vec<String>>();

    if opts.paths.len() == 1 {
        let mut col_names = _load_table_from_path(&mut conn, "t", &opts.paths[0], delim)?;
        base_words.append(&mut col_names);
    } else {
        for (idx, path) in opts.paths.iter().enumerate() {
            let mut col_names =
                _load_table_from_path(&mut conn, &format!("t{}", idx + 1), path, delim)?;
            base_words.append(&mut col_names);
        }
    }

    let completer = SimpleWordCompleter::new(base_words);
    let mut rl = rustyline::Editor::new();
    rl.set_helper(Some(completer));
    loop {
        match rl.readline("> ") {
            Ok(line) => {
                if line.trim().is_empty() {
                    continue;
                }
                _process_query(&mut conn, &line);
                rl.add_history_entry(line);
            }
            Err(rustyline::error::ReadlineError::Interrupted) => {
                println!("Interrupted");
                continue;
            }
            Err(rustyline::error::ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                println!("Error: {}", err);
                break;
            }
        }
    }

    Ok(())
}

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

    #[test]
    fn test_normalize_col() {
        for (value, expected) in &[
            ("", ""),
            ("abc", "abc"),
            ("abc (123)", "abc"),
            ("2/6/2000", "c_2_6_2000"),
            ("COMBO#", "combo"),
        ] {
            assert_eq!(&&normalize_col(value), expected);
        }
    }
}
<commit_msg>Try to make the paren removal logic smarter (#520)<commit_after>use clap::Clap;
use std::cmp::Ordering;
use std::fs::File;

fn normalize_col(col: &str) -> String {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"\(.*?\)$").unwrap();
    }
    let mut col = RE
        .replace_all(col, "")
        .to_lowercase()
        .trim()
        .replace("(", "")
        .replace(")", "")
        .replace(" ", "_")
        .replace(".", "_")
        .replace("-", "_")
        .replace("/", "_")
        .replace("?", "")
        .replace(",", "_")
        .replace("&", "_")
        .replace("#", "");
    if !col.chars().next().map(char::is_alphabetic).unwrap_or(true) {
        col = format!("c_{}", col)
    }
    col
}

fn _create_table(db: &mut rusqlite::Connection, table_name: &str, cols: &[String]) {
    let create_columns = cols
        .iter()
        .map(|c| format!("{} varchar", c))
        .collect::<Vec<String>>()
        .join(", ");
    db.execute(
        &format!("CREATE TABLE {} ({})", table_name, create_columns),
        &[] as &[&dyn rusqlite::types::ToSql],
    )
    .unwrap();
}

fn _load_table_from_path(
    db: &mut rusqlite::Connection,
    table_name: &str,
    path: &str,
    delimiter: u8,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut num_rows = 0;
    let f = File::open(path)?;
    let file_size = f.metadata().unwrap().len();
    let mut reader = csv::ReaderBuilder::new()
        .flexible(true)
        .delimiter(delimiter)
        .from_reader(f);

    let normalized_cols =
        reader
            .headers()?
            .iter()
            .map(normalize_col)
            .fold(vec![], |mut v, orig_col| {
                let mut col = orig_col.clone();
                let mut i = 1;
                while v.contains(&col) {
                    col = format!("{}_{}", orig_col, i);
                    i += 1
                }
                v.push(col);
                v
            });
    _create_table(db, table_name, &normalized_cols);

    let insert_query = format!(
        "INSERT INTO {} VALUES ({})",
        table_name,
        normalized_cols
            .iter()
            .map(|_| "?")
            .collect::<Vec<_>>()
            .join(", ")
    );
    let pb = indicatif::ProgressBar::new(file_size);
    pb.set_style(
        indicatif::ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
            .progress_chars("#>-"),
    );
    let mut records = reader.records();
    let tx = db.transaction().unwrap();
    {
        let mut stmt = tx.prepare(&insert_query).expect("tx.prepare() failed");
        while let Some(row) = records.next() {
            let mut row = row?;
            match row.len().cmp(&normalized_cols.len()) {
                Ordering::Less => {
                    for _ in 0..normalized_cols.len() - row.len() {
                        row.push_field("");
                    }
                }
                Ordering::Greater => {
                    panic!("Too many fields on row {}, fields: {:?}", num_rows + 1, row);
                }
                Ordering::Equal => {}
            }
            stmt.execute(&row).unwrap();

            num_rows += 1;
            if num_rows % 10000 == 0 {
                pb.set_position(records.reader().position().byte())
            }
        }
    }
    tx.commit().unwrap();
    pb.finish();

    println!(
        "Loaded {} rows into {}({}) from {:?}",
        num_rows,
        table_name,
        normalized_cols.join(", "),
        path,
    );
    Ok(normalized_cols)
}

struct FromAnySqlType {
    value: String,
}

impl rusqlite::types::FromSql for FromAnySqlType {
    fn column_result(
        value: rusqlite::types::ValueRef<'_>,
    ) -> Result<FromAnySqlType, rusqlite::types::FromSqlError> {
        let result = match value {
            rusqlite::types::ValueRef::Null => "null".to_string(),
            rusqlite::types::ValueRef::Integer(v) => v.to_string(),
            rusqlite::types::ValueRef::Real(v) => v.to_string(),
            rusqlite::types::ValueRef::Blob(v) | rusqlite::types::ValueRef::Text(v) => {
                String::from_utf8(v.to_vec()).unwrap()
            }
        };
        Ok(FromAnySqlType { value: result })
    }
}

fn _prepare_query<'a>(
    conn: &'a mut rusqlite::Connection,
    query: &str,
) -> Result<rusqlite::Statement<'a>, String> {
    conn.prepare(&query).map_err(|e| e.to_string())
}

fn _handle_query(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    let mut stmt = _prepare_query(conn, line)?;

    let mut table = comfy_table::Table::new();
    table.load_preset("││──╞═╪╡┆    ┬┴┌┐└┘");
    table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
    let mut title_row = comfy_table::Row::new();
    for col in stmt.column_names() {
        title_row.add_cell(comfy_table::Cell::new(col));
    }
    table.set_header(title_row);

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        let mut row = comfy_table::Row::new();
        for i in 0..r.column_count() {
            let cell: FromAnySqlType = r.get(i).unwrap();
            row.add_cell(comfy_table::Cell::new(&cell.value));
        }
        table.add_row(row);
    }
    println!("{}", table);
    Ok(())
}

fn _handle_export(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"^\.export\(([\w_\-\./]+)\) (.*)").unwrap();
    }
    let caps = RE
        .captures(line)
        .ok_or_else(|| "Must match `.export(file-name) SQL`".to_owned())?;
    let destination_path = &caps[1];
    let query = &caps[2];

    let mut stmt = _prepare_query(conn, query)?;

    let mut writer = csv::Writer::from_path(destination_path).unwrap();
    writer.write_record(stmt.column_names()).unwrap();

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        writer
            .write_record((0..r.column_count()).map(|i| {
                let cell: FromAnySqlType = r.get(i).unwrap();
                cell.value
            }))
            .unwrap();
    }

    Ok(())
}

fn _process_query(conn: &mut rusqlite::Connection, line: &str) {
    let result = if line.starts_with(".export") {
        _handle_export(conn, line)
    } else if line.starts_with(".schema") {
        _handle_query(
            conn,
            "SELECT sql AS schema FROM sqlite_master WHERE name like 't%'",
        )
    } else {
        _handle_query(conn, line)
    };
    if let Err(e) = result {
        println!("{}", e);
    }
}

struct SimpleWordCompleter {
    words: Vec<String>,
}

static BREAK_CHARS: [u8; 4] = [b' ', b'(', b')', b','];
impl SimpleWordCompleter {
    fn new(words: Vec<String>) -> SimpleWordCompleter {
        SimpleWordCompleter { words }
    }
}

impl rustyline::Helper for SimpleWordCompleter {}

impl rustyline::hint::Hinter for SimpleWordCompleter {
    type Hint = String;

    fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
        None
    }
}

impl rustyline::highlight::Highlighter for SimpleWordCompleter {}

impl rustyline::validate::Validator for SimpleWordCompleter {}

impl rustyline::completion::Completer for SimpleWordCompleter {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let (start, word) = rustyline::completion::extract_word(line, pos, None, &BREAK_CHARS);

        let matches = self
            .words
            .iter()
            .filter(|w| w.starts_with(word))
            .cloned()
            .collect();
        Ok((start, matches))
    }
}

#[derive(Clap)]
struct Opts {
    #[clap(long, about = "Use ',' as the delimiter for the CSV")]
    comma: bool,
    #[clap(long, about = "Use '|' as the delimiter for the CSV")]
    pipe: bool,
    #[clap(long, about = "Use '\\t' as the delimiter for the CSV")]
    tab: bool,
    #[clap(long, about = "Use ';' as the delimiter for the CSV")]
    semicolon: bool,

    #[clap()]
    paths: Vec<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let opts = Opts::parse();

    let delim = match (opts.comma, opts.pipe, opts.tab, opts.semicolon) {
        (true, false, false, false) | (false, false, false, false) => b',',
        (false, true, false, false) => b'|',
        (false, false, true, false) => b'\t',
        (false, false, false, true) => b';',
        _ => {
            eprintln!("Can't pass more than one of --comma, --pipe, and --tab");
            std::process::exit(1);
        }
    };

    let mut conn = rusqlite::Connection::open_in_memory().unwrap();

    let mut base_words = [
        "distinct", "select", "from", "group", "by", "order", "where", "count", "limit", "offset",
        ".export", ".schema",
    ]
    .iter()
    .map(|&s| s.to_string())
    .collect::<Vec<String>>();

    if opts.paths.len() == 1 {
        let mut col_names = _load_table_from_path(&mut conn, "t", &opts.paths[0], delim)?;
        base_words.append(&mut col_names);
    } else {
        for (idx, path) in opts.paths.iter().enumerate() {
            let mut col_names =
                _load_table_from_path(&mut conn, &format!("t{}", idx + 1), path, delim)?;
            base_words.append(&mut col_names);
        }
    }

    let completer = SimpleWordCompleter::new(base_words);
    let mut rl = rustyline::Editor::new();
    rl.set_helper(Some(completer));
    loop {
        match rl.readline("> ") {
            Ok(line) => {
                if line.trim().is_empty() {
                    continue;
                }
                _process_query(&mut conn, &line);
                rl.add_history_entry(line);
            }
            Err(rustyline::error::ReadlineError::Interrupted) => {
                println!("Interrupted");
                continue;
            }
            Err(rustyline::error::ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                println!("Error: {}", err);
                break;
            }
        }
    }

    Ok(())
}

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

    #[test]
    fn test_normalize_col() {
        for (value, expected) in &[
            ("", ""),
            ("abc", "abc"),
            ("(S)AO", "sao"),
            ("abc (123)", "abc"),
            ("2/6/2000", "c_2_6_2000"),
            ("COMBO#", "combo"),
        ] {
            assert_eq!(&&normalize_col(value), expected);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:5000";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            req.read_to_string(&mut buffer).unwrap();
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            res.write_all(symbol_response.as_bytes()).unwrap();

            res.end().unwrap();
        },
        hyper::Get => {
            let mut res = res.start().unwrap();
            res.write_all("symbolapi, see github.com/rhelmer/symbolapi".as_bytes()).unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");

        let mut full_symbol_path = symbol_path.clone();
        full_symbol_path.push(&debug_file);
        full_symbol_path.push(&debug_id);
        full_symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        create_dir_all(&full_symbol_path.parent().unwrap()).unwrap();

        let supplier = SimpleSymbolSupplier::new(vec!(symbol_path.clone()));

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {

            let symbolizer = Symbolizer::new(supplier);
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&full_symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                res.read_to_string(&mut body).unwrap();

                let mut f = File::create(&full_symbol_path).unwrap();
                f.write_all(body.as_bytes()).unwrap();
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbolizer.get_symbol_at_address(&debug_file_name, &debug_id, *address) {
                        Some(x) => symbols.push(x),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("debug_file_name: {:?}, symbols: {:?}", debug_file_name, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            result.symbolicatedStacks.push(
                vec!(format!("{} (in {}))", symbol, debug_file_name))
            );
        }
        result.knownModules.push(true);
    }

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<commit_msg>comments<commit_after>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::{Symbolizer, SimpleSymbolSupplier};
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:5000";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            req.read_to_string(&mut buffer).unwrap();
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            // FIXME limit the number of possible threads
            // TODO maybe push these into a queue and have a thread pool service the queue?
            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            res.write_all(symbol_response.as_bytes()).unwrap();

            res.end().unwrap();
        },
        hyper::Get => {
            let mut res = res.start().unwrap();
            res.write_all("symbolapi, see github.com/rhelmer/symbolapi".as_bytes()).unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");

        let mut full_symbol_path = symbol_path.clone();
        full_symbol_path.push(&debug_file);
        full_symbol_path.push(&debug_id);
        full_symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        create_dir_all(&full_symbol_path.parent().unwrap()).unwrap();

        let supplier = SimpleSymbolSupplier::new(vec!(symbol_path.clone()));

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {

            let symbolizer = Symbolizer::new(supplier);
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&full_symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                res.read_to_string(&mut body).unwrap();

                let mut f = File::create(&full_symbol_path).unwrap();
                f.write_all(body.as_bytes()).unwrap();
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbolizer.get_symbol_at_address(&debug_file_name, &debug_id, *address) {
                        Some(x) => symbols.push(x),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("debug_file_name: {:?}, symbols: {:?}", debug_file_name, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            result.symbolicatedStacks.push(
                vec!(format!("{} (in {}))", symbol, debug_file_name))
            );
        }
        result.knownModules.push(true);
    }

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};
use std::fs;
use std::io;
use std::path::PathBuf;

use rustyline::error::ReadlineError;
use rustyline::Editor;
use structopt::StructOpt;

use ein_syntax::parser::{self, ParseError};
use ein_vm::{Chunk, Instruction, RuntimeError, Value, VirtualMachine};

#[derive(StructOpt, Debug)]
struct Options {
    #[structopt(name = "FILE", parse(from_os_str))]
    file: Option<PathBuf>,
}

fn main() {
    let options = Options::from_args();

    match options.file {
        Some(path) => run_file(&path),
        None => repl(),
    }
}

fn run<'a>(input: &'a str, vm: &mut VirtualMachine) -> Result<'a, Option<Value>> {
    let mut chunk = Chunk::new();

    match parser::parse_expr(input) {
        Ok(expr) => chunk.emit(&expr),
        Err(_) => {
            let ast = parser::parse_program(input)?;
            chunk.emit(&ast);
        }
    }

    chunk.add_instruction(Instruction::Return);

    let return_value = vm.run(&chunk)?;

    Ok(return_value)
}

fn run_file(path: &PathBuf) {
    match fs::read_to_string(path) {
        Ok(program) => {
            if let Err(e) = run(&program, &mut VirtualMachine::new()) {
                eprintln!("Error: {}\n", e);
            }
        }
        Err(e) => eprintln!("Error: {}\n", e),
    }
}

fn repl() {
    println!("| Ein {}", env!("CARGO_PKG_VERSION"));
    println!("| Copyright © 2018-2019 Joe Clay");
    println!("| Released under the MIT License\n");

    let mut editor = Editor::<()>::new();

    if let Err(e) = editor.load_history("history.txt") {
        if !is_not_found_error(&e) {
            eprintln!("Failed to load REPL history: {}\n", e);
        }
    }

    let mut ctx = VirtualMachine::new();

    loop {
        let line = match editor.readline(">> ") {
            Ok(line) => line,
            Err(e) => {
                eprintln!("Error: {}\n", e);
                break;
            }
        };

        editor.add_history_entry(line.as_ref());

        match run(&line, &mut ctx) {
            Ok(Some(value)) => println!("{}\n", value),
            Ok(None) => {}
            Err(e) => eprintln!("Error: {}\n", e),
        }
    }

    if let Err(e) = editor.save_history("history.txt") {
        eprintln!("Failed to save REPL history: {}\n", e);
    }
}

fn is_not_found_error(error: &ReadlineError) -> bool {
    match error {
        ReadlineError::Io(inner_error) => match inner_error.kind() {
            io::ErrorKind::NotFound => true,
            _ => false,
        },
        _ => false,
    }
}

type Result<'a, T = ()> = std::result::Result<T, EinError<'a>>;

enum EinError<'a> {
    Parse(ParseError<'a>),
    Runtime(RuntimeError),
    Io(io::Error),
    Readline(ReadlineError),
}

impl<'a> From<ParseError<'a>> for EinError<'a> {
    fn from(err: ParseError<'a>) -> EinError<'a> {
        EinError::Parse(err)
    }
}

impl<'a> From<RuntimeError> for EinError<'a> {
    fn from(err: RuntimeError) -> EinError<'a> {
        EinError::Runtime(err)
    }
}

impl<'a> From<io::Error> for EinError<'a> {
    fn from(err: io::Error) -> EinError<'a> {
        EinError::Io(err)
    }
}

impl<'a> From<ReadlineError> for EinError<'a> {
    fn from(err: ReadlineError) -> EinError<'a> {
        EinError::Readline(err)
    }
}

impl<'a> Display for EinError<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            EinError::Parse(e) => e.fmt(f),
            EinError::Runtime(e) => e.fmt(f),
            EinError::Io(e) => e.fmt(f),
            EinError::Readline(e) => e.fmt(f),
        }
    }
}
<commit_msg>Fix the nightly failures (but for real this time)<commit_after>use std::fmt::{self, Display, Formatter};
use std::fs;
use std::io;
use std::path::PathBuf;

use rustyline::error::ReadlineError;
use rustyline::Editor;
use structopt::StructOpt;

use ein_syntax::parser::{self, ParseError};
use ein_vm::{Chunk, Instruction, RuntimeError, Value, VirtualMachine};

#[derive(StructOpt, Debug)]
struct Options {
    #[structopt(name = "FILE", parse(from_os_str))]
    file: Option<PathBuf>,
}

fn main() {
    let options = Options::from_args();

    match options.file {
        Some(path) => run_file(&path),
        None => repl(),
    }
}

fn run<'a>(input: &'a str, vm: &mut VirtualMachine) -> Result<'a, Option<Value>> {
    let mut chunk = Chunk::new();

    match parser::parse_expr(input) {
        Ok(expr) => chunk.emit(&expr),
        Err(_) => {
            let ast = parser::parse_program(input)?;
            chunk.emit(&ast);
        }
    }

    chunk.add_instruction(Instruction::Return);

    let return_value = vm.run(&chunk)?;

    Ok(return_value)
}

fn run_file(path: &PathBuf) {
    match fs::read_to_string(path) {
        Ok(program) => {
            if let Err(e) = run(&program, &mut VirtualMachine::new()) {
                eprintln!("Error: {}\n", e);
            }
        }
        Err(e) => eprintln!("Error: {}\n", e),
    }
}

fn repl() {
    println!("| Ein {}", env!("CARGO_PKG_VERSION"));
    println!("| Copyright © 2018-2019 Joe Clay");
    println!("| Released under the MIT License\n");

    let mut editor = Editor::<()>::new();

    if let Err(e) = editor.load_history("history.txt") {
        if !is_not_found_error(&e) {
            eprintln!("Failed to load REPL history: {}\n", e);
        }
    }

    let mut ctx = VirtualMachine::new();

    loop {
        let line = match editor.readline(">> ") {
            Ok(line) => line,
            Err(e) => {
                eprintln!("Error: {}\n", e);
                break;
            }
        };

        editor.add_history_entry(line.as_str());

        match run(&line, &mut ctx) {
            Ok(Some(value)) => println!("{}\n", value),
            Ok(None) => {}
            Err(e) => eprintln!("Error: {}\n", e),
        }
    }

    if let Err(e) = editor.save_history("history.txt") {
        eprintln!("Failed to save REPL history: {}\n", e);
    }
}

fn is_not_found_error(error: &ReadlineError) -> bool {
    match error {
        ReadlineError::Io(inner_error) => match inner_error.kind() {
            io::ErrorKind::NotFound => true,
            _ => false,
        },
        _ => false,
    }
}

type Result<'a, T = ()> = std::result::Result<T, EinError<'a>>;

enum EinError<'a> {
    Parse(ParseError<'a>),
    Runtime(RuntimeError),
    Io(io::Error),
    Readline(ReadlineError),
}

impl<'a> From<ParseError<'a>> for EinError<'a> {
    fn from(err: ParseError<'a>) -> EinError<'a> {
        EinError::Parse(err)
    }
}

impl<'a> From<RuntimeError> for EinError<'a> {
    fn from(err: RuntimeError) -> EinError<'a> {
        EinError::Runtime(err)
    }
}

impl<'a> From<io::Error> for EinError<'a> {
    fn from(err: io::Error) -> EinError<'a> {
        EinError::Io(err)
    }
}

impl<'a> From<ReadlineError> for EinError<'a> {
    fn from(err: ReadlineError) -> EinError<'a> {
        EinError::Readline(err)
    }
}

impl<'a> Display for EinError<'a> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            EinError::Parse(e) => e.fmt(f),
            EinError::Runtime(e) => e.fmt(f),
            EinError::Io(e) => e.fmt(f),
            EinError::Readline(e) => e.fmt(f),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();
  let initial_search = args.initial_search.clone();
  if args.use_first {
    let matches = matching::compute_matches(&choices, initial_search.as_slice());
    println!("{}", matches[0]);
    return;
  } else {
    event_loop(choices, initial_search.as_slice());
  }
}

fn event_loop(choices: Vec<String>, initial_search: &str) {
  let mut screen = Screen::open_screen();

  let mut search = Search {
    choices: &choices,
    query: initial_search.to_string(),
    matches: Vec::new(),
    stale: true,
    index: 0,
  };
  loop {
    search.recompute_matches();
    draw_screen(&mut screen, &search.matches, search.query.as_slice(), search.choices.len(), search.index);

    let chars = screen.get_buffered_keys();
    for char in chars.iter() {
      match *char {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('u') => search.clear_query(),
        Control('c') => return,
        Control('n') => search.down(screen.visible_choices),
        Control('p') => search.up(),
        Enter => {
          screen.move_cursor_to_bottom();
          search.recompute_matches();
          println!("{}", search.matches[search.index]);
          return;
        }
        _ => panic!("Unexpected input"),
      }
    }
  }
}

struct Search<'a> {
  choices: &'a Vec<String>,
  query: String,
  matches: Vec<&'a String>,
  stale: bool,
  index: usize,
}

impl<'a> Search<'a> {
  fn up(&mut self) {
    self.index = if self.index == 0 { 0 } else { self.index - 1 };
  }

  fn down(&mut self, visible_choices: u16) {
    let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
    self.index = min(self.index + 1, limit);
  }

  fn backspace(&mut self) {
    self.query.pop();
    self.stale = true;
    self.index = 0;
  }

  fn append(&mut self, c: char) {
    self.query.push(c);
    self.stale = true;
  }

  fn clear_query(&mut self) {
    self.query.clear();
    self.stale = true;
  }

  fn recompute_matches(&mut self) {
    if self.stale {
      self.matches = matching::compute_matches(self.choices, self.query.as_slice());
      self.stale = false;
    }
  }
}

fn draw_screen(screen: &mut Screen, matches: &Vec<&String>, search: &str, choices: usize, index: usize) {
  screen.hide_cursor();
  screen.blank_screen();
  screen.write(format!("> {} ({} choices)\n", search, choices).as_slice());

  print_matches(screen, matches, index);

  let start = screen.start_line;
  screen.move_cursor(start, 2 + search.len() as u16);
  screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &Vec<&String>, index: usize) {
  let mut i = 1;
  for choice in matches.iter() {
    if i == index + 1 {
      screen.write_inverted(choice.as_slice());
    } else {
      screen.write(choice.as_slice());
    }
    if i >= screen.visible_choices as usize {
      return;
    } else {
      screen.write("\n");
    }
    i += 1;
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  while let Ok(mut s) = stdin.read_line() {
    trim(&mut s);
    lines.push(s);
  }

  lines
}

fn trim(s: &mut String) {
  while let Some(x) = s.pop() {
    if x != '\n' {
      s.push(x);
      return;
    }
  }
}
<commit_msg>Simplify 'draw_screen' parameter list<commit_after>#![allow(unstable, dead_code)]

extern crate libc;

mod args;
mod ansi;
mod matching;
mod screen;

use std::os;
use std::io;
use std::cmp::min;
use screen::Screen;
use screen::Key::*;

fn main() {
  let args = match args::parse_args() {
    Some(args) => args,
    None => {
      os::set_exit_status(1);
      return;
    },
  };

  if args.help { return; }

  let choices = read_choices();
  let initial_search = args.initial_search.clone();
  if args.use_first {
    let matches = matching::compute_matches(&choices, initial_search.as_slice());
    println!("{}", matches[0]);
    return;
  } else {
    event_loop(choices, initial_search.as_slice());
  }
}

fn event_loop(choices: Vec<String>, initial_search: &str) {
  let mut screen = Screen::open_screen();

  let mut search = Search {
    choices: &choices,
    query: initial_search.to_string(),
    matches: Vec::new(),
    stale: true,
    index: 0,
  };
  loop {
    search.recompute_matches();
    draw_screen(&mut screen, &search);

    let chars = screen.get_buffered_keys();
    for char in chars.iter() {
      match *char {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('u') => search.clear_query(),
        Control('c') => return,
        Control('n') => search.down(screen.visible_choices),
        Control('p') => search.up(),
        Enter => {
          screen.move_cursor_to_bottom();
          search.recompute_matches();
          println!("{}", search.matches[search.index]);
          return;
        }
        _ => panic!("Unexpected input"),
      }
    }
  }
}

struct Search<'a> {
  choices: &'a Vec<String>,
  query: String,
  matches: Vec<&'a String>,
  stale: bool,
  index: usize,
}

impl<'a> Search<'a> {
  fn up(&mut self) {
    self.index = if self.index == 0 { 0 } else { self.index - 1 };
  }

  fn down(&mut self, visible_choices: u16) {
    let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
    self.index = min(self.index + 1, limit);
  }

  fn backspace(&mut self) {
    self.query.pop();
    self.stale = true;
    self.index = 0;
  }

  fn append(&mut self, c: char) {
    self.query.push(c);
    self.stale = true;
  }

  fn clear_query(&mut self) {
    self.query.clear();
    self.stale = true;
  }

  fn recompute_matches(&mut self) {
    if self.stale {
      self.matches = matching::compute_matches(self.choices, self.query.as_slice());
      self.stale = false;
    }
  }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
  screen.hide_cursor();
  screen.blank_screen();
  screen.write(format!("> {} ({} choices)\n", search.query, search.matches.len()).as_slice());

  print_matches(screen, &search.matches, search.index);

  let start = screen.start_line;
  screen.move_cursor(start, 2 + search.query.len() as u16);
  screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &Vec<&String>, index: usize) {
  let mut i = 1;
  for choice in matches.iter() {
    if i == index + 1 {
      screen.write_inverted(choice.as_slice());
    } else {
      screen.write(choice.as_slice());
    }
    if i >= screen.visible_choices as usize {
      return;
    } else {
      screen.write("\n");
    }
    i += 1;
  }
}

fn read_choices() -> Vec<String> {
  let mut stdin = io::stdio::stdin();
  let mut lines = Vec::new();

  while let Ok(mut s) = stdin.read_line() {
    trim(&mut s);
    lines.push(s);
  }

  lines
}

fn trim(s: &mut String) {
  while let Some(x) = s.pop() {
    if x != '\n' {
      s.push(x);
      return;
    }
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate imgui;
extern crate mush;
use mush::interface::Interface;
use imgui::{Ui,ImStr};

use std::fs;

const CLEAR_COLOR: (f32, f32, f32, f32) = (0.006, 0.006, 0.006, 1.0);

fn main() {
    let mut ifc = Interface::init();
    let mut state = State::default();

    loop {
        let r = ifc.render(CLEAR_COLOR, |ui| {
            menu(ui, &mut state);
            open_file(ui, &mut state);
        });
        if !r | state.exit{ break }
    }
}

struct State {
    exit: bool,
    open_file: bool,
    current_dir: String,
    current_dir_list: i32,
}
impl Default for State {
    fn default() -> Self {
        State {
            exit: false,
            open_file: true,
            current_dir: "./".to_owned(),
            current_dir_list: 0,
        }
    }
}

fn menu (ui: &Ui, state: &mut State) {
    ui.main_menu_bar(|| {
        ui.menu(im_str!("File"))
            .build(|| {
                ui.menu_item(im_str!("Open"))
                    .selected(&mut state.open_file)
                    .build();

                ui.menu_item(im_str!("Exit"))
                    .selected(&mut state.exit)
                    .build();
            });
    });
}

fn open_file (ui: &Ui, state: &mut State) {
    if !state.open_file { return }

    let mut cd = fs::read_dir(&state.current_dir);

    ui.window(im_str!("Select source"))
        .always_auto_resize(true)
        .movable(true)
        .show_borders(true)
        //.opened(&mut state.open_file) // FIXME:borrow check issues with closures
        .build(||{
            ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
            ui.separator();
            ui.input_text(im_str!("Current Directory"), &mut state.current_dir)
                .build();
            ui.separator();

            if let Ok(ref mut paths) = cd {
                let paths: Vec<ImStr> = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        im_str!("{:}", p.unwrap().path().display())
                    })
                    .collect();

                ui.list_box(im_str!("Files"),
                            &mut state.current_dir_list,
                            &paths[..],
                            paths.len() as i32);

            }
        })
}
<commit_msg>input field for file selector<commit_after>#[macro_use]
extern crate imgui;
extern crate mush;
use mush::interface::Interface;
use imgui::{Ui,ImStr,ImString};

use std::fs;
//use std::path::Path;

use std::time::{Duration,Instant};
use std::thread;

const CLEAR_COLOR: (f32, f32, f32, f32) = (0.006, 0.006, 0.006, 1.0);

/// represents 15ms as nanos
static FPS_60: u32 = 15000000;

fn main() {
    let mut ifc = Interface::init();
    let mut state = State::default();
    let mut filestate = FileState::default();

    loop {
        let start_time = Instant::now();

        let r = ifc.render(CLEAR_COLOR, |ui| {
            menu(ui, &mut state);
            open_file(ui, &mut state, &mut filestate);
        });
        if !r | state.exit{ break }

        maybe_sleep(start_time); // we must manage sleep if we run too fast
    }
}

fn maybe_sleep(start_time: Instant) {
    let duration = Duration::new(0,FPS_60);
    if start_time.elapsed() < duration {
        let delay = duration - start_time.elapsed();
        thread::sleep(delay);
    }
}

struct State {
    exit: bool,
    open_file: bool,
}
impl Default for State {
    fn default() -> Self {
        State {
            exit: false,
            open_file: true,
        }
    }
}

struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 0,
            files: vec![],
        }
    }
}

impl FileState {
    fn update(&mut self) {
        if let Ok(paths) = fs::read_dir(&self.cd.to_string()) {
            self.files = paths
                .filter(|p| p.is_ok())
                .map(|p| {
                    p.unwrap().path().as_path().to_str().unwrap().to_owned()
                })
                .collect();
        }
    }
}

fn menu (ui: &Ui, state: &mut State) {
    ui.main_menu_bar(|| {
        ui.menu(im_str!("File"))
            .build(|| {
                ui.menu_item(im_str!("Open"))
                    .selected(&mut state.open_file)
                    .build();

                ui.menu_item(im_str!("Exit"))
                    .selected(&mut state.exit)
                    .build();
            });
    });
}

fn open_file (ui: &Ui, state: &mut State, filestate: &mut FileState) {
    if !state.open_file { return }

    ui.window(im_str!("Select source"))
        .always_auto_resize(true)
        .movable(true)
        .show_borders(true)
        .opened(&mut state.open_file)
        .build(||{
            ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
            ui.separator();
            ui.input_text(im_str!("Current Directory"), &mut filestate.cd)
                .enter_returns_true(true)
                .build();
            ui.separator();

            filestate.update();

            // NOTE: to appease the borrow checker and have the proper argument for list_box
            // we must do build the list in two steps
            let paths: Vec<ImString> = filestate.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                })
                .collect();

            let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

            ui.list_box(im_str!("Files"),
                        &mut filestate.idx,
                        &paths[..],
                        paths.len() as i32);
        })
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>create basic rustyline loop<commit_after>extern crate rustyline;
use rustyline::Editor;
use rustyline::error::ReadlineError;

fn main() {
    let mut line_editor = Editor::<()>::new();
    loop {
        let line_result = line_editor.readline("> ");
        match line_result {
            Ok(line) => println!("{}", line),
            Err(ReadlineError::Interrupted) => {
                return;
            },
            Err(ReadlineError::Eof) => {
                return;
            },
            Err(err) => {
                eprintln!("{:?}", err);
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate reqwest;

use clap::{Arg, App};
use std::io;
use std::io::BufWriter;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::process;

enum ExitStatus {
    UrlFailure = 1,
    OutputFailure = 2,
}

fn exit(exit_status: ExitStatus) -> ! {
    process::exit(exit_status as i32);
}

fn main() {
    let args = App::new("download")
        .version("0.1.0")
        .about("remote file downloader command-line interface")
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("OUTPUT")
            .help("output filename")
            .takes_value(true))
        .arg(Arg::with_name("remote-name")
            .short("O")
            .long("remote-name")
            .help("output to a file using the same name as the remote"))
        .arg(Arg::with_name("url").required(true))
        .get_matches();

    let source_url = args.value_of("url").unwrap();
    let mut res = reqwest::get(source_url)
        .unwrap_or_else(|_| process::exit(ExitStatus::UrlFailure as i32));
    if let Some(output_filename) = args.value_of("output") {
        let _ = File::create(Path::new(output_filename))
            .and_then(|output_file| {
                let mut writer = BufWriter::new(output_file);
                io::copy(&mut res, &mut writer)?;
                writer.flush()?;
                Ok(())
            })
            .map_err(|_| exit(ExitStatus::OutputFailure));
    } else {
        io::copy(&mut res, &mut io::stdout())
            .unwrap_or_else(|_| exit(ExitStatus::OutputFailure));
    }

    ()
}
<commit_msg>Fixing remote-name option<commit_after>extern crate clap;
extern crate reqwest;

use clap::{Arg, App};
use std::io;
use std::io::BufWriter;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::process;

enum ExitStatus {
    UrlFailure = 1,
    OutputFailure = 2,
}

fn exit(exit_status: ExitStatus) -> ! {
    process::exit(exit_status as i32);
}

fn get_filename(url: &str) -> Option<&str> {
    url.rsplit('/').next()
}

fn main() {
    let args = App::new("download")
                   .version("0.1.0")
                   .about("remote file downloader command-line interface")
                   .arg(Arg::with_name("output")
                            .short("o")
                            .long("output")
                            .value_name("OUTPUT")
                            .help("output filename")
                            .takes_value(true))
                   .arg(Arg::with_name("remote-name")
                            .short("O")
                            .long("remote-name")
                            .help("output to a file using the same name as the remote"))
                   .arg(Arg::with_name("url").required(true))
                   .get_matches();

    let source_url = args.value_of("url").unwrap();
    let mut res = reqwest::get(source_url)
                      .unwrap_or_else(|e| {
                          let _ = writeln!(&mut std::io::stderr(), "{}", e);
                          process::exit(ExitStatus::UrlFailure as i32)
                      });

    let output_filename = {
        if args.is_present("remote-name") {
            get_filename(source_url)
        } else {
            args.value_of("output")
        }
    };

    if let Some(fname) = output_filename {
        let _ = File::create(Path::new(fname))
            .and_then(|output_file| {
                let mut writer = BufWriter::new(output_file);
                io::copy(&mut res, &mut writer)?;
                writer.flush()?;
                Ok(())
            })
            .map_err(|e| {
                let _ = writeln!(&mut std::io::stderr(), "{}", e);
                exit(ExitStatus::OutputFailure);
            });
    } else {
        io::copy(&mut res, &mut io::stdout())
            .unwrap_or_else(|e| {
                let _ = writeln!(&mut std::io::stderr(), "{}", e);
                exit(ExitStatus::OutputFailure)
            });
    }

    ()
}
<|endoftext|>


<commit_before>//#![feature(plugin)]
//
//#[plugin]
//extern crate clippy;

extern crate cli;
extern crate getopts;
extern crate hyper;

use std::os;
use std::env;
use std::old_io::fs;
use getopts::Options;

static FONT_EXTENSIONS : [&'static str; 2] = ["ttf", "otf", "pcf", "bdf"];

fn main() {
    let mut opts = Options::new();
    cli::helpopt(&mut opts);
    cli::versionopt(&mut opts);
    opts.optflag("l", "list", "List installed fonts");
    opts.optopt("s", "search", "Search font", "FONTNAME");
    opts.optmulti("i", "install", "Install font(s) require a --source", "FONTNAME");
    opts.optmulti("d", "delete", "Delete font(s)", "FONTNAME");
    opts.optmulti("s", "source", "Source file to use", "FILENAME");

    let matches = cli::parse_args(&opts);

    if matches.opt_present("help") {
        println!("{}", cli::usage_string(&opts));
        return;
    }
    if matches.opt_present("version") {
        println!("{}", cli::version_string("0.0.1"));
        return;
    }
    if matches.opt_present("list") {
        list_installed_fonts();
    }
    if matches.opt_present("search") {
        search_font(&*matches.opt_str("search").unwrap());
    }
    if matches.opt_present("install") {
        if matches.opt_present("source") {
            install_font(&*matches.opt_str("source").unwrap(), &*matches.opt_str("install").unwrap());
        } else {
            println!("{}", opts.usage("ttoo"));
        }
    }
    if matches.opt_present("delete") {
        delete_font(&*matches.opt_str("delete").unwrap());
    }
}

fn get_font_dir() -> Path {
    match env::consts::OS {
        "linux" => {
            match env::home_dir() {
                Some(ref p) => p.join(".fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "macos" => {
            match env::home_dir() {
                Some(ref p) => p.join("Library").join("Fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "windows" => {
            match os::getenv("SystemRoot") {
                Some(val) => Path::new(val).join("Fonts"),
                None => panic!("Impossible to get your font dir!")
            }
        },
        _ => unreachable!(),
    }
}

fn get_font_path(font_name: &str) -> Path {
    get_font_dir().join(font_name)
}

fn list_installed_fonts() {
    let font_dir = get_font_dir();
    match fs::readdir(&font_dir) {
        Ok(fonts) => {
            let mut it_fonts = fonts.iter().filter(|&f| {
                FONT_EXTENSIONS.iter().find(|&ext| {
                    *f.extension_str().unwrap().to_string() == *ext.to_string()
                }).is_some()
            });
            for font in it_fonts {
                if let Some(font_name) = font.filename_str() {
                    println!("{}", font_name);
                }
            }
        }
        Err(msg) => println!("{}", msg)
    }
}

fn search_font(font_name: &str) {
    let mut client = hyper::Client::new();
    let url = format!("http://api.github.com/search/repositories?q={}+in:name&sort=stars&order=desc", font_name);
    let resp = client.get(&*url).send();
    match resp {
        Ok(mut data) => match data.read_to_string() {
            Ok(body) => println!("body={}", body),
            Err(err) => println!("{}", err)
        },
        Err(err) => println!("{}", err)
    };
}

fn install_font(source: &str, font_name: &str) {
    let dest_font_path = get_font_path(font_name);
    match fs::copy(&Path::new(source), &dest_font_path) {
        Ok(_) => println!("Font {} installed successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

fn delete_font(font_name: &str) {
    let font_path = get_font_path(font_name);
    match fs::unlink(&font_path) {
        Ok(_) => println!("Font {} deleted successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

<commit_msg>Rustup ugly fix<commit_after>//#![feature(plugin)]
//
//#[plugin]
//extern crate clippy;

extern crate cli;
extern crate getopts;
extern crate hyper;

use std::os;
use std::{env, fs, io, path};
use std::io::Read;
use getopts::Options;

static FONT_EXTENSIONS : [&'static str; 4] = ["ttf", "otf", "pcf", "bdf"];

fn main() {
    let mut opts = Options::new();
    cli::helpopt(&mut opts);
    cli::versionopt(&mut opts);
    opts.optflag("l", "list", "List installed fonts");
    opts.optopt("s", "search", "Search font", "FONTNAME");
    opts.optmulti("i", "install", "Install font(s) require a --source", "FONTNAME");
    opts.optmulti("d", "delete", "Delete font(s)", "FONTNAME");
    opts.optmulti("s", "source", "Source file to use", "FILENAME");

    let matches = cli::parse_args(&opts);

    if matches.opt_present("help") {
        println!("{}", cli::usage_string(&opts));
        return;
    }
    if matches.opt_present("version") {
        println!("{}", cli::version_string("0.0.1"));
        return;
    }
    if matches.opt_present("list") {
        list_installed_fonts();
    }
    if matches.opt_present("search") {
        search_font(&*matches.opt_str("search").unwrap());
    }
    if matches.opt_present("install") && matches.opt_present("source") {
        install_font(&*matches.opt_str("source").unwrap(), &*matches.opt_str("install").unwrap());
    } else {
        println!("{}", opts.usage("ttoo"));
    }
    if matches.opt_present("delete") {
        delete_font(&*matches.opt_str("delete").unwrap());
    }
}

fn get_font_dir() -> path::PathBuf {
    match env::consts::OS {
        "linux" => {
            match env::home_dir() {
                Some(ref p) => p.join(".fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "macos" => {
            match env::home_dir() {
                Some(ref p) => p.join("Library").join("Fonts"),
                None => panic!("Impossible to get your home dir!")
            }
        },
        "windows" => {
            match os::getenv("SystemRoot") {
                Some(ref val) => path::Path::new(val).join("Fonts"),
                None => panic!("Impossible to get your font dir!")
            }
        },
        _ => unreachable!(),
    }
}

fn get_font_path(font_name: &str) -> path::PathBuf {
    get_font_dir().join(font_name.as_slice())
}

//let dir_results: Vec<_> = std::fs::read_dir("foo").and_then(|dir| dir.collect());
//
//let dir_results: Vec<_> = std::fs::read_dir("foo").and_then(|dir| dir.collect()).unwrap() ;
//
//let dir_results: Result<Vec<_>, _> = std::fs::read_dir("foo").and_then(|dir| dir.collect());

fn list_installed_fonts() {
    let font_dir = get_font_dir();
    match fs::read_dir(&font_dir) {
        Ok(fonts) => {
            let mut it_fonts = fonts.filter(|ref f| {
                FONT_EXTENSIONS.iter().find(|&ext| {
                    //*f.unwrap().path().extension().unwrap()..into_string() == *ext.to_string()
                 true
                }).is_some()
            });
            for font in it_fonts {
                if let Some(font_name) = font.ok().unwrap().path().file_name().unwrap().to_str() {
                    println!("{}", font_name);
                }
            }
        }
        Err(msg) => println!("{}", msg)
    }
}

fn search_font(font_name: &str) {
    let mut client = hyper::Client::new();
    let url = format!("http://api.github.com/search/repositories?q={}+in:name&sort=stars&order=desc", font_name);
    let resp = client.get(&*url).send();
    match resp {
        Ok(mut data) => {
            let mut body = String::new();
            data.read_to_string(&mut body).ok();
            println!("body={}", body);
        },
        Err(err) => println!("{}", err)
    };
}

fn install_font(source: &str, font_name: &str) {
    let dest_font_path = get_font_path(font_name);
    match fs::copy(&Path::new(source), &dest_font_path) {
        Ok(_) => println!("Font {} installed successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

fn delete_font(font_name: &str) {
    let font_path = get_font_path(font_name);
    match fs::remove_file(&font_path) {
        Ok(_) => println!("Font {} deleted successfully", font_name),
        Err(msg) => println!("{}", msg)
    }
}

<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate hyper;

use rustc_serialize::json;
use rustc_serialize::json::Json;
#[macro_use] extern crate nickel;

use nickel::status::StatusCode;
use nickel::{Nickel, HttpRouter, MediaType, JsonBody};

#[derive(RustcDecodable, RustcEncodable)]
struct Todo {
  status: i32,
  title: String,
}

fn main() {
  let mut server = Nickel::new();
  let mut router = Nickel::router();

  // index
  router.get("/api/todos", middleware! { |_, mut _res|
    let mut v: Vec<Todo> = vec![];
    let todo1 = Todo{
      status: 0,
      title: "Shopping".to_string(),
    };
    v.push(todo1);
    let todo2 = Todo{
      status: 1,
      title: "Movie".to_string(),
    };
    v.push(todo2);

    let json_obj = json::encode(&v).unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  // detail
  router.get("/api/todos/:id", middleware! { |_req, mut _res|
    let id = _req.param("id");
    println!("id: {:?}", id);

    let todo1 = Todo{
      status: 0,
      title: "Shopping".to_string(),
    };
    let json_obj = json::encode(&todo1).unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  // delete
  router.delete("/api/todos/:id", middleware! { |_req, mut _res|
    let id = _req.param("id");
    println!("delete id: {:?}", id);

    let json_obj = Json::from_str("{}").unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  // create
  router.post("/api/todos", middleware! { |_req, mut _res|
    let todo = _req.json_as::<Todo>().unwrap();
    println!("post todo: {} {}", todo.status, todo.title);

    let json_obj = json::encode(&todo).unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Created);
    return _res.send(json_obj);
  });

  // update
  router.put("/api/todos/:id", middleware! { |_req, mut _res|
    // let id = _req.param("id");
    let todo = _req.json_as::<Todo>().unwrap();
    // println!("post todo: {:?} {} {}", id, todo.status, todo.title);
    println!("post todo: {} {}", todo.status, todo.title);

    let json_obj = json::encode(&todo).unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  server.utilize(router);
  server.listen("127.0.0.1:6767");
}
<commit_msg>delete comment<commit_after>extern crate rustc_serialize;
extern crate hyper;

use rustc_serialize::json;
use rustc_serialize::json::Json;
#[macro_use] extern crate nickel;

use nickel::status::StatusCode;
use nickel::{Nickel, HttpRouter, MediaType};

#[derive(RustcDecodable, RustcEncodable)]
struct Todo {
  status: i32,
  title: String,
}

fn main() {
  let mut server = Nickel::new();
  let mut router = Nickel::router();

  // index
  router.get("/api/todos", middleware! { |_, mut _res|
    let mut v: Vec<Todo> = vec![];
    let todo1 = Todo{
      status: 0,
      title: "Shopping".to_string(),
    };
    v.push(todo1);
    let todo2 = Todo{
      status: 1,
      title: "Movie".to_string(),
    };
    v.push(todo2);

    let json_obj = json::encode(&v).unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  // detail
  router.get("/api/todos/:id", middleware! { |_req, mut _res|
    let id = _req.param("id");
    println!("id: {:?}", id);

    let todo1 = Todo{
      status: 0,
      title: "Shopping".to_string(),
    };
    let json_obj = json::encode(&todo1).unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  // delete
  router.delete("/api/todos/:id", middleware! { |_req, mut _res|
    let id = _req.param("id");
    println!("delete id: {:?}", id);

    let json_obj = Json::from_str("{}").unwrap();
    _res.set(MediaType::Json);
    _res.set(StatusCode::Ok);
    return _res.send(json_obj);
  });

  server.utilize(router);
  server.listen("127.0.0.1:6767");
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops;

trait Currency {
    type Value;
    fn to_normal(&self) -> f32;
    fn from_normal(f32) -> Self::Value;
}

macro_rules! currency {
    ($t:ident, $c:expr) => {
        #[derive(Copy, Clone)]
        struct $t(f32);

        impl Currency for $t {
            type Value = $t;
            fn to_normal(&self) -> f32 { self.0 * $c }
            fn from_normal(n: f32) -> Self::Value { $t(n / $c) }
        }

        impl<C: Currency> ops::Add<C> for $t {
            type Output = <Self as Currency>::Value;

            fn add(self, rhs: C) -> Self::Output {
                Self::Output::from_normal(self.to_normal() + rhs.to_normal())
            }
        }

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

currency!(Credits, 1.0);
currency!(CBills, 97.1);

fn main() {
    let x = Credits(232.0);
    let y = CBills(25.0);

    println!("{}", x + y);
    println!("{}", y + x);
}
<commit_msg>Add conversion<commit_after>use std::fmt;
use std::ops;

trait Currency {
    type Value;
    fn to_normal(&self) -> f32;
    fn from_normal(f32) -> Self::Value;
    fn to<C: Currency>(&self) -> <C as Currency>::Value;
}

macro_rules! currency {
    ($t:ident, $c:expr) => {
        #[derive(Copy, Clone)]
        struct $t(f32);

        impl Currency for $t {
            type Value = $t;

            fn to_normal(&self) -> f32 {
                self.0 * $c
            }

            fn from_normal(n: f32) -> Self::Value {
                $t(n / $c)
            }

            fn to<C: Currency>(&self) -> <C as Currency>::Value {
                C::from_normal(self.to_normal())
            }
        }

        impl<C: Currency> ops::Add<C> for $t {
            type Output = <Self as Currency>::Value;

            fn add(self, rhs: C) -> Self::Output {
                Self::Output::from_normal(self.to_normal() + rhs.to_normal())
            }
        }

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

currency!(Credits, 1.0);
currency!(CBills, 100.0);

fn main() {
    let amount = CBills(10.00).to::<Credits>();

    println!("{}", amount);
}
<|endoftext|>