<commit_before>#[macro_use]
extern crate clap;
extern crate sputnikvm;
extern crate serde_json;
extern crate gethrpc;
extern crate block;
extern crate bigint;
extern crate hexutil;

use serde_json::{Value};
use std::process;
use std::fs::File;
use std::path::Path;
use std::io::{BufReader};
use std::str::FromStr;
use std::collections::{HashMap, HashSet};

use block::TransactionAction;
use bigint::{Gas, Address, U256, M256, H256};
use hexutil::*;
use sputnikvm::{HeaderParams, Context, SeqTransactionVM, ValidTransaction, VM, Log, Patch,
                AccountCommitment, AccountChange, FRONTIER_PATCH, HOMESTEAD_PATCH,
                EIP150_PATCH, EIP160_PATCH};
use sputnikvm::errors::RequireError;
use gethrpc::{GethRPCClient, NormalGethRPCClient, RecordGethRPCClient, CachedGethRPCClient, RPCCall, RPCBlock, RPCTransaction, RPCLog};

fn from_rpc_block(block: &RPCBlock) -> HeaderParams {
    HeaderParams {
        beneficiary: Address::from_str(&block.miner).unwrap(),
        timestamp: U256::from_str(&block.timestamp).unwrap().into(),
        number: U256::from_str(&block.number).unwrap(),
        difficulty: U256::from_str(&block.difficulty).unwrap(),
        gas_limit: Gas::from_str(&block.gasLimit).unwrap(),
    }
}

fn from_rpc_transaction(transaction: &RPCTransaction) -> ValidTransaction {
    ValidTransaction {
        caller: Some(Address::from_str(&transaction.from).unwrap()),
        action: if transaction.to.is_empty() {
            TransactionAction::Create
        } else {
            TransactionAction::Call(Address::from_str(&transaction.to).unwrap())
        },
        value: U256::from_str(&transaction.value).unwrap(),
        gas_limit: Gas::from_str(&transaction.gas).unwrap(),
        gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
        input: read_hex(&transaction.input).unwrap(),
        nonce: U256::from_str(&transaction.nonce).unwrap(),
    }
}

fn from_rpc_log(log: &RPCLog) -> Log {
    let mut topics: Vec<H256> = Vec::new();
    for topic in &log.topics {
        topics.push(H256::from_str(&topic).unwrap());
    }
    Log {
        address: Address::from_str(&log.address).unwrap(),
        data: read_hex(&log.data).unwrap(),
        topics: topics,
    }
}

fn handle_fire<T: GethRPCClient>(client: &mut T, vm: &mut SeqTransactionVM, last_block_id: usize) {
    let last_block_number = format!("0x{:x}", last_block_id);
    loop {
        match vm.fire() {
            Ok(()) => {
                println!("VM exited with {:?}.", vm.status());
                break;
            },
            Err(RequireError::Account(address)) => {
                println!("Feeding VM account at 0x{:x} ...", address);
                let nonce = U256::from_str(&client.get_transaction_count(&format!("0x{:x}", address),
                                                                         &last_block_number)).unwrap();
                let balance = U256::from_str(&client.get_balance(&format!("0x{:x}", address),
                                                                 &last_block_number)).unwrap();
                let code = read_hex(&client.get_code(&format!("0x{:x}", address),
                                                     &last_block_number)).unwrap();
                if !client.account_exist(&format!("0x{:x}", address), last_block_id) {
                    vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                } else {
                    vm.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        code: code,
                    }).unwrap();
                }
            },
            Err(RequireError::AccountStorage(address, index)) => {
                println!("Feeding VM account storage at 0x{:x} with index 0x{:x} ...", address, index);
                let value = M256::from_str(&client.get_storage_at(&format!("0x{:x}", address),
                                                                  &format!("0x{:x}", index),
                                                                  &last_block_number)).unwrap();
                vm.commit_account(AccountCommitment::Storage {
                    address: address,
                    index: index,
                    value: value,
                }).unwrap();
            },
            Err(RequireError::AccountCode(address)) => {
                println!("Feeding VM account code at 0x{:x} ...", address);
                let code = read_hex(&client.get_code(&format!("0x{:x}", address),
                                                     &last_block_number)).unwrap();
                vm.commit_account(AccountCommitment::Code {
                    address: address,
                    code: code,
                }).unwrap();
            },
            Err(RequireError::Blockhash(number)) => {
                println!("Feeding blockhash with number 0x{:x} ...", number);
                let hash = H256::from_str(&client.get_block_by_number(&format!("0x{:x}", number))
                                          .hash).unwrap();
                vm.commit_blockhash(number, hash);
            },
        }
    }
}

fn is_miner_or_uncle<T: GethRPCClient>(client: &mut T, address: Address, block: &RPCBlock) -> bool {
    // Give up balance testing if the address is a miner or an uncle.

    let miner = Address::from_str(&block.miner).unwrap();
    if miner == address {
        return true;
    }
    if block.uncles.len() > 0 {
        for i in 0..block.uncles.len() {
            let uncle = client.get_uncle_by_block_number_and_index(&block.number,
                                                                   &format!("0x{:x}", i));
            let uncle_miner = Address::from_str(&uncle.miner).unwrap();
            if uncle_miner == address {
                return true;
            }
        }
    }

    return false;
}

fn test_block<T: GethRPCClient>(client: &mut T, number: usize, patch: &'static Patch) {
    let block = client.get_block_by_number(format!("0x{:x}", number).as_str());
    println!("block {} ({}), transaction count: {}", number, block.number, block.transactions.len());
    let last_id = number - 1;
    let last_number = format!("0x{:x}", last_id);
    let cur_number = block.number.to_string();
    let block_header = from_rpc_block(&block);

    let mut last_vm: Option<SeqTransactionVM> = None;
    for transaction_hash in &block.transactions {
        println!("\nworking on transaction {}", transaction_hash);
        let transaction = from_rpc_transaction(&client.get_transaction_by_hash(&transaction_hash));
        let receipt = client.get_transaction_receipt(&transaction_hash);

        let mut vm = if last_vm.is_none() {
            SeqTransactionVM::new(transaction, block_header.clone(), patch)
        } else {
            SeqTransactionVM::with_previous(transaction, block_header.clone(), patch, last_vm.as_ref().unwrap())
        };

        handle_fire(client, &mut vm, last_id);

        assert!(Gas::from_str(&receipt.gasUsed).unwrap() == vm.real_used_gas());
        assert!(receipt.logs.len() == vm.logs().len());
        for i in 0..receipt.logs.len() {
            assert!(from_rpc_log(&receipt.logs[i]) == vm.logs()[i]);
        }

        last_vm = Some(vm);
    }

    if last_vm.is_some() {
        for account in last_vm.as_ref().unwrap().accounts() {
            match account {
                &AccountChange::Full {
                    address,
                    balance,
                    ref changing_storage,
                    ..
                } => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == balance);
                    }
                    let changing_storage: HashMap<U256, M256> = changing_storage.clone().into();
                    for (key, value) in changing_storage {
                        let expected_value = client.get_storage_at(&format!("0x{:x}", address),
                                                                   &format!("0x{:x}", key),
                                                                   &cur_number);
                        assert!(M256::from_str(&expected_value).unwrap() == value);
                    }
                },
                &AccountChange::Create {
                    address,
                    balance,
                    ref storage,
                    ..
                } => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == balance);
                    }
                    let storage: HashMap<U256, M256> = storage.clone().into();
                    for (key, value) in storage {
                        let expected_value = client.get_storage_at(&format!("0x{:x}", address),
                                                                   &format!("0x{:x}", key),
                                                                   &cur_number);
                        assert!(M256::from_str(&expected_value).unwrap() == value);
                    }
                },
                &AccountChange::IncreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let last_balance = client.get_balance(&format!("0x{:x}", address),
                                                              &last_number);
                        let cur_balance = client.get_balance(&format!("0x{:x}", address),
                                                             &cur_number);

                        assert!(U256::from_str(&last_balance).unwrap() + balance ==
                                U256::from_str(&cur_balance).unwrap());
                    }
                },
                &AccountChange::DecreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let last_balance = client.get_balance(&format!("0x{:x}", address),
                                                              &last_number);
                        let cur_balance = client.get_balance(&format!("0x{:x}", address),
                                                             &cur_number);

                        assert!(U256::from_str(&last_balance).unwrap() - balance ==
                                U256::from_str(&cur_balance).unwrap());
                    }
                },
            }
        }
    }
}

fn test_blocks<T: GethRPCClient>(client: &mut T, number: &str, patch: &'static Patch) {
    if number.contains(".json") {
        let file = File::open(number).unwrap();
        let numbers: Vec<usize> = serde_json::from_reader(file).unwrap();
        for n in numbers {
            test_block(client, n, patch);
        }
    } else if number.contains("..") {
        let number: Vec<&str> = number.split("..").collect();
        let from = usize::from_str_radix(&number[0], 10).unwrap();
        let to = usize::from_str_radix(&number[1], 10).unwrap();
        for n in from..to {
            test_block(client, n, patch);
        }
    } else if number.contains(",") {
        let numbers: Vec<&str> = number.split("..").collect();
        for number in numbers {
            let n = usize::from_str_radix(number, 10).unwrap();
            test_block(client, n, patch);
        }
    } else {
        let number = usize::from_str_radix(&number, 10).unwrap();
        test_block(client, number, patch);
    }
}

fn main() {
    let matches = clap_app!(regtests =>
        (version: "0.1")
        (author: "Ethereum Classic Contributors")
        (about: "Performs an regression test on the entire Ethereum Classic blockchain.\n\nSteps to reproduce:\n* Install Ethereum Classic Geth: `$ go install github.com/ethereumproject/go-ethereum/cmd/geth`.\n* Run Geth with this command: `$ ~/go/bin/geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545`.\n* Wait for the chain to sync.\n* Change directory into the `regtests` directory `$ cd regtests`\n* Run this command: `$ RUST_BACKTRACE=1 cargo run --bin regtests -- -r http://127.0.0.1:8545")
        (@arg RPC: -r --rpc +takes_value +required "Domain of Ethereum Classic Geth's RPC endpoint. e.g. `-r http://127.0.0.1:8545`.")
        (@arg NUMBER: -n --number +takes_value +required "Block number to run this test. Radix is 10. e.g. `-n 49439`.")
        (@arg RECORD: --record +takes_value "Record to file path.")
        (@arg PATCH: -p --patch +takes_value +required "Patch to be used, homestead or frontier.")
    ).get_matches();

    let address = matches.value_of("RPC").unwrap();
    let number = matches.value_of("NUMBER").unwrap();
    let record = matches.value_of("RECORD");
    let patch = match matches.value_of("PATCH") {
        Some("frontier") => &FRONTIER_PATCH,
        Some("homestead") => &HOMESTEAD_PATCH,
        Some("eip150") => &EIP150_PATCH,
        Some("eip160") => &EIP160_PATCH,
        _ => panic!("Unknown patch."),
    };

    if address.contains(".json") {
        let file = File::open(address).unwrap();
        let cached: serde_json::Value = serde_json::from_reader(file).unwrap();
        let mut client = CachedGethRPCClient::from_value(cached);
        test_blocks(&mut client, number, patch);
    } else {
        match record {
            Some(val) => {
                let mut file = File::create(val).unwrap();
                let mut client = RecordGethRPCClient::new(address);
                test_blocks(&mut client, number, patch);
                serde_json::to_writer(&mut file, &client.to_value());
            },
            None => {
                let mut client = NormalGethRPCClient::new(address);
                test_blocks(&mut client, number, patch);
            }
        }
    }
}

#[cfg(test)]
#[test]
fn test_all_previously_failed_frontier_blocks() {
    let cached: serde_json::Value = serde_json::from_str(include_str!("../../res/frontier_records.json")).unwrap();
    let numbers: Vec<usize> = serde_json::from_str(include_str!("../../res/frontier_numbers.json")).unwrap();
    let mut client = CachedGethRPCClient::from_value(cached);
    for n in numbers {
        test_block(&mut client, n, &FRONTIER_PATCH);
    }
}

#[cfg(test)]
#[test]
fn test_all_previously_failed_homestead_blocks() {
    let cached: serde_json::Value = serde_json::from_str(include_str!("../../res/homestead_records.json")).unwrap();
    let numbers: Vec<usize> = serde_json::from_str(include_str!("../../res/homestead_numbers.json")).unwrap();
    let mut client = CachedGethRPCClient::from_value(cached);
    for n in numbers {
        test_block(&mut client, n, &HOMESTEAD_PATCH);
    }
}

#[cfg(test)]
#[test]
fn test_all_previously_failed_eip150_blocks() {
    let cached: serde_json::Value = serde_json::from_str(include_str!("../../res/eip150_records.json")).unwrap();
    let numbers: Vec<usize> = serde_json::from_str(include_str!("../../res/eip150_numbers.json")).unwrap();
    let mut client = CachedGethRPCClient::from_value(cached);
    for n in numbers {
        test_block(&mut client, n, &EIP150_PATCH);
    }
}
<commit_msg>Fix Patch interface in regtests crate<commit_after>#[macro_use]
extern crate clap;
extern crate sputnikvm;
extern crate serde_json;
extern crate gethrpc;
extern crate block;
extern crate bigint;
extern crate hexutil;

use serde_json::{Value};
use std::process;
use std::fs::File;
use std::path::Path;
use std::io::{BufReader};
use std::str::FromStr;
use std::collections::{HashMap, HashSet};

use block::TransactionAction;
use bigint::{Gas, Address, U256, M256, H256};
use hexutil::*;
use sputnikvm::{HeaderParams, Context, SeqTransactionVM, ValidTransaction, VM, Log, Patch,
                AccountCommitment, AccountChange, FrontierPatch, HomesteadPatch,
                EIP150Patch, EIP160Patch};
use sputnikvm::errors::RequireError;
use gethrpc::{GethRPCClient, NormalGethRPCClient, RecordGethRPCClient, CachedGethRPCClient, RPCCall, RPCBlock, RPCTransaction, RPCLog};

fn from_rpc_block(block: &RPCBlock) -> HeaderParams {
    HeaderParams {
        beneficiary: Address::from_str(&block.miner).unwrap(),
        timestamp: U256::from_str(&block.timestamp).unwrap().into(),
        number: U256::from_str(&block.number).unwrap(),
        difficulty: U256::from_str(&block.difficulty).unwrap(),
        gas_limit: Gas::from_str(&block.gasLimit).unwrap(),
    }
}

fn from_rpc_transaction(transaction: &RPCTransaction) -> ValidTransaction {
    ValidTransaction {
        caller: Some(Address::from_str(&transaction.from).unwrap()),
        action: if transaction.to.is_empty() {
            TransactionAction::Create
        } else {
            TransactionAction::Call(Address::from_str(&transaction.to).unwrap())
        },
        value: U256::from_str(&transaction.value).unwrap(),
        gas_limit: Gas::from_str(&transaction.gas).unwrap(),
        gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
        input: read_hex(&transaction.input).unwrap(),
        nonce: U256::from_str(&transaction.nonce).unwrap(),
    }
}

fn from_rpc_log(log: &RPCLog) -> Log {
    let mut topics: Vec<H256> = Vec::new();
    for topic in &log.topics {
        topics.push(H256::from_str(&topic).unwrap());
    }
    Log {
        address: Address::from_str(&log.address).unwrap(),
        data: read_hex(&log.data).unwrap(),
        topics: topics,
    }
}

fn handle_fire<T: GethRPCClient, P: Patch>(client: &mut T, vm: &mut SeqTransactionVM<P>, last_block_id: usize) {
    let last_block_number = format!("0x{:x}", last_block_id);
    loop {
        match vm.fire() {
            Ok(()) => {
                println!("VM exited with {:?}.", vm.status());
                break;
            },
            Err(RequireError::Account(address)) => {
                println!("Feeding VM account at 0x{:x} ...", address);
                let nonce = U256::from_str(&client.get_transaction_count(&format!("0x{:x}", address),
                                                                         &last_block_number)).unwrap();
                let balance = U256::from_str(&client.get_balance(&format!("0x{:x}", address),
                                                                 &last_block_number)).unwrap();
                let code = read_hex(&client.get_code(&format!("0x{:x}", address),
                                                     &last_block_number)).unwrap();
                if !client.account_exist(&format!("0x{:x}", address), last_block_id) {
                    vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                } else {
                    vm.commit_account(AccountCommitment::Full {
                        nonce: nonce,
                        address: address,
                        balance: balance,
                        code: code,
                    }).unwrap();
                }
            },
            Err(RequireError::AccountStorage(address, index)) => {
                println!("Feeding VM account storage at 0x{:x} with index 0x{:x} ...", address, index);
                let value = M256::from_str(&client.get_storage_at(&format!("0x{:x}", address),
                                                                  &format!("0x{:x}", index),
                                                                  &last_block_number)).unwrap();
                vm.commit_account(AccountCommitment::Storage {
                    address: address,
                    index: index,
                    value: value,
                }).unwrap();
            },
            Err(RequireError::AccountCode(address)) => {
                println!("Feeding VM account code at 0x{:x} ...", address);
                let code = read_hex(&client.get_code(&format!("0x{:x}", address),
                                                     &last_block_number)).unwrap();
                vm.commit_account(AccountCommitment::Code {
                    address: address,
                    code: code,
                }).unwrap();
            },
            Err(RequireError::Blockhash(number)) => {
                println!("Feeding blockhash with number 0x{:x} ...", number);
                let hash = H256::from_str(&client.get_block_by_number(&format!("0x{:x}", number))
                                          .hash).unwrap();
                vm.commit_blockhash(number, hash);
            },
        }
    }
}

fn is_miner_or_uncle<T: GethRPCClient>(client: &mut T, address: Address, block: &RPCBlock) -> bool {
    // Give up balance testing if the address is a miner or an uncle.

    let miner = Address::from_str(&block.miner).unwrap();
    if miner == address {
        return true;
    }
    if block.uncles.len() > 0 {
        for i in 0..block.uncles.len() {
            let uncle = client.get_uncle_by_block_number_and_index(&block.number,
                                                                   &format!("0x{:x}", i));
            let uncle_miner = Address::from_str(&uncle.miner).unwrap();
            if uncle_miner == address {
                return true;
            }
        }
    }

    return false;
}

fn test_block<T: GethRPCClient, P: Patch>(client: &mut T, number: usize) {
    let block = client.get_block_by_number(format!("0x{:x}", number).as_str());
    println!("block {} ({}), transaction count: {}", number, block.number, block.transactions.len());
    let last_id = number - 1;
    let last_number = format!("0x{:x}", last_id);
    let cur_number = block.number.to_string();
    let block_header = from_rpc_block(&block);

    let mut last_vm: Option<SeqTransactionVM<P>> = None;
    for transaction_hash in &block.transactions {
        println!("\nworking on transaction {}", transaction_hash);
        let transaction = from_rpc_transaction(&client.get_transaction_by_hash(&transaction_hash));
        let receipt = client.get_transaction_receipt(&transaction_hash);

        let mut vm = if last_vm.is_none() {
            SeqTransactionVM::new(transaction, block_header.clone())
        } else {
            SeqTransactionVM::with_previous(transaction, block_header.clone(), last_vm.as_ref().unwrap())
        };

        handle_fire(client, &mut vm, last_id);

        assert!(Gas::from_str(&receipt.gasUsed).unwrap() == vm.real_used_gas());
        assert!(receipt.logs.len() == vm.logs().len());
        for i in 0..receipt.logs.len() {
            assert!(from_rpc_log(&receipt.logs[i]) == vm.logs()[i]);
        }

        last_vm = Some(vm);
    }

    if last_vm.is_some() {
        for account in last_vm.as_ref().unwrap().accounts() {
            match account {
                &AccountChange::Full {
                    address,
                    balance,
                    ref changing_storage,
                    ..
                } => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == balance);
                    }
                    let changing_storage: HashMap<U256, M256> = changing_storage.clone().into();
                    for (key, value) in changing_storage {
                        let expected_value = client.get_storage_at(&format!("0x{:x}", address),
                                                                   &format!("0x{:x}", key),
                                                                   &cur_number);
                        assert!(M256::from_str(&expected_value).unwrap() == value);
                    }
                },
                &AccountChange::Create {
                    address,
                    balance,
                    ref storage,
                    ..
                } => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let expected_balance = client.get_balance(&format!("0x{:x}", address),
                                                                  &cur_number);
                        assert!(U256::from_str(&expected_balance).unwrap() == balance);
                    }
                    let storage: HashMap<U256, M256> = storage.clone().into();
                    for (key, value) in storage {
                        let expected_value = client.get_storage_at(&format!("0x{:x}", address),
                                                                   &format!("0x{:x}", key),
                                                                   &cur_number);
                        assert!(M256::from_str(&expected_value).unwrap() == value);
                    }
                },
                &AccountChange::IncreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let last_balance = client.get_balance(&format!("0x{:x}", address),
                                                              &last_number);
                        let cur_balance = client.get_balance(&format!("0x{:x}", address),
                                                             &cur_number);

                        assert!(U256::from_str(&last_balance).unwrap() + balance ==
                                U256::from_str(&cur_balance).unwrap());
                    }
                },
                &AccountChange::DecreaseBalance(address, balance) => {
                    if !is_miner_or_uncle(client, address, &block) {
                        let last_balance = client.get_balance(&format!("0x{:x}", address),
                                                              &last_number);
                        let cur_balance = client.get_balance(&format!("0x{:x}", address),
                                                             &cur_number);

                        assert!(U256::from_str(&last_balance).unwrap() - balance ==
                                U256::from_str(&cur_balance).unwrap());
                    }
                },
            }
        }
    }
}

fn test_blocks_patch<T: GethRPCClient>(client: &mut T, number: &str, patch: Option<&str>) {
    match patch {
        Some("frontier") => test_blocks::<_, FrontierPatch>(client, number),
        Some("homestead") => test_blocks::<_, HomesteadPatch>(client, number),
        Some("eip150") => test_blocks::<_, EIP150Patch>(client, number),
        Some("eip160") => test_blocks::<_, EIP160Patch>(client, number),
        _ => panic!("Unknown patch."),
    }
}

fn test_blocks<T: GethRPCClient, P: Patch>(client: &mut T, number: &str) {
    if number.contains(".json") {
        let file = File::open(number).unwrap();
        let numbers: Vec<usize> = serde_json::from_reader(file).unwrap();
        for n in numbers {
            test_block::<_, P>(client, n);
        }
    } else if number.contains("..") {
        let number: Vec<&str> = number.split("..").collect();
        let from = usize::from_str_radix(&number[0], 10).unwrap();
        let to = usize::from_str_radix(&number[1], 10).unwrap();
        for n in from..to {
            test_block::<_, P>(client, n);
        }
    } else if number.contains(",") {
        let numbers: Vec<&str> = number.split("..").collect();
        for number in numbers {
            let n = usize::from_str_radix(number, 10).unwrap();
            test_block::<_, P>(client, n);
        }
    } else {
        let number = usize::from_str_radix(&number, 10).unwrap();
        test_block::<_, P>(client, number);
    }
}

fn main() {
    let matches = clap_app!(regtests =>
        (version: "0.1")
        (author: "Ethereum Classic Contributors")
        (about: "Performs an regression test on the entire Ethereum Classic blockchain.\n\nSteps to reproduce:\n* Install Ethereum Classic Geth: `$ go install github.com/ethereumproject/go-ethereum/cmd/geth`.\n* Run Geth with this command: `$ ~/go/bin/geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545`.\n* Wait for the chain to sync.\n* Change directory into the `regtests` directory `$ cd regtests`\n* Run this command: `$ RUST_BACKTRACE=1 cargo run --bin regtests -- -r http://127.0.0.1:8545")
        (@arg RPC: -r --rpc +takes_value +required "Domain of Ethereum Classic Geth's RPC endpoint. e.g. `-r http://127.0.0.1:8545`.")
        (@arg NUMBER: -n --number +takes_value +required "Block number to run this test. Radix is 10. e.g. `-n 49439`.")
        (@arg RECORD: --record +takes_value "Record to file path.")
        (@arg PATCH: -p --patch +takes_value +required "Patch to be used, homestead or frontier.")
    ).get_matches();

    let address = matches.value_of("RPC").unwrap();
    let number = matches.value_of("NUMBER").unwrap();
    let record = matches.value_of("RECORD");
    let patch = matches.value_of("PATCH");

    if address.contains(".json") {
        let file = File::open(address).unwrap();
        let cached: serde_json::Value = serde_json::from_reader(file).unwrap();
        let mut client = CachedGethRPCClient::from_value(cached);
        test_blocks_patch(&mut client, number, patch);
    } else {
        match record {
            Some(val) => {
                let mut file = File::create(val).unwrap();
                let mut client = RecordGethRPCClient::new(address);
                test_blocks_patch(&mut client, number, patch);
                serde_json::to_writer(&mut file, &client.to_value());
            },
            None => {
                let mut client = NormalGethRPCClient::new(address);
                test_blocks_patch(&mut client, number, patch);
            }
        }
    }
}

#[cfg(test)]
#[test]
fn test_all_previously_failed_frontier_blocks() {
    let cached: serde_json::Value = serde_json::from_str(include_str!("../../res/frontier_records.json")).unwrap();
    let numbers: Vec<usize> = serde_json::from_str(include_str!("../../res/frontier_numbers.json")).unwrap();
    let mut client = CachedGethRPCClient::from_value(cached);
    for n in numbers {
        test_block(&mut client, n, &FRONTIER_PATCH);
    }
}

#[cfg(test)]
#[test]
fn test_all_previously_failed_homestead_blocks() {
    let cached: serde_json::Value = serde_json::from_str(include_str!("../../res/homestead_records.json")).unwrap();
    let numbers: Vec<usize> = serde_json::from_str(include_str!("../../res/homestead_numbers.json")).unwrap();
    let mut client = CachedGethRPCClient::from_value(cached);
    for n in numbers {
        test_block(&mut client, n, &HOMESTEAD_PATCH);
    }
}

#[cfg(test)]
#[test]
fn test_all_previously_failed_eip150_blocks() {
    let cached: serde_json::Value = serde_json::from_str(include_str!("../../res/eip150_records.json")).unwrap();
    let numbers: Vec<usize> = serde_json::from_str(include_str!("../../res/eip150_numbers.json")).unwrap();
    let mut client = CachedGethRPCClient::from_value(cached);
    for n in numbers {
        test_block(&mut client, n, &EIP150_PATCH);
    }
}
<|endoftext|>


<commit_before>mod statistics;
mod planner;

use kite::query::Query;
use kite::collectors::{Collector, DocumentMatch};
use byteorder::{ByteOrder, BigEndian};
use rocksdb;

use key_builder::KeyBuilder;
use document_index::DocRef;
use super::RocksDBIndexReader;
use doc_id_set::DocIdSet;
use search::statistics::StatisticsReader;
use search::planner::{SearchPlan, plan_query};
use search::planner::boolean_query::BooleanQueryOp;
use search::planner::score_function::{CombinatorScorer, ScoreFunctionOp};

impl<'a> RocksDBIndexReader<'a> {
    fn search_segment_boolean_phase(&self, boolean_query: &Vec<BooleanQueryOp>, is_negated: bool, segment: u32) -> Result<DocIdSet, rocksdb::Error> {
        // Execute boolean query
        let mut stack = Vec::new();
        for op in boolean_query.iter() {
            match *op {
                BooleanQueryOp::PushEmpty => {
                    stack.push(DocIdSet::new_filled(0));
                }
                BooleanQueryOp::PushFull => {
                    stack.push(DocIdSet::new_filled(65536));
                }
                BooleanQueryOp::PushTermDirectory(field_ref, term_ref) => {
                    let kb = KeyBuilder::segment_dir_list(segment, field_ref.ord(), term_ref.ord());
                    match try!(self.snapshot.get(&kb.key())) {
                        Some(docid_set) => {
                            let data = DocIdSet::FromRDB(docid_set);
                            stack.push(data);
                        }
                        None => stack.push(DocIdSet::new_filled(0)),
                    }
                }
                BooleanQueryOp::PushDeletionList => {
                    let kb = KeyBuilder::segment_del_list(segment);
                    match try!(self.snapshot.get(&kb.key())) {
                        Some(deletion_list) => {
                            let data = DocIdSet::FromRDB(deletion_list);
                            stack.push(data);
                        }
                        None => stack.push(DocIdSet::new_filled(0)),
                    }
                }
                BooleanQueryOp::And => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.intersection(&b));
                }
                BooleanQueryOp::Or => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.union(&b));
                }
                BooleanQueryOp::AndNot => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.exclusion(&b));
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("boolean query executor: stack size too big ({})", stack.len());
        }
        let mut matches = stack.pop().unwrap();

        // Invert the list if the query is negated
        if is_negated {
            let kb = KeyBuilder::segment_stat(segment, b"total_docs");
            let total_docs = match try!(self.snapshot.get(&kb.key())) {
                Some(total_docs) => BigEndian::read_i64(&total_docs) as u32,
                None => 0,
            };

            let all_docs = DocIdSet::new_filled(total_docs);
            matches = all_docs.exclusion(&matches);
        }

        Ok(matches)
    }

    fn score_doc(&self, doc_id: u16, score_function: &Vec<ScoreFunctionOp>, segment: u32, mut stats: &mut StatisticsReader) -> Result<f64, rocksdb::Error> {
        // Execute score function
        let mut stack = Vec::new();
        for op in score_function.iter() {
            match *op {
                ScoreFunctionOp::Literal(val) => stack.push(val),
                ScoreFunctionOp::TermScorer(field_ref, term_ref, ref scorer) => {
                    let kb = KeyBuilder::segment_dir_list(segment, field_ref.ord(), term_ref.ord());
                    match try!(self.snapshot.get(&kb.key())) {
                        Some(data) => {
                            let docid_set = DocIdSet::FromRDB(data);

                            if docid_set.contains_doc(doc_id) {
                                // Read field length
                                // TODO: we only need this for BM25
                                let kb = KeyBuilder::stored_field_value(segment, doc_id, field_ref.ord(), b"len");
                                let field_length = match try!(self.snapshot.get(&kb.key())) {
                                    Some(value) => {
                                        let length_sqrt = (value[0] as f64) / 3.0 + 1.0;
                                        length_sqrt * length_sqrt
                                    }
                                    None => 1.0,
                                };

                                // Read term frequency
                                let mut value_type = vec![b't', b'f'];
                                value_type.extend(term_ref.ord().to_string().as_bytes());
                                let kb = KeyBuilder::stored_field_value(segment, doc_id, field_ref.ord(), &value_type);
                                let term_frequency = match try!(self.snapshot.get(&kb.key())) {
                                    Some(value) => BigEndian::read_i64(&value),
                                    None => 1,
                                };

                                let score = scorer.similarity_model.score(term_frequency as u32, field_length, try!(stats.total_tokens(field_ref)) as u64, try!(stats.total_docs(field_ref)) as u64, try!(stats.term_document_frequency(field_ref, term_ref)) as u64);
                                stack.push(score * scorer.boost);
                            } else {
                                stack.push(0.0f64);
                            }
                        }
                        None => stack.push(0.0f64),
                    }
                }
                ScoreFunctionOp::CombinatorScorer(num_vals, ref scorer) => {
                    let score = match *scorer {
                        CombinatorScorer::Avg => {
                            let mut total_score = 0.0f64;

                            for _ in 0..num_vals {
                                total_score += stack.pop().expect("document scorer: stack underflow");
                            }

                            total_score / num_vals as f64
                        }
                        CombinatorScorer::Max => {
                            let mut max_score = 0.0f64;

                            for _ in 0..num_vals {
                                let score = stack.pop().expect("document scorer: stack underflow");
                                if score > max_score {
                                    max_score = score
                                }
                            }

                            max_score
                        }
                    };

                    stack.push(score);
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("document scorer: stack size too big ({})", stack.len());
        }

        Ok(stack.pop().expect("document scorer: stack underflow"))
    }

    fn search_segment<C: Collector>(&self, collector: &mut C, plan: &SearchPlan, segment: u32, mut stats: &mut StatisticsReader) -> Result<(), rocksdb::Error> {
        let matches = try!(self.search_segment_boolean_phase(&plan.boolean_query, plan.boolean_query_is_negated, segment));

        // Score documents and pass to collector
        for doc in matches.iter() {
            let score = try!(self.score_doc(doc, &plan.score_function, segment, &mut stats));

            let doc_ref = DocRef::from_segment_ord(segment, doc);
            let doc_match = DocumentMatch::new_scored(doc_ref.as_u64(), score);
            collector.collect(doc_match);
        }

        Ok(())
    }

    pub fn search<C: Collector>(&self, collector: &mut C, query: &Query) -> Result<(), rocksdb::Error> {
        // Plan query
        let plan = plan_query(&self, query, collector.needs_score());

        // Initialise statistics reader
        let mut stats = StatisticsReader::new(&self);

        // Run query on each segment
        for segment in self.store.segments.iter_active(&self.snapshot) {
            try!(self.search_segment(collector, &plan, segment, &mut stats));
        }

        Ok(())
    }
}
<commit_msg>Use Segment stuct in search_segment_boolean_phase<commit_after>mod statistics;
mod planner;

use kite::query::Query;
use kite::collectors::{Collector, DocumentMatch};
use byteorder::{ByteOrder, BigEndian};
use rocksdb;

use key_builder::KeyBuilder;
use document_index::DocRef;
use super::RocksDBIndexReader;
use doc_id_set::DocIdSet;
use segment::Segment;
use search::statistics::StatisticsReader;
use search::planner::{SearchPlan, plan_query};
use search::planner::boolean_query::BooleanQueryOp;
use search::planner::score_function::{CombinatorScorer, ScoreFunctionOp};

impl<'a> RocksDBIndexReader<'a> {
    fn search_segment_boolean_phase(&self, boolean_query: &Vec<BooleanQueryOp>, is_negated: bool, segment: &Segment) -> Result<DocIdSet, rocksdb::Error> {
        // Execute boolean query
        let mut stack = Vec::new();
        for op in boolean_query.iter() {
            match *op {
                BooleanQueryOp::PushEmpty => {
                    stack.push(DocIdSet::new_filled(0));
                }
                BooleanQueryOp::PushFull => {
                    stack.push(DocIdSet::new_filled(65536));
                }
                BooleanQueryOp::PushTermDirectory(field_ref, term_ref) => {
                    match try!(segment.load_term_directory(field_ref, term_ref)) {
                        Some(doc_id_set) => stack.push(doc_id_set),
                        None => stack.push(DocIdSet::new_filled(0)),
                    }
                }
                BooleanQueryOp::PushDeletionList => {
                     match try!(segment.load_deletion_list()) {
                        Some(doc_id_set) => stack.push(doc_id_set),
                        None => stack.push(DocIdSet::new_filled(0)),
                    }
                }
                BooleanQueryOp::And => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.intersection(&b));
                }
                BooleanQueryOp::Or => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.union(&b));
                }
                BooleanQueryOp::AndNot => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.exclusion(&b));
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("boolean query executor: stack size too big ({})", stack.len());
        }
        let mut matches = stack.pop().unwrap();

        // Invert the list if the query is negated
        if is_negated {
            let total_docs = try!(segment.load_statistic(b"total_docs")).unwrap_or(0);
            let all_docs = DocIdSet::new_filled(total_docs as u32);
            matches = all_docs.exclusion(&matches);
        }

        Ok(matches)
    }

    fn score_doc(&self, doc_id: u16, score_function: &Vec<ScoreFunctionOp>, segment: u32, mut stats: &mut StatisticsReader) -> Result<f64, rocksdb::Error> {
        // Execute score function
        let mut stack = Vec::new();
        for op in score_function.iter() {
            match *op {
                ScoreFunctionOp::Literal(val) => stack.push(val),
                ScoreFunctionOp::TermScorer(field_ref, term_ref, ref scorer) => {
                    let kb = KeyBuilder::segment_dir_list(segment, field_ref.ord(), term_ref.ord());
                    match try!(self.snapshot.get(&kb.key())) {
                        Some(data) => {
                            let docid_set = DocIdSet::FromRDB(data);

                            if docid_set.contains_doc(doc_id) {
                                // Read field length
                                // TODO: we only need this for BM25
                                let kb = KeyBuilder::stored_field_value(segment, doc_id, field_ref.ord(), b"len");
                                let field_length = match try!(self.snapshot.get(&kb.key())) {
                                    Some(value) => {
                                        let length_sqrt = (value[0] as f64) / 3.0 + 1.0;
                                        length_sqrt * length_sqrt
                                    }
                                    None => 1.0,
                                };

                                // Read term frequency
                                let mut value_type = vec![b't', b'f'];
                                value_type.extend(term_ref.ord().to_string().as_bytes());
                                let kb = KeyBuilder::stored_field_value(segment, doc_id, field_ref.ord(), &value_type);
                                let term_frequency = match try!(self.snapshot.get(&kb.key())) {
                                    Some(value) => BigEndian::read_i64(&value),
                                    None => 1,
                                };

                                let score = scorer.similarity_model.score(term_frequency as u32, field_length, try!(stats.total_tokens(field_ref)) as u64, try!(stats.total_docs(field_ref)) as u64, try!(stats.term_document_frequency(field_ref, term_ref)) as u64);
                                stack.push(score * scorer.boost);
                            } else {
                                stack.push(0.0f64);
                            }
                        }
                        None => stack.push(0.0f64),
                    }
                }
                ScoreFunctionOp::CombinatorScorer(num_vals, ref scorer) => {
                    let score = match *scorer {
                        CombinatorScorer::Avg => {
                            let mut total_score = 0.0f64;

                            for _ in 0..num_vals {
                                total_score += stack.pop().expect("document scorer: stack underflow");
                            }

                            total_score / num_vals as f64
                        }
                        CombinatorScorer::Max => {
                            let mut max_score = 0.0f64;

                            for _ in 0..num_vals {
                                let score = stack.pop().expect("document scorer: stack underflow");
                                if score > max_score {
                                    max_score = score
                                }
                            }

                            max_score
                        }
                    };

                    stack.push(score);
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("document scorer: stack size too big ({})", stack.len());
        }

        Ok(stack.pop().expect("document scorer: stack underflow"))
    }

    fn search_segment<C: Collector>(&self, collector: &mut C, plan: &SearchPlan, segment: u32, mut stats: &mut StatisticsReader) -> Result<(), rocksdb::Error> {
        let matches = try!(self.search_segment_boolean_phase(&plan.boolean_query, plan.boolean_query_is_negated, &Segment::new(self, segment)));

        // Score documents and pass to collector
        for doc in matches.iter() {
            let score = try!(self.score_doc(doc, &plan.score_function, segment, &mut stats));

            let doc_ref = DocRef::from_segment_ord(segment, doc);
            let doc_match = DocumentMatch::new_scored(doc_ref.as_u64(), score);
            collector.collect(doc_match);
        }

        Ok(())
    }

    pub fn search<C: Collector>(&self, collector: &mut C, query: &Query) -> Result<(), rocksdb::Error> {
        // Plan query
        let plan = plan_query(&self, query, collector.needs_score());

        // Initialise statistics reader
        let mut stats = StatisticsReader::new(&self);

        // Run query on each segment
        for segment in self.store.segments.iter_active(&self.snapshot) {
            try!(self.search_segment(collector, &plan, segment, &mut stats));
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use proc_macro2::Span;
use quote::Tokens;
use syn::Ident;

use internals::ast::{Container, Data, Field, Style};

// Suppress dead_code warnings that would otherwise appear when using a remote
// derive. Other than this pretend code, a struct annotated with remote derive
// never has its fields referenced and an enum annotated with remote derive
// never has its variants constructed.
//
//     warning: field is never used: `i`
//      --> src/main.rs:4:20
//       |
//     4 | struct StructDef { i: i32 }
//       |                    ^^^^^^
//
//     warning: variant is never constructed: `V`
//      --> src/main.rs:8:16
//       |
//     8 | enum EnumDef { V }
//       |                ^
//
pub fn pretend_used(cont: &Container) -> Tokens {
    let pretend_fields = pretend_fields_used(cont);
    let pretend_variants = pretend_variants_used(cont);

    quote! {
        #pretend_fields
        #pretend_variants
    }
}

// For structs with named fields, expands to:
//
//     match None::<T> {
//         Some(T { a: ref __v0, b: ref __v1 }) => {}
//         _ => {}
//     }
//
// For enums, expands to the following but only including struct variants:
//
//     match None::<T> {
//         Some(T::A { a: ref __v0 }) => {}
//         Some(T::B { b: ref __v0 }) => {}
//         _ => {}
//     }
//
// The `ref` is important in case the user has written a Drop impl on their
// type. Rust does not allow destructuring a struct or enum that has a Drop
// impl.
fn pretend_fields_used(cont: &Container) -> Tokens {
    let type_ident = cont.ident;
    let (_, ty_generics, _) = cont.generics.split_for_impl();

    let patterns = match cont.data {
        Data::Enum(ref variants) => {
            variants.iter()
                .filter_map(|variant| match variant.style {
                    Style::Struct => {
                        let variant_ident = variant.ident;
                        let pat = struct_pattern(&variant.fields);
                        Some(quote!(#type_ident::#variant_ident #pat))
                    }
                    _ => None,
                })
                .collect::<Vec<_>>()
        }
        Data::Struct(Style::Struct, ref fields) => {
            let pat = struct_pattern(fields);
            vec![quote!(#type_ident #pat)]
        }
        Data::Struct(_, _) => {
            return quote!();
        }
    };

    quote! {
        match _serde::export::None::<#type_ident #ty_generics> {
            #(
                _serde::export::Some(#patterns) => {}
            )*
            _ => {}
        }
    }
}

// Expands to one of these per enum variant:
//
//     match None {
//         Some((__v0, __v1,)) => {
//             let _ = E::V { a: __v0, b: __v1 };
//         }
//         _ => {}
//     }
//
fn pretend_variants_used(cont: &Container) -> Tokens {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return quote!();
        }
    };

    let type_ident = cont.ident;
    let (_, ty_generics, _) = cont.generics.split_for_impl();
    let turbofish = ty_generics.as_turbofish();

    let cases = variants.iter()
        .map(|variant| {
            let variant_ident = variant.ident;
            let ref placeholders = (0..variant.fields.len())
                .map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
                .collect::<Vec<_>>();

            let pat = match variant.style {
                Style::Struct => {
                    let names = variant.fields.iter().map(|field| field.ident);
                    quote!({ #(#names: #placeholders),* })
                }
                Style::Tuple | Style::Newtype => {
                    quote!(( #(#placeholders),* ))
                }
                Style::Unit => quote!(),
            };

            quote! {
                match _serde::export::None {
                    _serde::export::Some((#(#placeholders,)*)) => {
                        let _ = #type_ident::#variant_ident #turbofish #pat;
                    }
                    _ => {}
                }
            }
        });

    quote!(#(#cases)*)
}

fn struct_pattern(fields: &[Field]) -> Tokens {
    let names = fields.iter().map(|field| field.ident);
    let placeholders = (0..fields.len())
        .map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
    quote!({ #(#names: ref #placeholders),* })
}
<commit_msg>Format with rustfmt 0.6.1<commit_after>use proc_macro2::Span;
use quote::Tokens;
use syn::Ident;

use internals::ast::{Container, Data, Field, Style};

// Suppress dead_code warnings that would otherwise appear when using a remote
// derive. Other than this pretend code, a struct annotated with remote derive
// never has its fields referenced and an enum annotated with remote derive
// never has its variants constructed.
//
//     warning: field is never used: `i`
//      --> src/main.rs:4:20
//       |
//     4 | struct StructDef { i: i32 }
//       |                    ^^^^^^
//
//     warning: variant is never constructed: `V`
//      --> src/main.rs:8:16
//       |
//     8 | enum EnumDef { V }
//       |                ^
//
pub fn pretend_used(cont: &Container) -> Tokens {
    let pretend_fields = pretend_fields_used(cont);
    let pretend_variants = pretend_variants_used(cont);

    quote! {
        #pretend_fields
        #pretend_variants
    }
}

// For structs with named fields, expands to:
//
//     match None::<T> {
//         Some(T { a: ref __v0, b: ref __v1 }) => {}
//         _ => {}
//     }
//
// For enums, expands to the following but only including struct variants:
//
//     match None::<T> {
//         Some(T::A { a: ref __v0 }) => {}
//         Some(T::B { b: ref __v0 }) => {}
//         _ => {}
//     }
//
// The `ref` is important in case the user has written a Drop impl on their
// type. Rust does not allow destructuring a struct or enum that has a Drop
// impl.
fn pretend_fields_used(cont: &Container) -> Tokens {
    let type_ident = cont.ident;
    let (_, ty_generics, _) = cont.generics.split_for_impl();

    let patterns = match cont.data {
        Data::Enum(ref variants) => variants
            .iter()
            .filter_map(|variant| match variant.style {
                Style::Struct => {
                    let variant_ident = variant.ident;
                    let pat = struct_pattern(&variant.fields);
                    Some(quote!(#type_ident::#variant_ident #pat))
                }
                _ => None,
            })
            .collect::<Vec<_>>(),
        Data::Struct(Style::Struct, ref fields) => {
            let pat = struct_pattern(fields);
            vec![quote!(#type_ident #pat)]
        }
        Data::Struct(_, _) => {
            return quote!();
        }
    };

    quote! {
        match _serde::export::None::<#type_ident #ty_generics> {
            #(
                _serde::export::Some(#patterns) => {}
            )*
            _ => {}
        }
    }
}

// Expands to one of these per enum variant:
//
//     match None {
//         Some((__v0, __v1,)) => {
//             let _ = E::V { a: __v0, b: __v1 };
//         }
//         _ => {}
//     }
//
fn pretend_variants_used(cont: &Container) -> Tokens {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return quote!();
        }
    };

    let type_ident = cont.ident;
    let (_, ty_generics, _) = cont.generics.split_for_impl();
    let turbofish = ty_generics.as_turbofish();

    let cases = variants.iter().map(|variant| {
        let variant_ident = variant.ident;
        let ref placeholders = (0..variant.fields.len())
            .map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
            .collect::<Vec<_>>();

        let pat = match variant.style {
            Style::Struct => {
                let names = variant.fields.iter().map(|field| field.ident);
                quote!({ #(#names: #placeholders),* })
            }
            Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
            Style::Unit => quote!(),
        };

        quote! {
            match _serde::export::None {
                _serde::export::Some((#(#placeholders,)*)) => {
                    let _ = #type_ident::#variant_ident #turbofish #pat;
                }
                _ => {}
            }
        }
    });

    quote!(#(#cases)*)
}

fn struct_pattern(fields: &[Field]) -> Tokens {
    let names = fields.iter().map(|field| field.ident);
    let placeholders =
        (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
    quote!({ #(#names: ref #placeholders),* })
}
<|endoftext|>


<commit_before>use reqwest::Url;
use rustyline::{error::ReadlineError, Editor};
use std::path::PathBuf;

mod cmd;
mod db;
mod parser;
mod script_builder;

use self::db::{Db, DbState};

pub struct Wallet {
    prompt: String,
    url: Url,
    db: Db,
}

impl Wallet {
    pub fn new(home: PathBuf) -> Wallet {
        let db = Db::new(home.join("db"));
        let prompt = (if db.state() == DbState::Locked {
            "locked>> "
        } else {
            "new>> "
        })
        .to_owned();
        Wallet {
            db,
            prompt,
            url: "http://localhost:7777".parse().unwrap(),
        }
    }

    pub fn start(mut self) {
        let mut rl = Editor::<()>::new();
        loop {
            let readline = rl.readline(&self.prompt);
            match readline {
                Ok(line) => {
                    if line.is_empty() {
                        continue;
                    }
                    let mut args = parser::parse_line(&line);

                    match self.process_line(&mut args) {
                        Ok(store_history) => {
                            if store_history {
                                rl.add_history_entry(line);
                            } else {
                                sodiumoxide::utils::memzero(&mut line.into_bytes());
                            }
                        }
                        Err(s) => {
                            println!("{}", s);
                            sodiumoxide::utils::memzero(&mut line.into_bytes());
                        }
                    }

                    for a in args {
                        sodiumoxide::utils::memzero(&mut a.into_bytes());
                    }
                }
                Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
                    println!("Closing wallet...");
                    break;
                }
                Err(err) => {
                    println!("Error reading input: {:?}", err);
                    break;
                }
            }
        }
    }

    fn process_line(&mut self, args: &mut Vec<String>) -> Result<bool, String> {
        if args.is_empty() {
            return Ok(false);
        }
        println!();
        match &*args[0] {
            "new" => cmd::create_wallet(self, args),
            "unlock" => cmd::unlock(self, args),
            "create_account" => cmd::account::create(self, args),
            "import_account" => cmd::account::import(self, args),
            "get_account" => cmd::account::get(self, args),
            "delete_account" => cmd::account::delete(self, args),
            "list_accounts" => cmd::account::list(self, args),
            "build_script" => cmd::build_script(self, args),
            "check_script_size" => cmd::check_script_size(self, args),
            "script_to_p2sh" => cmd::script_to_p2sh(self, args),
            "decode_tx" => cmd::decode_tx(self, args),
            "sign_tx" => cmd::sign_tx(self, args),
            "unsign_tx" => cmd::unsign_tx(self, args),
            "broadcast" => cmd::broadcast(self, args),
            "build_mint_tx" => cmd::build_mint_tx(self, args),
            "get_properties" => cmd::get_properties(self, args),
            "get_block" => cmd::get_block(self, args),
            "help" => {
                Self::print_usage("Displaying help...");
                Ok(true)
            }
            _ => {
                Self::print_usage(&format!("Invalid command: {}", args[0]));
                Ok(true)
            }
        }
    }

    fn print_usage(header: &str) {
        let mut cmds = Vec::<[&str; 2]>::new();
        cmds.push(["help", "Display this help menu"]);
        cmds.push(["new <password>", "Create a new wallet"]);
        cmds.push(["unlock <password>", "Unlock an existing wallet"]);
        cmds.push(["create_account <account>", "Create an account"]);
        cmds.push(["import_account <account> <wif>", "Import an account"]);
        cmds.push(["delete_account <account>", "Delete an existing account"]);
        cmds.push(["get_account <account>", "Retrieve account information"]);
        cmds.push(["list_accounts", "List all accounts"]);
        cmds.push(["build_script <...op>", "Builds a script"]);
        cmds.push([
            "check_script_size <raw_hex>",
            "Checks if the script is too large and prints the size in bytes",
        ]);
        cmds.push([
            "script_to_p2sh <raw_hex>",
            "Converts a script to a payable P2SH address",
        ]);
        cmds.push([
            "decode_tx <tx_hex>",
            "Decodes a transaction and prints it to console",
        ]);
        cmds.push(["sign_tx <tx_hex> <account...>", "Signs a raw transaction"]);
        cmds.push([
            "unsign_tx <sig_pos> <tx_hex>",
            "Removes a signature from a raw transaction",
        ]);
        cmds.push([
            "broadcast <tx_hex>",
            "Broadcasts a transaction to the network",
        ]);
        cmds.push([
            "build_mint_tx <timestamp_offset> <grael_asset> <owner_script> <attachment_path>",
            "Builds a mint transaction",
        ]);
        cmds.push(["get_properties", "Retrieve global network properties"]);
        cmds.push(["get_block <height>", "Retrieve a block from the network"]);

        let mut max_len = 0;
        for cmd in &cmds {
            assert_eq!(cmd.len(), 2);
            let cmd_len = cmd[0].len();
            if cmd_len > max_len {
                max_len = cmd_len;
            }
        }

        println!("{}\n", header);
        for cmd in &cmds {
            let mut c = cmd[0].to_owned();
            if c.len() < max_len {
                for _ in 0..max_len - c.len() {
                    c.push(' ');
                }
            }
            println!("  {}  {}", c, cmd[1]);
        }
        println!();
    }
}
<commit_msg>Use wallet_db instead of db in the path<commit_after>use reqwest::Url;
use rustyline::{error::ReadlineError, Editor};
use std::path::PathBuf;

mod cmd;
mod db;
mod parser;
mod script_builder;

use self::db::{Db, DbState};

pub struct Wallet {
    prompt: String,
    url: Url,
    db: Db,
}

impl Wallet {
    pub fn new(home: PathBuf) -> Wallet {
        let db = Db::new(home.join("wallet_db"));
        let prompt = (if db.state() == DbState::Locked {
            "locked>> "
        } else {
            "new>> "
        })
        .to_owned();
        Wallet {
            db,
            prompt,
            url: "http://localhost:7777".parse().unwrap(),
        }
    }

    pub fn start(mut self) {
        let mut rl = Editor::<()>::new();
        loop {
            let readline = rl.readline(&self.prompt);
            match readline {
                Ok(line) => {
                    if line.is_empty() {
                        continue;
                    }
                    let mut args = parser::parse_line(&line);

                    match self.process_line(&mut args) {
                        Ok(store_history) => {
                            if store_history {
                                rl.add_history_entry(line);
                            } else {
                                sodiumoxide::utils::memzero(&mut line.into_bytes());
                            }
                        }
                        Err(s) => {
                            println!("{}", s);
                            sodiumoxide::utils::memzero(&mut line.into_bytes());
                        }
                    }

                    for a in args {
                        sodiumoxide::utils::memzero(&mut a.into_bytes());
                    }
                }
                Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
                    println!("Closing wallet...");
                    break;
                }
                Err(err) => {
                    println!("Error reading input: {:?}", err);
                    break;
                }
            }
        }
    }

    fn process_line(&mut self, args: &mut Vec<String>) -> Result<bool, String> {
        if args.is_empty() {
            return Ok(false);
        }
        println!();
        match &*args[0] {
            "new" => cmd::create_wallet(self, args),
            "unlock" => cmd::unlock(self, args),
            "create_account" => cmd::account::create(self, args),
            "import_account" => cmd::account::import(self, args),
            "get_account" => cmd::account::get(self, args),
            "delete_account" => cmd::account::delete(self, args),
            "list_accounts" => cmd::account::list(self, args),
            "build_script" => cmd::build_script(self, args),
            "check_script_size" => cmd::check_script_size(self, args),
            "script_to_p2sh" => cmd::script_to_p2sh(self, args),
            "decode_tx" => cmd::decode_tx(self, args),
            "sign_tx" => cmd::sign_tx(self, args),
            "unsign_tx" => cmd::unsign_tx(self, args),
            "broadcast" => cmd::broadcast(self, args),
            "build_mint_tx" => cmd::build_mint_tx(self, args),
            "get_properties" => cmd::get_properties(self, args),
            "get_block" => cmd::get_block(self, args),
            "help" => {
                Self::print_usage("Displaying help...");
                Ok(true)
            }
            _ => {
                Self::print_usage(&format!("Invalid command: {}", args[0]));
                Ok(true)
            }
        }
    }

    fn print_usage(header: &str) {
        let mut cmds = Vec::<[&str; 2]>::new();
        cmds.push(["help", "Display this help menu"]);
        cmds.push(["new <password>", "Create a new wallet"]);
        cmds.push(["unlock <password>", "Unlock an existing wallet"]);
        cmds.push(["create_account <account>", "Create an account"]);
        cmds.push(["import_account <account> <wif>", "Import an account"]);
        cmds.push(["delete_account <account>", "Delete an existing account"]);
        cmds.push(["get_account <account>", "Retrieve account information"]);
        cmds.push(["list_accounts", "List all accounts"]);
        cmds.push(["build_script <...op>", "Builds a script"]);
        cmds.push([
            "check_script_size <raw_hex>",
            "Checks if the script is too large and prints the size in bytes",
        ]);
        cmds.push([
            "script_to_p2sh <raw_hex>",
            "Converts a script to a payable P2SH address",
        ]);
        cmds.push([
            "decode_tx <tx_hex>",
            "Decodes a transaction and prints it to console",
        ]);
        cmds.push(["sign_tx <tx_hex> <account...>", "Signs a raw transaction"]);
        cmds.push([
            "unsign_tx <sig_pos> <tx_hex>",
            "Removes a signature from a raw transaction",
        ]);
        cmds.push([
            "broadcast <tx_hex>",
            "Broadcasts a transaction to the network",
        ]);
        cmds.push([
            "build_mint_tx <timestamp_offset> <grael_asset> <owner_script> <attachment_path>",
            "Builds a mint transaction",
        ]);
        cmds.push(["get_properties", "Retrieve global network properties"]);
        cmds.push(["get_block <height>", "Retrieve a block from the network"]);

        let mut max_len = 0;
        for cmd in &cmds {
            assert_eq!(cmd.len(), 2);
            let cmd_len = cmd[0].len();
            if cmd_len > max_len {
                max_len = cmd_len;
            }
        }

        println!("{}\n", header);
        for cmd in &cmds {
            let mut c = cmd[0].to_owned();
            if c.len() < max_len {
                for _ in 0..max_len - c.len() {
                    c.push(' ');
                }
            }
            println!("  {}  {}", c, cmd[1]);
        }
        println!();
    }
}
<|endoftext|>


<commit_before>//! Provides set of implementation for hir's objects that allows get back location in file.

use either::Either;
use hir_def::{
    nameres::{ModuleOrigin, ModuleSource},
    src::{HasChildSource, HasSource as _},
    Lookup, VariantId,
};
use hir_expand::InFile;
use syntax::ast;

use crate::{
    db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
    MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
};

pub trait HasSource {
    type Ast;
    #[deprecated = "migrating to source() method that returns an Option"]
    fn source_old(self, db: &dyn HirDatabase) -> InFile<Self::Ast>;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
}

/// NB: Module is !HasSource, because it has two source nodes at the same time:
/// definition and declaration.
impl Module {
    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
    pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].definition_source(db.upcast())
    }

    pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
        let def_map = db.crate_def_map(self.id.krate);
        match def_map[self.id.local_id].origin {
            ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
            _ => false,
        }
    }

    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
    /// `None` for the crate root.
    pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].declaration_source(db.upcast())
    }
}

impl HasSource for Field {
    type Ast = FieldSource;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<FieldSource> {
        let var = VariantId::from(self.parent);
        let src = var.child_source(db.upcast());
        src.map(|it| match it[self.id].clone() {
            Either::Left(it) => FieldSource::Pos(it),
            Either::Right(it) => FieldSource::Named(it),
        })
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let var = VariantId::from(self.parent);
        let src = var.child_source(db.upcast());
        let field_source = src.map(|it| match it[self.id].clone() {
            Either::Left(it) => FieldSource::Pos(it),
            Either::Right(it) => FieldSource::Named(it),
        });
        Some(field_source)
    }
}
impl HasSource for Struct {
    type Ast = ast::Struct;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Union {
    type Ast = ast::Union;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Enum {
    type Ast = ast::Enum;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Variant {
    type Ast = ast::Variant;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
        self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> {
        Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()))
    }
}
impl HasSource for Function {
    type Ast = ast::Fn;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Const {
    type Ast = ast::Const;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Static {
    type Ast = ast::Static;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Trait {
    type Ast = ast::Trait;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for TypeAlias {
    type Ast = ast::TypeAlias;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for MacroDef {
    type Ast = ast::Macro;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Macro> {
        InFile {
            file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
            value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
        }
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let ast_id = self.id.ast_id?;
        Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
    }
}
impl HasSource for Impl {
    type Ast = ast::Impl;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
        self.id.lookup(db.upcast()).source(db.upcast())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}

impl HasSource for TypeParam {
    type Ast = Either<ast::Trait, ast::TypeParam>;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
        let child_source = self.id.parent.child_source(db.upcast());
        child_source.map(|it| it[self.id.local_id].clone())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let child_source = self.id.parent.child_source(db.upcast());
        Some(child_source.map(|it| it[self.id.local_id].clone()))
    }
}

impl HasSource for LifetimeParam {
    type Ast = ast::LifetimeParam;
    fn source_old(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
        let child_source = self.id.parent.child_source(db.upcast());
        child_source.map(|it| it[self.id.local_id].clone())
    }

    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let child_source = self.id.parent.child_source(db.upcast());
        Some(child_source.map(|it| it[self.id.local_id].clone()))
    }
}

impl HasSource for ConstParam {
    type Ast = ast::ConstParam;
    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
        let child_source = self.id.parent.child_source(db.upcast());
        child_source.map(|it| it[self.id.local_id].clone())
    }
}
<commit_msg>Remove old_source now we've fully migrated<commit_after>//! Provides set of implementation for hir's objects that allows get back location in file.

use either::Either;
use hir_def::{
    nameres::{ModuleOrigin, ModuleSource},
    src::{HasChildSource, HasSource as _},
    Lookup, VariantId,
};
use hir_expand::InFile;
use syntax::ast;

use crate::{
    db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
    MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
};

pub trait HasSource {
    type Ast;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
}

/// NB: Module is !HasSource, because it has two source nodes at the same time:
/// definition and declaration.
impl Module {
    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
    pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].definition_source(db.upcast())
    }

    pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
        let def_map = db.crate_def_map(self.id.krate);
        match def_map[self.id.local_id].origin {
            ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
            _ => false,
        }
    }

    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
    /// `None` for the crate root.
    pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
        let def_map = db.crate_def_map(self.id.krate);
        def_map[self.id.local_id].declaration_source(db.upcast())
    }
}

impl HasSource for Field {
    type Ast = FieldSource;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let var = VariantId::from(self.parent);
        let src = var.child_source(db.upcast());
        let field_source = src.map(|it| match it[self.id].clone() {
            Either::Left(it) => FieldSource::Pos(it),
            Either::Right(it) => FieldSource::Named(it),
        });
        Some(field_source)
    }
}
impl HasSource for Struct {
    type Ast = ast::Struct;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Union {
    type Ast = ast::Union;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Enum {
    type Ast = ast::Enum;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Variant {
    type Ast = ast::Variant;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> {
        Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()))
    }
}
impl HasSource for Function {
    type Ast = ast::Fn;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Const {
    type Ast = ast::Const;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Static {
    type Ast = ast::Static;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for Trait {
    type Ast = ast::Trait;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for TypeAlias {
    type Ast = ast::TypeAlias;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}
impl HasSource for MacroDef {
    type Ast = ast::Macro;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let ast_id = self.id.ast_id?;
        Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
    }
}
impl HasSource for Impl {
    type Ast = ast::Impl;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        Some(self.id.lookup(db.upcast()).source(db.upcast()))
    }
}

impl HasSource for TypeParam {
    type Ast = Either<ast::Trait, ast::TypeParam>;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let child_source = self.id.parent.child_source(db.upcast());
        Some(child_source.map(|it| it[self.id.local_id].clone()))
    }
}

impl HasSource for LifetimeParam {
    type Ast = ast::LifetimeParam;
    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
        let child_source = self.id.parent.child_source(db.upcast());
        Some(child_source.map(|it| it[self.id.local_id].clone()))
    }
}

impl HasSource for ConstParam {
    type Ast = ast::ConstParam;
    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
        let child_source = self.id.parent.child_source(db.upcast());
        child_source.map(|it| it[self.id.local_id].clone())
    }
}
<|endoftext|>


<commit_before>/// Returns true if the find string can be found in the search string.
/// # Examples
///
/// ```
/// use substring::has_substring;
///
/// assert!(has_substring("abcdef", "def"));
/// assert!(!has_substring("abcdef", "xyz"));
/// ```
pub fn has_substring(search: &str, find: &str) -> bool {
    // The non-brute-force algorithms would be too difficult to implement in an
    // interview without reference so accept that this will be O(nm).
    if search.is_empty() {
        return find.is_empty();
    }

    let search_bytes = search.as_bytes();
    let find_bytes = find.as_bytes();
    let max_search_index = search_bytes.len() - find_bytes.len();

    for i in 0..(max_search_index + 1) {
        let mut found = true;
        for j in 0..find_bytes.len() {
            if search_bytes[i + j] != find_bytes[j] {
                found = false;
                break;
            }
        }
        if found {
            return true;
        }
    }
    false
}

#[test]
fn substring_at_end() {
    assert!(has_substring("abcdef", "def"));
}

#[test]
fn substring_at_beginning() {
    assert!(has_substring("abcdef", "abc"));
}

#[test]
fn substring_in_middle() {
    assert!(has_substring("abcdef", "cde"));
}

#[test]
fn substring_empty() {
    assert!(has_substring("abcdef", ""));
}

#[test]
fn search_string_empty() {
    assert!(!has_substring("", "abc"));
}

#[test]
fn search_string_and_substring_empty() {
    assert!(has_substring("", ""));
}

#[test]
fn search_string_has_repeating_pattern() {
    assert!(has_substring("aaaaaaaaaaaaaba", "aaab"));
}

#[test]
fn substring_not_found() {
    assert!(!has_substring("aaaaaaaaaaaaaba", "aaabb"));
}

#[test]
fn non_ascii() {
    assert!(has_substring(
        "Οἱ δὲ Φοίνιϰες οὗτοι οἱ σὺν Κάδμῳ ἀπιϰόμενοι..",
        "Φοίνιϰες"));
}
<commit_msg>Fix the grammar in a comment.<commit_after>/// Returns true if the find string can be found in the search string.
///
/// # Examples
///
/// ```
/// use substring::has_substring;
///
/// assert!(has_substring("abcdef", "def"));
/// assert!(!has_substring("abcdef", "xyz"));
/// ```
pub fn has_substring(search: &str, find: &str) -> bool {
    // Any non-brute-force algorithm would be too difficult to implement in an
    // interview without reference so implement the naive O(nm) solution.
    if search.is_empty() {
        return find.is_empty();
    }

    let search_bytes = search.as_bytes();
    let find_bytes = find.as_bytes();
    let max_search_index = search_bytes.len() - find_bytes.len();

    for i in 0..(max_search_index + 1) {
        let mut found = true;
        for j in 0..find_bytes.len() {
            if search_bytes[i + j] != find_bytes[j] {
                found = false;
                break;
            }
        }
        if found {
            return true;
        }
    }
    false
}

#[test]
fn substring_at_end() {
    assert!(has_substring("abcdef", "def"));
}

#[test]
fn substring_at_beginning() {
    assert!(has_substring("abcdef", "abc"));
}

#[test]
fn substring_in_middle() {
    assert!(has_substring("abcdef", "cde"));
}

#[test]
fn substring_empty() {
    assert!(has_substring("abcdef", ""));
}

#[test]
fn search_string_empty() {
    assert!(!has_substring("", "abc"));
}

#[test]
fn search_string_and_substring_empty() {
    assert!(has_substring("", ""));
}

#[test]
fn search_string_has_repeating_pattern() {
    assert!(has_substring("aaaaaaaaaaaaaba", "aaab"));
}

#[test]
fn substring_not_found() {
    assert!(!has_substring("aaaaaaaaaaaaaba", "aaabb"));
}

#[test]
fn non_ascii() {
    assert!(has_substring(
        "Οἱ δὲ Φοίνιϰες οὗτοι οἱ σὺν Κάδμῳ ἀπιϰόμενοι..",
        "Φοίνιϰες"));
}
<|endoftext|>


<commit_before>//! The Rust Prelude.
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: crate::io::prelude
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their constituent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and re-exports the following:
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]},
//!   marker traits that indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}, various
//!   operations for both destructors and overloading `()`.
//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
//!   dropping a value.
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`], the conversion trait that defines
//!   [`to_owned`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }, the
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}, generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [`std::default`]::[`Default`], types that have default values.
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`]
//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}, iterators of various
//!   kinds.
//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}, a
//!   type which expresses the presence or absence of a value. This type is so
//!   commonly used, its variants are also exported.
//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}, a type
//!   for functions that may succeed or fail. Like [`Option`], its variants are
//!   exported as well.
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
//! * [`std::vec`]::[`Vec`], a growable, heap-allocated vector.
//!
//! [`mem::drop`]: crate::mem::drop
//! [`std::borrow`]: crate::borrow
//! [`std::boxed`]: crate::boxed
//! [`std::clone`]: crate::clone
//! [`std::cmp`]: crate::cmp
//! [`std::convert`]: crate::convert
//! [`std::default`]: crate::default
//! [`std::iter`]: crate::iter
//! [`std::marker`]: crate::marker
//! [`std::mem`]: crate::mem
//! [`std::ops`]: crate::ops
//! [`std::option`]: crate::option
//! [`std::prelude::v1`]: v1
//! [`std::result`]: crate::result
//! [`std::slice`]: crate::slice
//! [`std::string`]: crate::string
//! [`std::vec`]: mod@crate::vec
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
//! [book-iter]: ../../book/ch13-02-iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<commit_msg>Use consistent punctuation for 'Prelude contents' docs<commit_after>//! The Rust Prelude.
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: crate::io::prelude
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their constituent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and re-exports the following:
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}:
//!   Marker traits that indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}: Various
//!   operations for both destructors and overloading `()`.
//! * [`std::mem`]::[`drop`][`mem::drop`]: A convenience function for explicitly
//!   dropping a value.
//! * [`std::boxed`]::[`Box`]: A way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`]: The conversion trait that defines
//!   [`to_owned`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [`std::clone`]::[`Clone`]: The ubiquitous trait that defines
//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`]}: The
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}: Generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [`std::default`]::[`Default`], types that have default values.
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}: Iterators of various
//!   kinds.
//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}, a
//!   type which expresses the presence or absence of a value. This type is so
//!   commonly used, its variants are also exported.
//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}: A type
//!   for functions that may succeed or fail. Like [`Option`], its variants are
//!   exported as well.
//! * [`std::string`]::{[`String`], [`ToString`]}: Heap-allocated strings.
//! * [`std::vec`]::[`Vec`]: A growable, heap-allocated vector.
//!
//! [`mem::drop`]: crate::mem::drop
//! [`std::borrow`]: crate::borrow
//! [`std::boxed`]: crate::boxed
//! [`std::clone`]: crate::clone
//! [`std::cmp`]: crate::cmp
//! [`std::convert`]: crate::convert
//! [`std::default`]: crate::default
//! [`std::iter`]: crate::iter
//! [`std::marker`]: crate::marker
//! [`std::mem`]: crate::mem
//! [`std::ops`]: crate::ops
//! [`std::option`]: crate::option
//! [`std::prelude::v1`]: v1
//! [`std::result`]: crate::result
//! [`std::slice`]: crate::slice
//! [`std::string`]: crate::string
//! [`std::vec`]: mod@crate::vec
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
//! [book-iter]: ../../book/ch13-02-iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<|endoftext|>