<commit_before>#![feature(slicing_syntax)]
#![feature(if_let)]
#![feature(phase)]

extern crate collections;
extern crate time;

#[phase(plugin, link)]
extern crate log;

use std::collections::HashMap;
use std::io::{BufferedReader, File};
use std::str::CharSplits;
use time::precise_time_ns;

use collections::hash::Hash;

use numeric::Numeric;

mod numeric;

trait PrimaryKey<T> {
    fn primary_key(&self) -> T;
}

trait FromRow {
    fn from_row(mut row: CharSplits<char>) -> Self;
}

#[deriving(Show)]
struct Table<Data, Index: Eq + Hash> {
    rows: Vec<Data>,
    index: HashMap<Index, uint>
}

impl<Data: PrimaryKey<Index> + Clone, Index: Eq + Hash> Table<Data, Index> {
    fn new() -> Table<Data, Index> {
        Table {
            rows: Vec::new(),
            index: HashMap::new()
        }
    }

    fn insert(&mut self, data: Data) {
        self.rows.push(data.clone());
        self.index.insert(data.primary_key(), self.rows.len() - 1);
    }

    fn size(&self) -> uint {
        self.rows.len()
    }
}

#[deriving(Clone, Show)]
struct Warehouse {
    w_id: i32,
    w_name: String,
    w_street_1: String,
    w_street_2: String,
    w_city: String,
    w_state: String,
    w_zip: String,
    w_tax: Numeric, // numeric(4, 4)
    w_ytd: Numeric, // numeric(12, 2)
}

impl PrimaryKey<i32> for Warehouse {
    fn primary_key(&self) -> i32 {
        self.w_id
    }
}

impl FromRow for Warehouse {
    fn from_row(mut row: CharSplits<char>) -> Warehouse {
        Warehouse {
            w_id: from_str(row.next().unwrap()).unwrap(),
            w_name: row.next().unwrap().into_string(),
            w_street_1: row.next().unwrap().into_string(),
            w_street_2: row.next().unwrap().into_string(),
            w_city: row.next().unwrap().into_string(),
            w_state: row.next().unwrap().into_string(),
            w_zip: row.next().unwrap().into_string(),
            w_tax: Numeric::from_str(row.next().unwrap(), 4, 4).unwrap(),
            w_ytd: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(),
        }
    }
}

type WarehouseTable = Table<Warehouse, i32>;

#[deriving(Clone, Show)]
struct District {
    d_id: i32,
    d_w_id: i32,
    d_name: String,
    d_street_1: String,
    d_street_2: String,
    d_city: String,
    d_state: String,
    d_zip: String,
    d_tax: Numeric, // numeric(4, 4)
    d_ytd: Numeric, // numeric(12,2)
    d_next_o_id: i32,
}

impl PrimaryKey<(i32, i32)> for District {
    fn primary_key(&self) -> (i32, i32) {
        (self.d_w_id, self.d_id)
    }
}

impl FromRow for District {
    fn from_row(mut row: CharSplits<char>) -> District {
        District {
            d_id: from_str(row.next().unwrap()).unwrap(),
            d_w_id: from_str(row.next().unwrap()).unwrap(),
            d_name: row.next().unwrap().into_string(),
            d_street_1: row.next().unwrap().into_string(),
            d_street_2: row.next().unwrap().into_string(),
            d_city: row.next().unwrap().into_string(),
            d_state: row.next().unwrap().into_string(),
            d_zip: row.next().unwrap().into_string(),
            d_tax: Numeric::from_str(row.next().unwrap(), 4, 4).unwrap(),
            d_ytd: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(),
            d_next_o_id: from_str(row.next().unwrap()).unwrap(),
        }
    }
}

type DistrictTable = Table<District, (i32, i32)>;

#[deriving(Clone, Show)]
struct Customer {
    c_id: i32,
    c_d_id: i32,
    c_w_id: i32,
    c_first: String,
    c_middle: String,
    c_last: String,
    c_street_1: String,
    c_street_2: String,
    c_city: String,
    c_state: String,
    c_zip: String,
    c_phone: String,
    c_since: i32, // Timestamp
    c_credit: String,
    c_credit_lim: Numeric, // numeric(12,2)
    c_discount: Numeric, // numeric(4, 4)
    c_balance: Numeric, // numeric(12,2)
    c_ytd_paymenr: Numeric, // numeric(12,2)
    c_payment_cnt: Numeric, // numeric(4,0)
    c_delivery_cnt: Numeric, // numeric(4,0)
    c_data: String,
}

impl PrimaryKey<(i32, i32, i32)> for Customer {
    fn primary_key(&self) -> (i32, i32, i32) {
        (self.c_w_id, self.c_d_id, self.c_id)
    }
}

impl FromRow for Customer {
    fn from_row(mut row: CharSplits<char>) -> Customer {
        Customer {
            c_id: from_str(row.next().unwrap()).unwrap(),
            c_d_id: from_str(row.next().unwrap()).unwrap(),
            c_w_id: from_str(row.next().unwrap()).unwrap(),
            c_first: row.next().unwrap().into_string(),
            c_middle: row.next().unwrap().into_string(),
            c_last: row.next().unwrap().into_string(),
            c_street_1: row.next().unwrap().into_string(),
            c_street_2: row.next().unwrap().into_string(),
            c_city: row.next().unwrap().into_string(),
            c_state: row.next().unwrap().into_string(),
            c_zip: row.next().unwrap().into_string(),
            c_phone: row.next().unwrap().into_string(),
            c_since: from_str(row.next().unwrap()).unwrap(), // Timestamp
            c_credit: row.next().unwrap().into_string(),
            c_credit_lim: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(), // numeric(12,2)
            c_discount: Numeric::from_str(row.next().unwrap(), 4, 4).unwrap(), // numeric(4, 4)
            c_balance: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(), // numeric(12,2)
            c_ytd_paymenr: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(), // numeric(12,2)
            c_payment_cnt: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(), // numeric(4,0)
            c_delivery_cnt: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(), // numeric(4,0)
            c_data: row.next().unwrap().into_string(),
        }
    }
}

type CustomerTable = Table<Customer, (i32, i32, i32)>;

#[deriving(Clone, Show)]
struct Neworder {
    no_o_id: i32,
    no_d_id: i32,
    no_w_id: i32,
}

impl PrimaryKey<(i32, i32, i32)> for Neworder {
    fn primary_key(&self) -> (i32, i32, i32) {
        (self.no_w_id, self.no_d_id, self.no_o_id)
    }
}

impl FromRow for Neworder {
    fn from_row(mut row: CharSplits<char>) -> Neworder {
        Neworder {
            no_o_id: from_str(row.next().unwrap()).unwrap(),
            no_d_id: from_str(row.next().unwrap()).unwrap(),
            no_w_id: from_str(row.next().unwrap()).unwrap(),
        }
    }
}

type NeworderTable = Table<Neworder, (i32, i32, i32)>;

#[deriving(Clone, Show)]
struct Order {
    o_id: i32,
    o_d_id: i32,
    o_w_id: i32,
    o_c_id: i32,
    o_entry_d: i32, // Timestamp
    o_carrier_id: i32,
    o_ol_cnt: Numeric, // numeric(2,0)
    o_all_local: Numeric, // numeric(1, 0)
}

impl PrimaryKey<(i32, i32, i32)> for Order {
    fn primary_key(&self) -> (i32, i32, i32) {
        (self.o_w_id, self.o_d_id, self.o_id)
    }
}

impl FromRow for Order {
    fn from_row(mut row: CharSplits<char>) -> Order {
        Order {
            o_id: from_str(row.next().unwrap()).unwrap(),
            o_d_id: from_str(row.next().unwrap()).unwrap(),
            o_w_id: from_str(row.next().unwrap()).unwrap(),
            o_c_id: from_str(row.next().unwrap()).unwrap(),
            o_entry_d: from_str(row.next().unwrap()).unwrap(),
            o_carrier_id: from_str(row.next().unwrap()).unwrap(),
            o_ol_cnt: Numeric::from_str(row.next().unwrap(), 2, 0).unwrap(),
            o_all_local: Numeric::from_str(row.next().unwrap(), 1, 0).unwrap(),
        }
    }
}

type OrderTable = Table<Order, (i32, i32, i32)>;

struct Tables {
    warehouse_table: WarehouseTable,
    district_table: DistrictTable,
    customer_table: CustomerTable,
    neworder_table: NeworderTable,
    order_table: OrderTable,
}

impl Tables {
    fn new() -> Tables {
        Tables {
            warehouse_table: Table::new(),
            district_table: Table::new(),
            customer_table: Table::new(),
            neworder_table: Table::new(),
            order_table: Table::new(),
        }
    }
}

fn read_table<Data: Clone + FromRow + PrimaryKey<Index>, Index: Eq + Hash>
        (filename: &str, table: &mut Table<Data, Index>) {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
        let row = FromRow::from_row(line.unwrap()[].trim_chars('\n').split('|'));
        table.insert(row);
    }
}

fn read_tables(tables: &mut Tables) {
    read_table::<Warehouse, i32>("../data/tpcc_warehouse.tbl", &mut tables.warehouse_table);
    read_table::<District, (i32, i32)>("../data/tpcc_district.tbl", &mut tables.district_table);
    read_table::<Customer, (i32, i32, i32)>("../data/tpcc_customer.tbl", &mut tables.customer_table);
    read_table::<Neworder, (i32, i32, i32)>("../data/tpcc_neworder.tbl", &mut tables.neworder_table);
    read_table::<Order, (i32, i32, i32)>("../data/tpcc_order.tbl", &mut tables.order_table);
}

fn main() {
    let time = precise_time_ns();

    let tables: &mut Tables =  &mut Tables::new();
    read_tables(tables);
    println!("Warehouse: {}", tables.warehouse_table.size());
    println!("District: {}", tables.district_table.size());
    println!("Customer: {}", tables.customer_table.size());
    println!("Neworder: {}", tables.neworder_table.size());
    println!("Order: {}", tables.order_table.size());

    println!("insert {}s", ((precise_time_ns() - time) as f64) / 1e9f64);
}
<commit_msg>parse all tables<commit_after>#![feature(slicing_syntax)]
#![feature(if_let)]
#![feature(phase)]

extern crate collections;
extern crate time;

#[phase(plugin, link)]
extern crate log;

use std::collections::HashMap;
use std::io::{BufferedReader, File};
use std::str::CharSplits;
use time::precise_time_ns;

use collections::hash::Hash;

use numeric::Numeric;

mod numeric;

trait PrimaryKey<T> {
    fn primary_key(&self) -> T;
}

trait FromRow {
    fn from_row(mut row: CharSplits<char>) -> Self;
}

#[deriving(Show)]
struct Table<Data, Index: Eq + Hash> {
    rows: Vec<Data>,
    index: HashMap<Index, uint>
}

impl<Data: PrimaryKey<Index> + Clone, Index: Eq + Hash> Table<Data, Index> {
    fn new() -> Table<Data, Index> {
        Table {
            rows: Vec::new(),
            index: HashMap::new()
        }
    }

    fn insert(&mut self, data: Data) {
        self.rows.push(data.clone());
        self.index.insert(data.primary_key(), self.rows.len() - 1);
    }

    fn size(&self) -> uint {
        self.rows.len()
    }
}

#[deriving(Clone, Show)]
struct Warehouse {
    w_id: i32,
    w_name: String,
    w_street_1: String,
    w_street_2: String,
    w_city: String,
    w_state: String,
    w_zip: String,
    w_tax: Numeric, // numeric(4, 4)
    w_ytd: Numeric, // numeric(12, 2)
}

impl PrimaryKey<i32> for Warehouse {
    fn primary_key(&self) -> i32 {
        self.w_id
    }
}

impl FromRow for Warehouse {
    fn from_row(mut row: CharSplits<char>) -> Warehouse {
        Warehouse {
            w_id: from_str(row.next().unwrap()).unwrap(),
            w_name: row.next().unwrap().into_string(),
            w_street_1: row.next().unwrap().into_string(),
            w_street_2: row.next().unwrap().into_string(),
            w_city: row.next().unwrap().into_string(),
            w_state: row.next().unwrap().into_string(),
            w_zip: row.next().unwrap().into_string(),
            w_tax: Numeric::from_str(row.next().unwrap(), 4, 4).unwrap(),
            w_ytd: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(),
        }
    }
}

type WarehouseTable = Table<Warehouse, i32>;

#[deriving(Clone, Show)]
struct District {
    d_id: i32,
    d_w_id: i32,
    d_name: String,
    d_street_1: String,
    d_street_2: String,
    d_city: String,
    d_state: String,
    d_zip: String,
    d_tax: Numeric, // numeric(4, 4)
    d_ytd: Numeric, // numeric(12,2)
    d_next_o_id: i32,
}

impl PrimaryKey<(i32, i32)> for District {
    fn primary_key(&self) -> (i32, i32) {
        (self.d_w_id, self.d_id)
    }
}

impl FromRow for District {
    fn from_row(mut row: CharSplits<char>) -> District {
        District {
            d_id: from_str(row.next().unwrap()).unwrap(),
            d_w_id: from_str(row.next().unwrap()).unwrap(),
            d_name: row.next().unwrap().into_string(),
            d_street_1: row.next().unwrap().into_string(),
            d_street_2: row.next().unwrap().into_string(),
            d_city: row.next().unwrap().into_string(),
            d_state: row.next().unwrap().into_string(),
            d_zip: row.next().unwrap().into_string(),
            d_tax: Numeric::from_str(row.next().unwrap(), 4, 4).unwrap(),
            d_ytd: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(),
            d_next_o_id: from_str(row.next().unwrap()).unwrap(),
        }
    }
}

type DistrictTable = Table<District, (i32, i32)>;

#[deriving(Clone, Show)]
struct Customer {
    c_id: i32,
    c_d_id: i32,
    c_w_id: i32,
    c_first: String,
    c_middle: String,
    c_last: String,
    c_street_1: String,
    c_street_2: String,
    c_city: String,
    c_state: String,
    c_zip: String,
    c_phone: String,
    c_since: i32, // Timestamp
    c_credit: String,
    c_credit_lim: Numeric, // numeric(12,2)
    c_discount: Numeric, // numeric(4, 4)
    c_balance: Numeric, // numeric(12,2)
    c_ytd_paymenr: Numeric, // numeric(12,2)
    c_payment_cnt: Numeric, // numeric(4,0)
    c_delivery_cnt: Numeric, // numeric(4,0)
    c_data: String,
}

impl PrimaryKey<(i32, i32, i32)> for Customer {
    fn primary_key(&self) -> (i32, i32, i32) {
        (self.c_w_id, self.c_d_id, self.c_id)
    }
}

impl FromRow for Customer {
    fn from_row(mut row: CharSplits<char>) -> Customer {
        Customer {
            c_id: from_str(row.next().unwrap()).unwrap(),
            c_d_id: from_str(row.next().unwrap()).unwrap(),
            c_w_id: from_str(row.next().unwrap()).unwrap(),
            c_first: row.next().unwrap().into_string(),
            c_middle: row.next().unwrap().into_string(),
            c_last: row.next().unwrap().into_string(),
            c_street_1: row.next().unwrap().into_string(),
            c_street_2: row.next().unwrap().into_string(),
            c_city: row.next().unwrap().into_string(),
            c_state: row.next().unwrap().into_string(),
            c_zip: row.next().unwrap().into_string(),
            c_phone: row.next().unwrap().into_string(),
            c_since: from_str(row.next().unwrap()).unwrap(), // Timestamp
            c_credit: row.next().unwrap().into_string(),
            c_credit_lim: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(), // numeric(12,2)
            c_discount: Numeric::from_str(row.next().unwrap(), 4, 4).unwrap(), // numeric(4, 4)
            c_balance: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(), // numeric(12,2)
            c_ytd_paymenr: Numeric::from_str(row.next().unwrap(), 12, 2).unwrap(), // numeric(12,2)
            c_payment_cnt: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(), // numeric(4,0)
            c_delivery_cnt: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(), // numeric(4,0)
            c_data: row.next().unwrap().into_string(),
        }
    }
}

type CustomerTable = Table<Customer, (i32, i32, i32)>;

#[deriving(Clone, Show)]
struct Neworder {
    no_o_id: i32,
    no_d_id: i32,
    no_w_id: i32,
}

impl PrimaryKey<(i32, i32, i32)> for Neworder {
    fn primary_key(&self) -> (i32, i32, i32) {
        (self.no_w_id, self.no_d_id, self.no_o_id)
    }
}

impl FromRow for Neworder {
    fn from_row(mut row: CharSplits<char>) -> Neworder {
        Neworder {
            no_o_id: from_str(row.next().unwrap()).unwrap(),
            no_d_id: from_str(row.next().unwrap()).unwrap(),
            no_w_id: from_str(row.next().unwrap()).unwrap(),
        }
    }
}

type NeworderTable = Table<Neworder, (i32, i32, i32)>;

#[deriving(Clone, Show)]
struct Order {
    o_id: i32,
    o_d_id: i32,
    o_w_id: i32,
    o_c_id: i32,
    o_entry_d: i32, // Timestamp
    o_carrier_id: i32,
    o_ol_cnt: Numeric, // numeric(2,0)
    o_all_local: Numeric, // numeric(1, 0)
}

impl PrimaryKey<(i32, i32, i32)> for Order {
    fn primary_key(&self) -> (i32, i32, i32) {
        (self.o_w_id, self.o_d_id, self.o_id)
    }
}

impl FromRow for Order {
    fn from_row(mut row: CharSplits<char>) -> Order {
        Order {
            o_id: from_str(row.next().unwrap()).unwrap(),
            o_d_id: from_str(row.next().unwrap()).unwrap(),
            o_w_id: from_str(row.next().unwrap()).unwrap(),
            o_c_id: from_str(row.next().unwrap()).unwrap(),
            o_entry_d: from_str(row.next().unwrap()).unwrap(),
            o_carrier_id: from_str(row.next().unwrap()).unwrap(),
            o_ol_cnt: Numeric::from_str(row.next().unwrap(), 2, 0).unwrap(),
            o_all_local: Numeric::from_str(row.next().unwrap(), 1, 0).unwrap(),
        }
    }
}

type OrderTable = Table<Order, (i32, i32, i32)>;

#[deriving(Clone, Show)]
struct Orderline {
    ol_o_id: i32,
    ol_d_id: i32,
    ol_w_id: i32,
    ol_number: i32,
    ol_i_id: i32,
    ol_supply_w_id: i32,
    ol_delivery_d: i32,
    ol_quantity: Numeric, // numeric(2,0)
    ol_amount: Numeric, // numeric(6, 2)
    ol_dist_info: String,
}

impl PrimaryKey<(i32, i32, i32, i32)> for Orderline {
    fn primary_key(&self) -> (i32, i32, i32, i32) {
        (self.ol_w_id, self.ol_d_id, self.ol_o_id, self.ol_number)
    }
}

impl FromRow for Orderline {
    fn from_row(mut row: CharSplits<char>) -> Orderline {
        Orderline {
            ol_o_id: from_str(row.next().unwrap()).unwrap(),
            ol_d_id: from_str(row.next().unwrap()).unwrap(),
            ol_w_id: from_str(row.next().unwrap()).unwrap(),
            ol_number: from_str(row.next().unwrap()).unwrap(),
            ol_i_id: from_str(row.next().unwrap()).unwrap(),
            ol_supply_w_id: from_str(row.next().unwrap()).unwrap(),
            ol_delivery_d: from_str(row.next().unwrap()).unwrap(),
            ol_quantity: Numeric::from_str(row.next().unwrap(), 2, 0).unwrap(),
            ol_amount: Numeric::from_str(row.next().unwrap(), 6, 2).unwrap(),
            ol_dist_info: row.next().unwrap().into_string(),
        }
    }
}

type OrderlineTable = Table<Orderline, (i32, i32, i32, i32)>;

#[deriving(Clone, Show)]
struct Item {
    i_id: i32,
    i_im_id: i32,
    i_name: String,
    i_price: Numeric, // numeric(5,2)
    i_data: String,
}

impl PrimaryKey<i32> for Item {
    fn primary_key(&self) -> i32 {
        self.i_id
    }
}

impl FromRow for Item {
    fn from_row(mut row: CharSplits<char>) -> Item {
        Item {
            i_id: from_str(row.next().unwrap()).unwrap(),
            i_im_id: from_str(row.next().unwrap()).unwrap(),
            i_name: row.next().unwrap().into_string(),
            i_price: Numeric::from_str(row.next().unwrap(), 5, 2).unwrap(),
            i_data: row.next().unwrap().into_string(),
        }
    }
}

type ItemTable = Table<Item, i32>;

#[deriving(Clone, Show)]
struct Stock {
    s_i_id: i32,
    s_w_id: i32,
    s_quantity: Numeric, // numeric(4,0)
    s_dist_01: String,
    s_dist_02: String,
    s_dist_03: String,
    s_dist_04: String,
    s_dist_05: String,
    s_dist_06: String,
    s_dist_07: String,
    s_dist_08: String,
    s_dist_09: String,
    s_dist_10: String,
    s_ytd: Numeric, // numeric(8,0)
    s_order_cnt: Numeric, // numeric(4, 0)
    s_remote_cnt: Numeric, // numeric(4,0)
    s_data: String,
}

impl PrimaryKey<(i32, i32)> for Stock {
    fn primary_key(&self) -> (i32, i32) {
        (self.s_w_id, self.s_i_id)
    }
}

impl FromRow for Stock {
    fn from_row(mut row: CharSplits<char>) -> Stock {
        Stock {
            s_i_id: from_str(row.next().unwrap()).unwrap(),
            s_w_id: from_str(row.next().unwrap()).unwrap(),
            s_quantity: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(),
            s_dist_01: row.next().unwrap().into_string(),
            s_dist_02: row.next().unwrap().into_string(),
            s_dist_03: row.next().unwrap().into_string(),
            s_dist_04: row.next().unwrap().into_string(),
            s_dist_05: row.next().unwrap().into_string(),
            s_dist_06: row.next().unwrap().into_string(),
            s_dist_07: row.next().unwrap().into_string(),
            s_dist_08: row.next().unwrap().into_string(),
            s_dist_09: row.next().unwrap().into_string(),
            s_dist_10: row.next().unwrap().into_string(),
            s_ytd: Numeric::from_str(row.next().unwrap(), 8, 0).unwrap(),
            s_order_cnt: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(),
            s_remote_cnt: Numeric::from_str(row.next().unwrap(), 4, 0).unwrap(),
            s_data: row.next().unwrap().into_string(),
        }
    }
}

type StockTable = Table<Stock, (i32, i32)>;

struct Tables {
    warehouse_table: WarehouseTable,
    district_table: DistrictTable,
    customer_table: CustomerTable,
    neworder_table: NeworderTable,
    order_table: OrderTable,
    orderline_table: OrderlineTable,
    item_table: ItemTable,
    stock_table: StockTable,
}

impl Tables {
    fn new() -> Tables {
        Tables {
            warehouse_table: Table::new(),
            district_table: Table::new(),
            customer_table: Table::new(),
            neworder_table: Table::new(),
            order_table: Table::new(),
            orderline_table: Table::new(),
            item_table: Table::new(),
            stock_table: Table::new(),
        }
    }
}

fn read_table<Data: Clone + FromRow + PrimaryKey<Index>, Index: Eq + Hash>
        (filename: &str, table: &mut Table<Data, Index>) {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
        let row = FromRow::from_row(line.unwrap()[].trim_chars('\n').split('|'));
        table.insert(row);
    }
}

fn read_tables(tables: &mut Tables) {
    read_table::<Warehouse, i32>("../data/tpcc_warehouse.tbl", &mut tables.warehouse_table);
    read_table::<District, (i32, i32)>("../data/tpcc_district.tbl", &mut tables.district_table);
    read_table::<Customer, (i32, i32, i32)>("../data/tpcc_customer.tbl", &mut tables.customer_table);
    read_table::<Neworder, (i32, i32, i32)>("../data/tpcc_neworder.tbl", &mut tables.neworder_table);
    read_table::<Order, (i32, i32, i32)>("../data/tpcc_order.tbl", &mut tables.order_table);
    read_table::<Orderline, (i32, i32, i32, i32)>("../data/tpcc_orderline.tbl", &mut tables.orderline_table);
    read_table::<Item, i32>("../data/tpcc_item.tbl", &mut tables.item_table);
    read_table::<Stock, (i32, i32)>("../data/tpcc_stock.tbl", &mut tables.stock_table);
}

fn main() {
    let time = precise_time_ns();

    let tables: &mut Tables =  &mut Tables::new();
    read_tables(tables);
    println!("Warehouse: {}", tables.warehouse_table.size());
    println!("District: {}", tables.district_table.size());
    println!("Customer: {}", tables.customer_table.size());
    println!("Neworder: {}", tables.neworder_table.size());
    println!("Order: {}", tables.order_table.size());
    println!("Orderline: {}", tables.orderline_table.size());
    println!("Item: {}", tables.item_table.size());
    println!("Stock: {}", tables.stock_table.size());

    println!("insert {}s", ((precise_time_ns() - time) as f64) / 1e9f64);
}
<|endoftext|>


<commit_before>extern crate discord;
extern crate serde_json;

use std::fs::File;
use std::io::Read;
use discord::{Discord, State};
use discord::model::{Event, ChannelId, UserId};

fn main() {
    // Read and set config vars
    let mut file = File::open("config.json").unwrap();
    let mut config = String::new();
    file.read_to_string(&mut config).unwrap();

    let json: serde_json::Value = serde_json::from_str(&config).unwrap();
    let bot_tokens = json.find_path(&["bot-token"]).unwrap();
    let welcome_message = json.find_path(&["welcome-message"]).unwrap();

    info(&format!("[bot-token has been set to {} from config", bot_tokens));
    info(&format!("welcome-message has been set to {} from the config",
                  welcome_message));

    // Login to the API
    let discord = Discord::from_bot_token(bot_tokens.as_string().unwrap()).expect("Login Fail");

    // establish websocket and voice connection
    let (mut connection, ready) = discord.connect().expect("connect failed");
    println!("[Ready] {} is serving {} servers",
             ready.user.username,
             ready.servers.len());
    let mut state = State::new(ready);

    // receive events forever
    loop {
        let event = match connection.recv_event() {
            Ok(event) => event,
            Err(err) => {
                warning(&format!("Receive error: {:?}", err));
                if let discord::Error::WebSocket(..) = err {
                    // Handle the websocket connection being dropped
                    let (new_connection, ready) = discord.connect().expect("connect failed");
                    connection = new_connection;
                    state = State::new(ready);
                    println!("[Ready] Reconnected successfully.");
                }
                if let discord::Error::Closed(..) = err {
                    break;
                }
                continue;
            }
        };
        state.update(&event);

        match event {
            Event::MessageCreate(message) => {
                use std::ascii::AsciiExt;
                // safeguard: stop if the message is from us
                if message.author.id == state.user().id {
                    continue;
                }

                // reply to a command if there was one
                let mut split = message.content.split(" ");
                let first_word = split.next().unwrap_or("");
                let argument = split.next().unwrap_or("");

                if first_word.eq_ignore_ascii_case("!help") {
                    if argument.eq_ignore_ascii_case("dj") {
                        try_twice(&discord,
                                  &message.channel_id,
                                  &format!("``!dj`` Plays YouTube videos in Voice Chat\n``!dj \
                                            stop`` Stops the current playing song.\n``!dj \
                                            quit`` Stops the current playing song, and exits \
                                            the Voice Chat."));
                    } else {
                        try_twice(&discord,
                                  &message.channel_id,
                                  &format!("Here's the help that @{} wanted:\n\n``!dj`` Plays \
                                            YouTube videos in Voice Chat. See ``!help dj`` for \
                                            more info\n\n``!help`` Shows this output.",
                                           message.author.name));
                    }
                } else if first_word.eq_ignore_ascii_case("!dj") {
                    let vchan = state.find_voice_user(message.author.id);
                    if argument.eq_ignore_ascii_case("stop") {
                        vchan.map(|(sid, _)| connection.voice(sid).stop());
                    } else if argument.eq_ignore_ascii_case("quit") {
                        vchan.map(|(sid, _)| connection.drop_voice(sid));
                    } else {
                        let output = if let Some((server_id, channel_id)) = vchan {
                            match discord::voice::open_ytdl_stream(&argument) {
                                Ok(stream) => {
                                    let voice = connection.voice(server_id);
                                    voice.set_deaf(true);
                                    voice.connect(channel_id);
                                    voice.play(stream);
                                    String::new()
                                }
                                Err(error) => format!("Error: {}", error),
                            }
                        } else {
                            "You must be in a voice channel to DJ".to_owned()
                        };
                        if output.len() > 0 {
                            warn(discord.send_message(&message.channel_id, &output, "", false));
                        }
                    }
                } else if first_word.eq_ignore_ascii_case("!quit") {
                    if message.author.id == UserId(5417) {
                        std::process::exit(1);
                    } else {
                        try_twice(&discord,
                                  &message.channel_id,
                                  "Your not authorized to do that");
                        warning("Somebody not authorized tried to kill me.");
                    }
                }
            }
            Event::VoiceStateUpdate(server_id, _) => {
                // If someone moves/hangs up, and we are in a voice channel,
                if let Some(cur_channel) = connection.voice(server_id).current_channel() {
                    // and our current voice channel is empty, disconnect from voice
                    if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
                        if srv.voice_states
                            .iter()
                            .filter(|vs| vs.channel_id == Some(cur_channel))
                            .count() <= 1 {
                            connection.voice(server_id).disconnect();
                        }
                    }
                }
            }
            Event::ServerMemberAdd(server_joined_id, member) => {
                let channel_id = ChannelId(server_joined_id.0);

                for server in state.servers() {
                    if server.id == server_joined_id {
                        try_twice(&discord,
                                  &channel_id,
                                  &format!("Welcome {} to {}! {}",
                                           member.user.name,
                                           server.name,
                                           welcome_message));
                    }
                }
            }
            _ => {} // discard other events
        }
    }
}

fn warn<T, E: ::std::fmt::Debug>(result: Result<T, E>) {
    match result {
        Ok(_) => {}
        Err(err) => println!("[Warning] {:?}", err),
    }
}

fn try_twice(discord: &Discord, channel: &ChannelId, message: &str) {
    let result = discord.send_message(channel, message, "", false);
    match result {
        Ok(_) => {} // nothing to do, it was sent - the `Ok()` contains a `Message` if you want it
        Err(discord::Error::RateLimited(milliseconds)) => {
            let sleep_duration = std::time::Duration::from_millis(milliseconds);

            warning(&format!("We were rate limited for {:?} milliseconds.",
                             sleep_duration));
            std::thread::sleep(sleep_duration);
            try_twice(discord, channel, message);
        }
        _ => {} // discard all other events
    }
}

fn warning(output: &str) {
    println!("[Warning] {}", output);
}
fn info(output: &str) {
    println!("[Info] {}", output);
}
<commit_msg>Output info messages for !quit command.<commit_after>extern crate discord;
extern crate serde_json;

use std::fs::File;
use std::io::Read;
use discord::{Discord, State};
use discord::model::{Event, ChannelId, UserId};

fn main() {
    // Read and set config vars
    let mut file = File::open("config.json").unwrap();
    let mut config = String::new();
    file.read_to_string(&mut config).unwrap();

    let json: serde_json::Value = serde_json::from_str(&config).unwrap();
    let bot_tokens = json.find_path(&["bot-token"]).unwrap();
    let welcome_message = json.find_path(&["welcome-message"]).unwrap();

    info(&format!("[bot-token has been set to {} from config", bot_tokens));
    info(&format!("welcome-message has been set to {} from the config",
                  welcome_message));

    // Login to the API
    let discord = Discord::from_bot_token(bot_tokens.as_string().unwrap()).expect("Login Fail");

    // establish websocket and voice connection
    let (mut connection, ready) = discord.connect().expect("connect failed");
    println!("[Ready] {} is serving {} servers",
             ready.user.username,
             ready.servers.len());
    let mut state = State::new(ready);

    // receive events forever
    loop {
        let event = match connection.recv_event() {
            Ok(event) => event,
            Err(err) => {
                warning(&format!("Receive error: {:?}", err));
                if let discord::Error::WebSocket(..) = err {
                    // Handle the websocket connection being dropped
                    let (new_connection, ready) = discord.connect().expect("connect failed");
                    connection = new_connection;
                    state = State::new(ready);
                    println!("[Ready] Reconnected successfully.");
                }
                if let discord::Error::Closed(..) = err {
                    break;
                }
                continue;
            }
        };
        state.update(&event);

        match event {
            Event::MessageCreate(message) => {
                use std::ascii::AsciiExt;
                // safeguard: stop if the message is from us
                if message.author.id == state.user().id {
                    continue;
                }

                // reply to a command if there was one
                let mut split = message.content.split(" ");
                let first_word = split.next().unwrap_or("");
                let argument = split.next().unwrap_or("");

                if first_word.eq_ignore_ascii_case("!help") {
                    if argument.eq_ignore_ascii_case("dj") {
                        try_twice(&discord,
                                  &message.channel_id,
                                  &format!("``!dj`` Plays YouTube videos in Voice Chat\n``!dj \
                                            stop`` Stops the current playing song.\n``!dj \
                                            quit`` Stops the current playing song, and exits \
                                            the Voice Chat."));
                    } else {
                        try_twice(&discord,
                                  &message.channel_id,
                                  &format!("Here's the help that @{} wanted:\n\n``!dj`` Plays \
                                            YouTube videos in Voice Chat. See ``!help dj`` for \
                                            more info\n\n``!help`` Shows this output.",
                                           message.author.name));
                    }
                } else if first_word.eq_ignore_ascii_case("!dj") {
                    let vchan = state.find_voice_user(message.author.id);
                    if argument.eq_ignore_ascii_case("stop") {
                        vchan.map(|(sid, _)| connection.voice(sid).stop());
                    } else if argument.eq_ignore_ascii_case("quit") {
                        vchan.map(|(sid, _)| connection.drop_voice(sid));
                    } else {
                        let output = if let Some((server_id, channel_id)) = vchan {
                            match discord::voice::open_ytdl_stream(&argument) {
                                Ok(stream) => {
                                    let voice = connection.voice(server_id);
                                    voice.set_deaf(true);
                                    voice.connect(channel_id);
                                    voice.play(stream);
                                    String::new()
                                }
                                Err(error) => format!("Error: {}", error),
                            }
                        } else {
                            "You must be in a voice channel to DJ".to_owned()
                        };
                        if output.len() > 0 {
                            warn(discord.send_message(&message.channel_id, &output, "", false));
                        }
                    }
                } else if first_word.eq_ignore_ascii_case("!quit") {
                    if message.author.id == UserId(77812253511913472) {
                        try_twice(&discord, &message.channel_id, "Shutting Down...");
                        info(&format!("{} has told me to quit.", message.author.name));
                        std::process::exit(1);
                    } else {
                        try_twice(&discord,
                                  &message.channel_id,
                                  "Your not authorized to do that");
                        warning(&format!("{} with the {:?} tried to kill me.",
                                         message.author.name,
                                         message.author.id));
                    }
                }
            }
            Event::VoiceStateUpdate(server_id, _) => {
                // If someone moves/hangs up, and we are in a voice channel,
                if let Some(cur_channel) = connection.voice(server_id).current_channel() {
                    // and our current voice channel is empty, disconnect from voice
                    if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
                        if srv.voice_states
                            .iter()
                            .filter(|vs| vs.channel_id == Some(cur_channel))
                            .count() <= 1 {
                            connection.voice(server_id).disconnect();
                        }
                    }
                }
            }
            Event::ServerMemberAdd(server_joined_id, member) => {
                let channel_id = ChannelId(server_joined_id.0);

                for server in state.servers() {
                    if server.id == server_joined_id {
                        try_twice(&discord,
                                  &channel_id,
                                  &format!("Welcome {} to {}! {}",
                                           member.user.name,
                                           server.name,
                                           welcome_message));
                    }
                }
            }
            _ => {} // discard other events
        }
    }
}

fn warn<T, E: ::std::fmt::Debug>(result: Result<T, E>) {
    match result {
        Ok(_) => {}
        Err(err) => println!("[Warning] {:?}", err),
    }
}

fn try_twice(discord: &Discord, channel: &ChannelId, message: &str) {
    let result = discord.send_message(channel, message, "", false);
    match result {
        Ok(_) => {} // nothing to do, it was sent - the `Ok()` contains a `Message` if you want it
        Err(discord::Error::RateLimited(milliseconds)) => {
            let sleep_duration = std::time::Duration::from_millis(milliseconds);

            warning(&format!("We were rate limited for {:?} milliseconds.",
                             sleep_duration));
            std::thread::sleep(sleep_duration);
            try_twice(discord, channel, message);
        }
        _ => {} // discard all other events
    }
}

fn warning(output: &str) {
    println!("[Warning] {}", output);
}
fn info(output: &str) {
    println!("[Info] {}", output);
}
<|endoftext|>


<commit_before>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

enum ItemType {
   Dir,
   File,
   Other,
}

struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for dir_entry in entries {
         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  println!("f {:?}", dir_entry.file_name());
               }
               else if metadata.is_dir() {
                  println!("d {:?}", dir_entry.file_name());
               }
            }
         }
      }
   }
}
<commit_msg>src/main.rs: create FoundItem structs from found items<commit_after>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

enum ItemType {
   Dir,
   File,
   Other,
}

struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for dir_entry in entries {
         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  println!("f {:?}", dir_entry.file_name());
                  let item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  println!("d {:?}", dir_entry.file_name());
                  let item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
               }
            }
         }
      }
   }
}
<|endoftext|>


<commit_before>#![deny(anonymous_parameters,
        coerce_never,
        const_err,
        dead_code,
        deprecated,
        exceeding_bitshifts,
        illegal_floating_point_literal_pattern,
        improper_ctypes,
        invalid_type_param_default,
        late_bound_lifetime_arguments,
        legacy_constructor_visibility,
        legacy_directory_ownership,
        legacy_imports,
        missing_copy_implementations,
        missing_docs,
        missing_fragment_specifier,
        mutable_transmutes,
        no_mangle_const_items,
        no_mangle_generic_items,
        non_camel_case_types,
        non_shorthand_field_patterns,
        non_snake_case,
        non_upper_case_globals,
        overflowing_literals,
        parenthesized_params_in_types_and_modules,
        path_statements,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        pub_use_of_private_extern_crate,
        renamed_and_removed_lints,
        resolve_trait_on_defaulted_unit,
        safe_extern_statics,
        safe_packed_borrows,
        stable_features,
        trivial_numeric_casts,
        unconditional_recursion,
        unions_with_drop_fields,
        unknown_crate_types,
        unknown_lints,
        unreachable_code,
        unreachable_patterns,
        unreachable_pub,
        unsafe_code,
        unstable_features,
        unused_allocation,
        unused_assignments,
        unused_attributes,
        unused_comparisons,
        unused_doc_comment,
        unused_extern_crates,
        unused_features,
        unused_import_braces,
        unused_imports,
        unused_macros,
        unused_must_use,
        unused_mut,
        unused_parens,
        unused_qualifications,
        unused_unsafe,
        unused_variables,
        while_true)]
#![warn(unknown_lints)]
#![allow(box_pointers,
        missing_debug_implementations,
        trivial_casts,
        unused_results,
        variant_size_differences,
        warnings)]
#![cfg_attr(feature="clippy", feature(plugin))]

//! # cargo-make
//!
//! Rust task runner and build tool.

//! The cargo-make task runner enables to define and configure sets of tasks and run them as a flow.

//! A task is a command or a script to execute.

//! Tasks can have dependencies which are also tasks that will be executed before the task itself.

//! With a simple toml based configuration file, you can define a multi platform build script that can run build, test,
//! documentation generation, bench tests execution, security validations and more by running a single command.
//!
//! ## Installation
//! In order to install, just run the following command
//!
//! ```sh
//! cargo install cargo-make
//! ```
//!
//! This will install cargo-make in your ~/.cargo/bin.

//! Make sure to add ~/.cargo/bin directory to your PATH variable.
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/simple_redis/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/simple_redis/blob/master/LICENSE) open source license.
//!

extern crate ci_info;
extern crate clap;
extern crate fern;
extern crate glob;
#[macro_use]
extern crate log;
extern crate rand;
extern crate run_script;
extern crate rust_info;
extern crate semver;
#[macro_use]
extern crate serde_derive;
extern crate shell2batch;
extern crate toml;

// make types public for docs
pub mod types;

mod logger;
mod descriptor;
mod environment;
mod command;
mod installer;
mod scriptengine;
mod condition;
mod runner;
mod cli;
mod version;

#[cfg(test)]
#[path = "./main_test.rs"]
mod main_test;

#[cfg(test)]
#[path = "./test.rs"]
mod test;

fn main() {
    cli::run_cli();
}
<commit_msg>update lint rules<commit_after>#![deny(anonymous_parameters,
        coerce_never,
        const_err,
        dead_code,
        deprecated,
        exceeding_bitshifts,
        illegal_floating_point_literal_pattern,
        improper_ctypes,
        invalid_type_param_default,
        late_bound_lifetime_arguments,
        legacy_constructor_visibility,
        legacy_directory_ownership,
        legacy_imports,
        missing_copy_implementations,
        missing_docs,
        missing_fragment_specifier,
        mutable_transmutes,
        no_mangle_const_items,
        no_mangle_generic_items,
        non_camel_case_types,
        non_shorthand_field_patterns,
        non_snake_case,
        non_upper_case_globals,
        overflowing_literals,
        parenthesized_params_in_types_and_modules,
        path_statements,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        pub_use_of_private_extern_crate,
        renamed_and_removed_lints,
        resolve_trait_on_defaulted_unit,
        safe_extern_statics,
        safe_packed_borrows,
        stable_features,
        trivial_numeric_casts,
        unconditional_recursion,
        unions_with_drop_fields,
        unknown_crate_types,
        unreachable_code,
        unreachable_patterns,
        unreachable_pub,
        unsafe_code,
        unstable_features,
        unused_allocation,
        unused_assignments,
        unused_attributes,
        unused_comparisons,
        unused_doc_comment,
        unused_extern_crates,
        unused_features,
        unused_import_braces,
        unused_imports,
        unused_macros,
        unused_must_use,
        unused_mut,
        unused_parens,
        unused_qualifications,
        unused_unsafe,
        unused_variables,
        while_true)]
#![warn(unknown_lints)]
#![allow(box_pointers,
        missing_debug_implementations,
        trivial_casts,
        unused_results,
        variant_size_differences,
        warnings)]
#![cfg_attr(feature="clippy", feature(plugin))]

//! # cargo-make
//!
//! Rust task runner and build tool.

//! The cargo-make task runner enables to define and configure sets of tasks and run them as a flow.

//! A task is a command or a script to execute.

//! Tasks can have dependencies which are also tasks that will be executed before the task itself.

//! With a simple toml based configuration file, you can define a multi platform build script that can run build, test,
//! documentation generation, bench tests execution, security validations and more by running a single command.
//!
//! ## Installation
//! In order to install, just run the following command
//!
//! ```sh
//! cargo install cargo-make
//! ```
//!
//! This will install cargo-make in your ~/.cargo/bin.

//! Make sure to add ~/.cargo/bin directory to your PATH variable.
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/simple_redis/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/simple_redis/blob/master/LICENSE) open source license.
//!

extern crate ci_info;
extern crate clap;
extern crate fern;
extern crate glob;
#[macro_use]
extern crate log;
extern crate rand;
extern crate run_script;
extern crate rust_info;
extern crate semver;
#[macro_use]
extern crate serde_derive;
extern crate shell2batch;
extern crate toml;

// make types public for docs
pub mod types;

mod logger;
mod descriptor;
mod environment;
mod command;
mod installer;
mod scriptengine;
mod condition;
mod runner;
mod cli;
mod version;

#[cfg(test)]
#[path = "./main_test.rs"]
mod main_test;

#[cfg(test)]
#[path = "./test.rs"]
mod test;

fn main() {
    cli::run_cli();
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::{self, BufReader, Cursor};
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;

use rand::Rng;
use rand::os::OsRng;

use crypto::ed25519;
use crypto::digest::Digest;
use crypto::sha2::Sha512;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use docopt::Docopt;

const KEYNUMLEN : usize = 8;
const PUBLICBYTES : usize = 32;
const SECRETBYTES : usize = 64;
const SIGBYTES : usize = 64;

const PKGALG : [u8; 2] = *b"Ed";
const KDFALG : [u8; 2] = *b"BK";

const COMMENTHDR : &'static str = "untrusted comment: ";
const COMMENTHDRLEN : usize = 19;
const COMMENTMAXLEN : usize = 1024;

const USAGE: &'static str = "
signify-rs

Usage:
  signify -h
  signify -G [-c <comment>] -p <pubkey> -s <seckey>
  signify -V [-x <sigfile>] -p <pubkey> -m <message>

Options:
  -h --help              Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -m <message>  When signing, the file containing the message to sign.  When verifying, the file containing the
                message to verify.  When verifying with -e, the file to create.
  -p <pubkey>   Public key produced by -G, and used by -V to check a signature.
  -s <seckey>   Secret (private) key produced by -G, and used by -S to sign a message.
  -x <sigfile>  The signature file to create or verify.  The default is <message>.sig.
";

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_V: bool,
    flag_G: bool,

    flag_x: Option<String>,
    flag_c: Option<String>,

    flag_p: String,
    flag_s: String,
    flag_m: String,
}

enum FileContent {
    PublicKey(PublicKey),
    PrivateKey(PrivateKey),
    Signature(Signature),
}

struct PublicKey {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

struct PrivateKey {
   pkgalg: [u8; 2],
   kdfalg: [u8; 2],
   kdfrounds: u32,
   salt: [u8; 16],
   checksum: [u8; 8],
   keynum: [u8; KEYNUMLEN],
   seckey: [u8; SECRETBYTES],
}

struct Signature {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.publkey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PublicKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut publkey));

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }

    fn verify(&self, msg: &[u8], signature: &Signature) -> bool {
        ed25519::verify(msg, &self.publkey, &signature.sig)
    }
}

impl PrivateKey {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.kdfalg));
        try!(w.write_u32::<BigEndian>(self.kdfrounds));
        try!(w.write(&self.salt));
        try!(w.write(&self.checksum));
        try!(w.write(&self.keynum));
        try!(w.write(&self.seckey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PrivateKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut kdfalg));
        kdfrounds = try!(buf.read_u32::<BigEndian>());
        try!(buf.read(&mut salt));
        try!(buf.read(&mut checksum));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut seckey));

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    fn sign(&self, msg: &[u8]) -> Signature {
        let signature = ed25519::signature(msg, &self.seckey);
        Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: signature
        }
    }
}

impl Signature {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.sig));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<Signature, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut sig));

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        ed25519::verify(msg, &pkey.publkey, &self.sig)
    }
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<(), io::Error> {
    let mut f = File::create(file).unwrap();

    try!(write!(f, "{}", COMMENTHDR));
    try!(write!(f, "{}\n", comment));
    let out = base64::encode(buf);
    try!(write!(f, "{}\n", out));

    Ok(())
}

fn read_base64_file<P: AsRef<Path>>(file: P) -> Result<FileContent, io::Error> {
    let file_display = format!("{}", file.as_ref().display());
    let f = try!(File::open(file));
    let mut reader = BufReader::new(f);

    let mut comment_line = String::new();
    let len = try!(reader.read_line(&mut comment_line));

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        println!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR);
        process::exit(1);
    }

    if &comment_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        println!("comment too long");
        process::exit(1);
    }

    let mut base64_line = String::new();
    let len = try!(reader.read_line(&mut base64_line));

    if len == 0 {
        println!("missing line in {}", file_display);
        process::exit(1);
    }

    if &base64_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    let base64_line = &base64_line[0..len-1];

    let data = match base64::decode(&base64_line) {
        Ok(data) => data,
        Err(e) => {
            println!("invalid base64 encoding in {}: {:?}", file_display, e);
            process::exit(1);
        }
    };

    if &data[0..2] != PKGALG {
        println!("unsupported file {}", file_display);
        process::exit(1);
    }

    match data.len() {
        x if x == mem::size_of::<PublicKey>() => {
            return PublicKey::from_buf(&data)
                .map(FileContent::PublicKey);
        },
        x if x == mem::size_of::<PrivateKey>() => {
            return PrivateKey::from_buf(&data)
                .map(FileContent::PrivateKey);
        },
        x if x == mem::size_of::<Signature>() => {
            return Signature::from_buf(&data)
                .map(FileContent::Signature);
        },
        _ => {
            println!("unsupported file {}", file_display);
            process::exit(1);
        },
    };
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => {
            println!("Can't read signature from '{}'", signature_path);
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
    } else {
        println!("signature verification failed");
        process::exit(1);
    }
}

fn generate(pubkey_path: String, privkey_path: String, comment: Option<String>) {
    let comment = match comment {
        Some(s) => s,
        None    => "signify".into()
    };

    let mut keynum = [0; KEYNUMLEN];

    let mut rng = OsRng::new().expect("Can't create random number generator");
    rng.fill_bytes(&mut keynum);

    let mut seed = [0; 32];
    rng.fill_bytes(&mut seed);
    let (skey, pkey) = ed25519::keypair(&seed);

    // Store private key
    let mut ctx = Sha512::new();
    ctx.input(&skey);
    let mut digest = [0; 64];
    ctx.result(&mut digest);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest[0..8]);

    let mut salt = [0; 16];
    rng.fill_bytes(&mut salt);

    let private_key = PrivateKey {
        pkgalg: PKGALG,
        kdfalg: KDFALG,
        kdfrounds: 0,
        salt: salt,
        checksum: checksum,
        keynum: keynum,
        seckey: skey,
    };

    let mut out = vec![];
    private_key.write(&mut out).expect("Can't write to internal buffer");

    let priv_comment = format!("{} secret key", comment);
    write_base64_file(&privkey_path, &priv_comment, &out).unwrap();

    // Store public key
    let public_key = PublicKey::with_key_and_keynum(pkey, keynum);

    let mut out = vec![];
    public_key.write(&mut out).expect("Can't write to internal buffer");

    let pub_comment = format!("{} public key", comment);
    write_base64_file(&pubkey_path, &pub_comment, &out).unwrap();
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_V {
        verify(args.flag_p, args.flag_m, args.flag_x);
    } else if args.flag_G {
        generate(args.flag_p, args.flag_s, args.flag_c);
    }
}
<commit_msg>feat: Sign data<commit_after>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::{self, BufReader, Cursor};
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;

use rand::Rng;
use rand::os::OsRng;

use crypto::ed25519;
use crypto::digest::Digest;
use crypto::sha2::Sha512;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use docopt::Docopt;

const KEYNUMLEN : usize = 8;
const PUBLICBYTES : usize = 32;
const SECRETBYTES : usize = 64;
const SIGBYTES : usize = 64;

const PKGALG : [u8; 2] = *b"Ed";
const KDFALG : [u8; 2] = *b"BK";

const COMMENTHDR : &'static str = "untrusted comment: ";
const COMMENTHDRLEN : usize = 19;
const COMMENTMAXLEN : usize = 1024;

const USAGE: &'static str = "
signify-rs

Usage:
  signify -h
  signify -G [-c <comment>] -p <pubkey> -s <seckey>
  signify -S [-x <sigfile>] -s <seckey> -m <message>
  signify -V [-x <sigfile>] -p <pubkey> -m <message>

Options:
  -h --help              Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -m <message>  When signing, the file containing the message to sign.  When verifying, the file containing the
                message to verify.  When verifying with -e, the file to create.
  -p <pubkey>   Public key produced by -G, and used by -V to check a signature.
  -s <seckey>   Secret (private) key produced by -G, and used by -S to sign a message.
  -x <sigfile>  The signature file to create or verify.  The default is <message>.sig.
";

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_G: bool,
    flag_S: bool,
    flag_V: bool,

    flag_x: Option<String>,
    flag_c: Option<String>,

    flag_p: String,
    flag_s: String,
    flag_m: String,
}

enum FileContent {
    PublicKey(PublicKey),
    PrivateKey(PrivateKey),
    Signature(Signature),
}

struct PublicKey {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

struct PrivateKey {
   pkgalg: [u8; 2],
   kdfalg: [u8; 2],
   kdfrounds: u32,
   salt: [u8; 16],
   checksum: [u8; 8],
   keynum: [u8; KEYNUMLEN],
   seckey: [u8; SECRETBYTES],
}

struct Signature {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.publkey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PublicKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut publkey));

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }

    fn verify(&self, msg: &[u8], signature: &Signature) -> bool {
        ed25519::verify(msg, &self.publkey, &signature.sig)
    }
}

impl PrivateKey {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.kdfalg));
        try!(w.write_u32::<BigEndian>(self.kdfrounds));
        try!(w.write(&self.salt));
        try!(w.write(&self.checksum));
        try!(w.write(&self.keynum));
        try!(w.write(&self.seckey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PrivateKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut kdfalg));
        kdfrounds = try!(buf.read_u32::<BigEndian>());
        try!(buf.read(&mut salt));
        try!(buf.read(&mut checksum));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut seckey));

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    fn sign(&self, msg: &[u8]) -> Signature {
        let signature = ed25519::signature(msg, &self.seckey);
        Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: signature
        }
    }
}

impl Signature {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.sig));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<Signature, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut sig));

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        ed25519::verify(msg, &pkey.publkey, &self.sig)
    }
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<(), io::Error> {
    let mut f = File::create(file).unwrap();

    try!(write!(f, "{}", COMMENTHDR));
    try!(write!(f, "{}\n", comment));
    let out = base64::encode(buf);
    try!(write!(f, "{}\n", out));

    Ok(())
}

fn read_base64_file<P: AsRef<Path>>(file: P) -> Result<FileContent, io::Error> {
    let file_display = format!("{}", file.as_ref().display());
    let f = try!(File::open(file));
    let mut reader = BufReader::new(f);

    let mut comment_line = String::new();
    let len = try!(reader.read_line(&mut comment_line));

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        println!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR);
        process::exit(1);
    }

    if &comment_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        println!("comment too long");
        process::exit(1);
    }

    let mut base64_line = String::new();
    let len = try!(reader.read_line(&mut base64_line));

    if len == 0 {
        println!("missing line in {}", file_display);
        process::exit(1);
    }

    if &base64_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    let base64_line = &base64_line[0..len-1];

    let data = match base64::decode(&base64_line) {
        Ok(data) => data,
        Err(e) => {
            println!("invalid base64 encoding in {}: {:?}", file_display, e);
            process::exit(1);
        }
    };

    if &data[0..2] != PKGALG {
        println!("unsupported file {}", file_display);
        process::exit(1);
    }

    match data.len() {
        x if x == mem::size_of::<PublicKey>() => {
            return PublicKey::from_buf(&data)
                .map(FileContent::PublicKey);
        },
        x if x == mem::size_of::<PrivateKey>() => {
            return PrivateKey::from_buf(&data)
                .map(FileContent::PrivateKey);
        },
        x if x == mem::size_of::<Signature>() => {
            return Signature::from_buf(&data)
                .map(FileContent::Signature);
        },
        _ => {
            println!("unsupported file {}", file_display);
            process::exit(1);
        },
    };
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => {
            println!("Can't read signature from '{}'", signature_path);
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
    } else {
        println!("signature verification failed");
        process::exit(1);
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) {
    let skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let sig = skey.sign(&msg);

    let mut out = vec![];
    sig.write(&mut out).expect("Can't write to internal buffer");

    let sig_comment = "signature from signify secret key";
    write_base64_file(&signature_path, sig_comment, &out).unwrap();
}

fn generate(pubkey_path: String, privkey_path: String, comment: Option<String>) {
    let comment = match comment {
        Some(s) => s,
        None    => "signify".into()
    };

    let mut keynum = [0; KEYNUMLEN];

    let mut rng = OsRng::new().expect("Can't create random number generator");
    rng.fill_bytes(&mut keynum);

    let mut seed = [0; 32];
    rng.fill_bytes(&mut seed);
    let (skey, pkey) = ed25519::keypair(&seed);

    // Store private key
    let mut ctx = Sha512::new();
    ctx.input(&skey);
    let mut digest = [0; 64];
    ctx.result(&mut digest);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest[0..8]);

    let mut salt = [0; 16];
    rng.fill_bytes(&mut salt);

    let private_key = PrivateKey {
        pkgalg: PKGALG,
        kdfalg: KDFALG,
        kdfrounds: 0,
        salt: salt,
        checksum: checksum,
        keynum: keynum,
        seckey: skey,
    };

    let mut out = vec![];
    private_key.write(&mut out).expect("Can't write to internal buffer");

    let priv_comment = format!("{} secret key", comment);
    write_base64_file(&privkey_path, &priv_comment, &out).unwrap();

    // Store public key
    let public_key = PublicKey::with_key_and_keynum(pkey, keynum);

    let mut out = vec![];
    public_key.write(&mut out).expect("Can't write to internal buffer");

    let pub_comment = format!("{} public key", comment);
    write_base64_file(&pubkey_path, &pub_comment, &out).unwrap();
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_V {
        verify(args.flag_p, args.flag_m, args.flag_x);
    } else if args.flag_G {
        generate(args.flag_p, args.flag_s, args.flag_c);
    } else if args.flag_S {
        sign(args.flag_s, args.flag_m, args.flag_x);
    }
}
<|endoftext|>